tools/incdir.c: Add faster, C version of incdir.sh

This commit is contained in:
Gregory Nutt
2020-05-29 13:19:32 -06:00
committed by Alan Carvalho de Assis
parent 1b8c072802
commit b111e135e0
3 changed files with 500 additions and 5 deletions
+12 -3
View File
@@ -63,14 +63,14 @@ all: b16$(HOSTEXEEXT) bdf-converter$(HOSTEXEEXT) cmpconfig$(HOSTEXEEXT) \
mksymtab$(HOSTEXEEXT) mksyscall$(HOSTEXEEXT) mkversion$(HOSTEXEEXT) \ mksymtab$(HOSTEXEEXT) mksyscall$(HOSTEXEEXT) mkversion$(HOSTEXEEXT) \
cnvwindeps$(HOSTEXEEXT) nxstyle$(HOSTEXEEXT) initialconfig$(HOSTEXEEXT) \ cnvwindeps$(HOSTEXEEXT) nxstyle$(HOSTEXEEXT) initialconfig$(HOSTEXEEXT) \
gencromfs$(HOSTEXEEXT) convert-comments$(HOSTEXEEXT) lowhex$(HOSTEXEEXT) \ gencromfs$(HOSTEXEEXT) convert-comments$(HOSTEXEEXT) lowhex$(HOSTEXEEXT) \
detab$(HOSTEXEEXT) rmcr$(HOSTEXEEXT) detab$(HOSTEXEEXT) rmcr$(HOSTEXEEXT) incdir$(HOSTEXEEXT)
default: mkconfig$(HOSTEXEEXT) mksyscall$(HOSTEXEEXT) mkdeps$(HOSTEXEEXT) \ default: mkconfig$(HOSTEXEEXT) mksyscall$(HOSTEXEEXT) mkdeps$(HOSTEXEEXT) \
cnvwindeps$(HOSTEXEEXT) cnvwindeps$(HOSTEXEEXT) incdir$(HOSTEXEEXT)
ifdef HOSTEXEEXT ifdef HOSTEXEEXT
.PHONY: b16 bdf-converter cmpconfig clean configure kconfig2html mkconfig \ .PHONY: b16 bdf-converter cmpconfig clean configure kconfig2html mkconfig \
mkdeps mksymtab mksyscall mkversion cnvwindeps nxstyle initialconfig \ mkdeps mksymtab mksyscall mkversion cnvwindeps nxstyle initialconfig \
gencromfs convert-comments lowhex detab rmcr gencromfs convert-comments lowhex detab rmcr incdir
else else
.PHONY: clean .PHONY: clean
endif endif
@@ -221,6 +221,15 @@ ifdef HOSTEXEEXT
rmcr: rmcr$(HOSTEXEEXT) rmcr: rmcr$(HOSTEXEEXT)
endif endif
# incdir - Generate compiler-specific include paths
incdir$(HOSTEXEEXT): incdir.c
$(Q) $(HOSTCC) $(HOSTCFLAGS) -o incdir$(HOSTEXEEXT) incdir.c
ifdef HOSTEXEEXT
incdir: incdir$(HOSTEXEEXT)
endif
# cnvwindeps - Convert dependences generated by a Windows native toolchain # cnvwindeps - Convert dependences generated by a Windows native toolchain
# for use in a Cygwin/POSIX build environment # for use in a Cygwin/POSIX build environment
+4 -2
View File
@@ -605,8 +605,8 @@ ide_exporter.py
Obsoleted/stm32f429i_disco/ltcd/template and at Obsoleted/stm32f429i_disco/ltcd/template and at
Obsoleted/stm3220g-eval/template. Obsoleted/stm3220g-eval/template.
incdir.sh and incdir.bat incdir.sh, incdir.bat, and incdir.c
------------------------ -----------------------------------
Different compilers have different conventions for specifying lists Different compilers have different conventions for specifying lists
of include file paths on the compiler command line. This incdir.sh of include file paths on the compiler command line. This incdir.sh
@@ -617,6 +617,8 @@ incdir.sh and incdir.bat
build. However, there is currently only one compiler supported in build. However, there is currently only one compiler supported in
that context: MinGW-GCC. that context: MinGW-GCC.
incdir.c is a higher performance version of incdir.sh, converted to C.
indent.sh indent.sh
--------- ---------
+484
View File
@@ -0,0 +1,484 @@
/****************************************************************************
* tools/incdir.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/utsname.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef HOST_CYGWIN
# include <sys/cygwin.h>
#endif
/****************************************************************************
* Private Types
****************************************************************************/
enum pathtype_e
{
USER_PATH = 0,
SYSTEM_PATH
};
enum os_e
{
OS_UNKNOWN = 0,
OS_LINUX,
OS_WINDOWS,
OS_CYGWIN,
OS_MSYS,
OS_WSL,
OS_MACOS,
OS_BSD
};
enum compiler_e
{
COMPILER_UNKNOWN = 0,
COMPILER_GCC,
COMPILER_CLANG,
COMPILER_MINGW,
COMPILER_SDCC,
COMPILER_ZDSII
};
/****************************************************************************
* Private Functions
****************************************************************************/
static void show_advice(const char *progname, int exitcode)
{
fprintf(stderr, "\nUSAGE: %s [-h] [-w] [-s] <compiler-path> "
"<dir1> [<dir2> [<dir3> ...]]\n",
progname);
fprintf(stderr, "Try '%s -h' for more information\n", progname);
exit(exitcode);
}
static void show_help(const char *progname, int exitcode)
{
fprintf(stderr, "%s is a tool for flexible generation of include path "
"arguments for a\n",
progname);
fprintf(stderr, "variety of different compilers in a variety of "
"compilation environments\n");
fprintf(stderr, "\nUSAGE: %s [-w] [-s] <compiler-path> "
"<dir1> [<dir2> [<dir3> ...]]\n",
progname);
fprintf(stderr, " %s -h\n\n", progname);
fprintf(stderr, "Where:\n");
fprintf(stderr, " <compiler-path>\n");
fprintf(stderr, " The full path to your compiler\n");
fprintf(stderr, " <dir1> [<dir2> [<dir3> ...]]\n");
fprintf(stderr, " A list of include directories\n");
fprintf(stderr, " -w\n");
fprintf(stderr, " The compiler is a Windows native tool and requires "
"Windows\n");
fprintf(stderr, " style pathnames like C:\\Program Files\n");
fprintf(stderr, " -s\n");
fprintf(stderr, " Generate standard, system header file paths instead "
"of normal user\n");
fprintf(stderr, " header file paths.\n");
fprintf(stderr, " -h\n");
fprintf(stderr, " Shows this help text and exits.\n");
exit(exitcode);
}
static enum os_e get_os(const char *ccpath)
{
struct utsname buf;
int ret;
/* Check for MinGW which implies a Windows native environment */
if (strstr(ccpath, "mingw") != NULL)
{
return OS_WINDOWS;
}
/* Get the context names */
ret = uname(&buf);
if (ret < 0)
{
int errcode = errno;
fprintf(stderr, "ERROR: uname failed: %s\n", strerror(errcode));
exit(EXIT_FAILURE);
}
if (strcmp(buf.sysname, "Linux") == 0)
{
return OS_LINUX; /* Or OS_WSL */
}
else if (strncmp(buf.sysname, "CYGWIN", 6) == 0)
{
return OS_CYGWIN;
}
else if (strncmp(buf.sysname, "MINGW", 5) == 0)
{
return OS_CYGWIN;
}
else if (strncmp(buf.sysname, "MSYS", 4) == 0)
{
return OS_CYGWIN;
}
else if (strcmp(buf.sysname, "Darwin") == 0)
{
return OS_MACOS;
}
else if (strcmp(buf.sysname, "FreeBSD") == 0 ||
strcmp(buf.sysname, "OpenBSD") == 0 ||
strcmp(buf.sysname, "GNU/kFreeBSD") == 0)
{
return OS_BSD;
}
else
{
return OS_UNKNOWN;
}
}
static enum compiler_e get_compiler(const char *ccpath, enum os_e os)
{
/* Let's assume that all GCC compiler paths contain the string gcc or
* g++ and no non-GCC compiler paths include these substrings
*/
if (strstr(ccpath, "gcc") != NULL ||
strstr(ccpath, "g++") != NULL)
{
return COMPILER_GCC;
}
else if (strstr(ccpath, "clang") != NULL)
{
return COMPILER_CLANG;
}
else if (strstr(ccpath, "sdcc") != NULL)
{
return COMPILER_SDCC;
}
else if (strstr(ccpath, "mingw") != NULL)
{
return COMPILER_MINGW;
}
else if (strstr(ccpath, "ez8cc") != NULL ||
strstr(ccpath, "zneocc") != NULL ||
strstr(ccpath, "ez80cc") != NULL)
{
return COMPILER_ZDSII;
}
else
{
return COMPILER_UNKNOWN;
}
}
static int my_asprintf(char **strp, const char *fmt, ...)
{
va_list ap;
ssize_t bufsize;
char *buffer;
/* Get the size of the buffer */
va_start(ap, fmt);
bufsize = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (bufsize <= 0)
{
fprintf(stderr, "ERROR: vsnprintf() failed.\n");
exit (EXIT_FAILURE);
}
buffer = malloc(bufsize + 1);
if (buffer == NULL)
{
fprintf(stderr, "ERROR: Failed allocated vsnprintf() buffer.\n");
exit (EXIT_FAILURE);
}
va_start(ap, fmt);
vsnprintf(buffer, bufsize + 1, fmt, ap);
va_end(ap);
*strp = buffer;
return bufsize;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, char **argv, char **envp)
{
#ifdef HOST_CYGWIN
char *convpath = NULL;
#endif
enum pathtype_e pathtype = USER_PATH;
enum os_e os;
enum compiler_e compiler;
const char *progname = argv[0];
const char *ccpath;
const char *cmdarg;
char * const *dirlist;
size_t respsize = 0;
char *response = NULL;
bool wintool = false;
int ndirs;
int ret;
int ch;
int i;
/* Handle command line options */
while ((ch = getopt(argc, argv, "wsh")) >= 0)
{
switch (ch)
{
case 'w':
wintool = true;
break;
case 's':
pathtype = SYSTEM_PATH;
break;
case 'h':
show_help(progname, EXIT_SUCCESS);
}
}
if (optind >= argc)
{
fprintf(stderr, "ERROR: Missing <compiler-path>\n");
show_advice(progname, EXIT_FAILURE);
}
ccpath = argv[optind];
optind++;
if (optind >= argc)
{
fprintf(stderr, "ERROR: At least one directory must be supplied\n");
show_advice(progname, EXIT_FAILURE);
}
dirlist = &argv[optind];
ndirs = argc - optind;
/* Most compilers support CFLAG options like '-I<dir>' to add include
* file header paths. Some (like the Zilog tools), do not. This script
* makes the selection of header file paths compiler independent.
*
* Below are all known compiler names (as found in the board/ Make.defs
* files). If a new compiler is used that has some unusual syntax, then
* additional logic needs to be added to this file.
*
* NAME Syntax
* $(CROSSDEV)gcc -I<dir1> -I<dir2> -I<dir3> ...
* sdcc -I<dir2> -I<dir2> -I<dir3> ...
* $(ZDSBINDIR)/ez8cc.exe -usrinc:'<dir1>:<dir2>:<dir3>:...`
* $(ZDSBINDIR)/zneocc.exe -usrinc:'<dir1>:<dir2>:<dir3>:...`
* $(ZDSBINDIR)/ez80cc.exe -usrinc:'<dir1>:<dir2>:<dir3>:...`
*
* Furthermore, just to make matters more difficult, with Windows based
* toolchains, we have to use the full windows-style paths to the header
* files.
*/
os = get_os(ccpath);
if (os == OS_UNKNOWN)
{
fprintf(stderr, "ERROR: Operating system not recognized.\n");
show_advice(progname, EXIT_FAILURE);
}
compiler = get_compiler(ccpath, os);
if (compiler == COMPILER_UNKNOWN)
{
fprintf(stderr, "ERROR: Compiler not recognized.\n");
show_advice(progname, EXIT_FAILURE);
}
/* Select system or user header file path command line option */
if (compiler == COMPILER_ZDSII)
{
cmdarg = (pathtype == SYSTEM_PATH) ? "-stdinc:" : "-usrinc:";
wintool = true;
}
else
{
cmdarg = (pathtype == SYSTEM_PATH) ? "-isystem" : "-I";
}
/* Now process each directory in the directory list */
for (i = 0; i < ndirs; i++)
{
const char *dirname;
const char *incpath;
char *saveresp;
char *segment = NULL;
size_t segsize;
dirname = dirlist[i];
#ifdef HOST_CYGWIN
/* Check if the path needs to be extended for Windows-based tools under
* Cygwin:
*
* wintool == true: The platform is Cygwin and we are using a windows
* native tool
*/
if (os == OS_CYGWIN && wintool)
{
ssize_t bufsize;
bufsize = cygwin_conv_path(CCP_POSIX_TO_WIN_A, dirname, NULL, 0);
convpath = (char *)malloc(bufsize);
if (convpath == NULL)
{
fprintf(stderr, "ERROR: Faile to allocate buffer.\n");
exit(EXIT_FAILURE);
}
(void)cygwin_conv_path(CCP_POSIX_TO_WIN_A, dirname, convpath,
bufsize);
incpath = convpath;
}
else
#endif
{
incpath = dirname;
}
/* Handle the output using the selected format */
if (compiler == COMPILER_ZDSII)
{
/* FORM: -stdinc: 'dir1;dir2;...;dirN'
* -usrinc: 'dir1;dir2;...;dirN'
*/
/* Treat the first directory differently */
if (response == NULL)
{
if (i == ndirs - 1)
{
ret = my_asprintf(&segment, "%s '%s'", cmdarg, incpath);
}
else
{
ret = my_asprintf(&segment, "%s '%s", cmdarg, incpath);
}
}
else
{
if (i == ndirs - 1)
{
ret = my_asprintf(&segment, ";%s'", incpath);
}
else
{
ret = my_asprintf(&segment, ";%s", incpath);
}
}
}
else
{
/* FORM: -isystem: "dir1" -isystem "dir2" ... -isystem "dirN"
* -I: "dir1" -I "dir2" ... -I "dirN"
*/
/* Treat the first directory differently */
if (response == NULL)
{
ret = my_asprintf(&segment, "%s \"%s\"", cmdarg, incpath);
}
else
{
ret = my_asprintf(&segment, " %s \"%s\"", cmdarg, incpath);
}
}
if (ret < 0)
{
fprintf(stderr, "ERROR: my_asprintf failed.\n");
exit(EXIT_FAILURE);
}
/* Append the new response segment */
saveresp = response;
segsize = ret;
respsize += (response == NULL) ? segsize + 1 : segsize;
response = (char *)malloc(respsize);
if (response == NULL)
{
fprintf(stderr, "ERROR: Failed to allocate response.\n");
exit(EXIT_FAILURE);
}
if (saveresp == NULL)
{
strncpy(response, segment, respsize);
}
else
{
snprintf(response, respsize, "%s%s", saveresp, segment);
}
/* Clean up for the next pass */
if (segment != NULL)
{
free(segment);
segment = NULL;
}
#ifdef HOST_CYGWIN
if (convpath != NULL)
{
free(convpath);
convpath = NULL;
}
#endif
}
fputs(response, stdout);
return EXIT_SUCCESS;
}