You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/05/29 20:17:47 UTC

[incubator-nuttx] branch master updated: tools/incdir.c: Add faster, C version of incdir.sh

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new b111e13  tools/incdir.c:  Add faster, C version of incdir.sh
b111e13 is described below

commit b111e135e049e561122b3ec41cd19c4ad8417c44
Author: Gregory Nutt <gn...@nuttx.org>
AuthorDate: Fri May 29 13:19:32 2020 -0600

    tools/incdir.c:  Add faster, C version of incdir.sh
---
 tools/Makefile.host |  15 +-
 tools/README.txt    |   6 +-
 tools/incdir.c      | 484 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+), 5 deletions(-)

diff --git a/tools/Makefile.host b/tools/Makefile.host
index 0b12bec..2531c20 100644
--- a/tools/Makefile.host
+++ b/tools/Makefile.host
@@ -63,14 +63,14 @@ all: b16$(HOSTEXEEXT) bdf-converter$(HOSTEXEEXT) cmpconfig$(HOSTEXEEXT) \
     mksymtab$(HOSTEXEEXT)  mksyscall$(HOSTEXEEXT) mkversion$(HOSTEXEEXT) \
     cnvwindeps$(HOSTEXEEXT) nxstyle$(HOSTEXEEXT) initialconfig$(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) \
-    cnvwindeps$(HOSTEXEEXT)
+    cnvwindeps$(HOSTEXEEXT) incdir$(HOSTEXEEXT)
 
 ifdef HOSTEXEEXT
 .PHONY: b16 bdf-converter cmpconfig clean configure kconfig2html mkconfig \
     mkdeps mksymtab mksyscall mkversion cnvwindeps nxstyle initialconfig \
-    gencromfs convert-comments lowhex detab rmcr
+    gencromfs convert-comments lowhex detab rmcr incdir
 else
 .PHONY: clean
 endif
@@ -221,6 +221,15 @@ ifdef HOSTEXEEXT
 rmcr: rmcr$(HOSTEXEEXT)
 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
 # for use in a Cygwin/POSIX build environment
 
diff --git a/tools/README.txt b/tools/README.txt
index e824a4e..3a70e56 100644
--- a/tools/README.txt
+++ b/tools/README.txt
@@ -605,8 +605,8 @@ ide_exporter.py
     Obsoleted/stm32f429i_disco/ltcd/template and at
     Obsoleted/stm3220g-eval/template.
 
-incdir.sh and incdir.bat
-------------------------
+incdir.sh, incdir.bat, and incdir.c
+-----------------------------------
 
   Different compilers have different conventions for specifying lists
   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
   that context:  MinGW-GCC.
 
+  incdir.c is a higher performance version of incdir.sh, converted to C.
+
 indent.sh
 ---------
 
diff --git a/tools/incdir.c b/tools/incdir.c
new file mode 100644
index 0000000..0eaaf43
--- /dev/null
+++ b/tools/incdir.c
@@ -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;
+}