123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969 |
- /****************************************************************************
- * tools/mkdeps.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
- ****************************************************************************/
- #define _FILE_OFFSET_BITS 64
- #include <sys/stat.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include <ctype.h>
- #include <libgen.h>
- #include <errno.h>
- #include <dirent.h>
- #ifdef HOST_CYGWIN
- # include <sys/cygwin.h>
- #endif
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- #define MAX_BUFFER (8192)
- #define MAX_EXPAND (2048)
- #define MAX_SHQUOTE (2048)
- /* MAX_PATH might be defined in stdlib.h */
- #if !defined(MAX_PATH)
- # define MAX_PATH (512)
- #endif
- /* NAME_MAX is typically defined in limits.h */
- #if !defined(NAME_MAX)
- /* FILENAME_MAX might be defined in stdio.h */
- # if defined(FILENAME_MAX)
- # define NAME_MAX FILENAME_MAX
- # else
- /* MAXNAMELEN might be defined in dirent.h */
- # if defined(MAXNAMLEN)
- # define NAME_MAX MAXNAMLEN
- # else
- /* Lets not let a silly think like this stop us... just make something up */
- # define NAME_MAX 256
- # endif
- # endif
- #endif
- /****************************************************************************
- * Private Types
- ****************************************************************************/
- enum slashmode_e
- {
- MODE_FSLASH = 0,
- MODE_BSLASH = 1,
- MODE_DBLBACK = 2
- };
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- static char *g_cc = NULL;
- static char *g_cflags = NULL;
- static char *g_files = NULL;
- static char *g_altpath = NULL;
- static char *g_objpath = NULL;
- static char *g_suffix = ".o";
- static int g_debug = 0;
- static bool g_winnative = false;
- #ifdef HOST_CYGWIN
- static bool g_winpath = false;
- #endif
- static char g_command[MAX_BUFFER];
- static char g_path[MAX_PATH];
- #ifdef HOST_CYGWIN
- static char g_expand[MAX_EXPAND];
- static char g_dequoted[MAX_PATH];
- static char g_posixpath[MAX_PATH];
- #endif
- static char g_shquote[MAX_SHQUOTE];
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /* MinGW does not seem to provide strtok_r */
- #ifndef HAVE_STRTOK_R
- static char *my_strtok_r(char *str, const char *delim, char **saveptr)
- {
- char *pbegin;
- char *pend = NULL;
- /* Decide if we are starting a new string or continuing from
- * the point we left off.
- */
- if (str)
- {
- pbegin = str;
- }
- else if (saveptr && *saveptr)
- {
- pbegin = *saveptr;
- }
- else
- {
- return NULL;
- }
- /* Find the beginning of the next token */
- for (;
- *pbegin && strchr(delim, *pbegin) != NULL;
- pbegin++);
- /* If we are at the end of the string with nothing
- * but delimiters found, then return NULL.
- */
- if (!*pbegin)
- {
- return NULL;
- }
- /* Find the end of the token */
- for (pend = pbegin + 1;
- *pend && strchr(delim, *pend) == NULL;
- pend++);
- /* pend either points to the end of the string or to
- * the first delimiter after the string.
- */
- if (*pend)
- {
- /* Turn the delimiter into a null terminator */
- *pend++ = '\0';
- }
- /* Save the pointer where we left off and return the
- * beginning of the token.
- */
- if (saveptr)
- {
- *saveptr = pend;
- }
- return pbegin;
- }
- #undef strtok_r
- #define strtok_r my_strtok_r
- #endif
- static void append(char **base, const char *str)
- {
- char *oldbase;
- char *newbase;
- int alloclen;
- oldbase = *base;
- if (!oldbase)
- {
- newbase = strdup(str);
- if (!newbase)
- {
- fprintf(stderr, "ERROR: Failed to strdup %s\n", str);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- alloclen = strlen(oldbase) + strlen(str) +
- sizeof((char) ' ') + sizeof((char) '\0');
- newbase = (char *)malloc(alloclen);
- if (!newbase)
- {
- fprintf(stderr, "ERROR: Failed to allocate %d bytes\n", alloclen);
- exit(EXIT_FAILURE);
- }
- snprintf(newbase, alloclen, "%s %s", oldbase, str);
- free(oldbase);
- }
- *base = newbase;
- }
- static void show_usage(const char *progname, const char *msg, int exitcode)
- {
- if (msg)
- {
- fprintf(stderr, "\n");
- fprintf(stderr, "%s:\n", msg);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, "%s [OPTIONS] CC -- CFLAGS -- file [file [file...]]\n",
- progname);
- fprintf(stderr, "\n");
- fprintf(stderr, "Where:\n");
- fprintf(stderr, " CC\n");
- fprintf(stderr, " A variable number of arguments that define how to\n");
- fprintf(stderr, " execute the compiler\n");
- fprintf(stderr, " CFLAGS\n");
- fprintf(stderr, " The compiler compilation flags\n");
- fprintf(stderr, " file\n");
- fprintf(stderr, " One or more C files whose dependencies will be\n");
- fprintf(stderr, " checked. Each file is expected\n");
- fprintf(stderr, " to reside in the current directory unless\n");
- fprintf(stderr, " --dep-path is provided on the command line\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "And [OPTIONS] include:\n");
- fprintf(stderr, " --dep-debug\n");
- fprintf(stderr, " Enable script debug\n");
- fprintf(stderr, " --dep-path <path>\n");
- fprintf(stderr, " Do not look in the current directory for the\n");
- fprintf(stderr, " file. Instead, look in <path> to see\n");
- fprintf(stderr, " if the file resides there. --dep-path may be\n");
- fprintf(stderr, " used multiple times to specify\n");
- fprintf(stderr, " multiple alternative location\n");
- fprintf(stderr, " --obj-path <path>\n");
- fprintf(stderr, " The final objects will not reside in this path\n");
- fprintf(stderr, " but, rather, at the path provided by\n");
- fprintf(stderr, " <path>. if provided multiple time, only the last\n");
- fprintf(stderr, " --obj-path will be used.\n");
- fprintf(stderr, " --obj-suffix <suffix>\n");
- fprintf(stderr, " If an object path is provided, then the extension\n");
- fprintf(stderr, " will be assumed to be .o. This\n");
- fprintf(stderr, " default suffix can be overridden with this\n");
- fprintf(stderr, " command line option.\n");
- fprintf(stderr, " --winnative\n");
- fprintf(stderr, " By default, a POSIX-style environment is assumed\n");
- fprintf(stderr, " (e.g., Linux, Cygwin, etc.) This option is\n");
- fprintf(stderr, " inform the tool that is working in a pure Windows\n");
- fprintf(stderr, " native environment.\n");
- #ifdef HOST_CYGWIN
- fprintf(stderr, " --winpaths\n");
- fprintf(stderr, " This option is useful when using a Windows native\n");
- fprintf(stderr, " toolchain in a POSIX environment (such such as\n");
- fprintf(stderr, " Cygwin). In this case, will CC\n");
- fprintf(stderr, " generates dependency lists using Windows paths\n");
- fprintf(stderr, " (e.g., C:\\blablah\\blabla).\n");
- #endif
- fprintf(stderr, " --help\n");
- fprintf(stderr, " Shows this message and exits\n");
- exit(exitcode);
- }
- /****************************************************************************
- * Name: do_shquote
- *
- * Description:
- * Escape the given string for use with the shell.
- *
- * The idea was taken from:
- * https://netbsd.gw.com/cgi-bin/man-cgi?shquote++NetBSD-current
- * However, this implementation doesn't try to elide extraneous quotes.
- ****************************************************************************/
- static const char *do_shquote(const char *argument)
- {
- const char *src;
- char *dest;
- int len;
- src = argument;
- dest = g_shquote;
- len = 0;
- if (len < sizeof(g_shquote))
- {
- *dest++ = '\'';
- len++;
- }
- while (*src && len < sizeof(g_shquote))
- {
- if (*src == '\'')
- {
- /* Expand single quote to '\'' */
- if (len + 4 > sizeof(g_shquote))
- {
- break;
- }
- src++;
- memcpy(dest, "\'\\\'\'", 4);
- dest += 4;
- len += 4;
- }
- else
- {
- *dest++ = *src++;
- len++;
- }
- }
- if (*src || len + 2 > sizeof(g_shquote))
- {
- fprintf(stderr,
- "ERROR: Truncated during shquote string is too long"
- "[%zu/%zu]\n", strlen(argument), sizeof(g_shquote));
- exit(EXIT_FAILURE);
- }
- *dest++ = '\'';
- *dest = '\0';
- return g_shquote;
- }
- static void parse_args(int argc, char **argv)
- {
- char *args = NULL;
- int argidx;
- int group = 0;
- /* Always look in the current directory */
- g_altpath = strdup(".");
- /* Accumulate CFLAGS up to "--" */
- for (argidx = 1; argidx < argc; argidx++)
- {
- if (strcmp(argv[argidx], "--") == 0)
- {
- g_cc = g_cflags;
- g_cflags = args;
- args = NULL;
- group++;
- }
- else if (strcmp(argv[argidx], "--dep-debug") == 0)
- {
- g_debug++;
- }
- else if (strcmp(argv[argidx], "--dep-path") == 0)
- {
- argidx++;
- if (argidx >= argc)
- {
- show_usage(argv[0], "ERROR: Missing argument to --dep-path",
- EXIT_FAILURE);
- }
- if (args)
- {
- append(&args, argv[argidx]);
- }
- else
- {
- append(&g_altpath, argv[argidx]);
- }
- }
- else if (strcmp(argv[argidx], "--obj-path") == 0)
- {
- argidx++;
- if (argidx >= argc)
- {
- show_usage(argv[0], "ERROR: Missing argument to --obj-path",
- EXIT_FAILURE);
- }
- g_objpath = argv[argidx];
- }
- else if (strcmp(argv[argidx], "--obj-suffix") == 0)
- {
- argidx++;
- if (argidx >= argc)
- {
- show_usage(argv[0], "ERROR: Missing argument to --obj-suffix",
- EXIT_FAILURE);
- }
- g_suffix = argv[argidx];
- }
- else if (strcmp(argv[argidx], "--winnative") == 0)
- {
- g_winnative = true;
- }
- #ifdef HOST_CYGWIN
- else if (strcmp(argv[argidx], "--winpath") == 0)
- {
- g_winpath = true;
- }
- #endif
- else if (strcmp(argv[argidx], "--help") == 0)
- {
- show_usage(argv[0], NULL, EXIT_SUCCESS);
- }
- else
- {
- const char *arg = argv[argidx];
- /* This condition means "perform shquote for
- * g_cflags, but not g_cc or g_files".
- *
- * It isn't safe to escape g_cc because, for some reasons,
- * Makefile passes it as a single argument like:
- *
- * $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS)
- *
- * It isn't safe to escape g_files because
- * do_dependency() uses them as bare filenames as well.
- * (In addition to passing them to system().)
- */
- if (group == 1)
- {
- arg = do_shquote(arg);
- }
- append(&args, arg);
- }
- }
- /* The final thing accumulated is the list of files */
- g_files = args;
- if (g_debug)
- {
- fprintf(stderr, "SELECTIONS\n");
- fprintf(stderr, " CC : [%s]\n",
- g_cc ? g_cc : "(None)");
- fprintf(stderr, " CFLAGS : [%s]\n",
- g_cflags ? g_cflags : "(None)");
- fprintf(stderr, " FILES : [%s]\n",
- g_files ? g_files : "(None)");
- fprintf(stderr, " PATHS : [%s]\n",
- g_altpath ? g_altpath : "(None)");
- if (g_objpath)
- {
- fprintf(stderr, " OBJDIR : [%s]\n", g_objpath);
- fprintf(stderr, " SUFFIX : [%s]\n", g_suffix);
- }
- else
- {
- fprintf(stderr, " OBJDIR : (None)\n");
- }
- #ifdef HOST_CYGWIN
- fprintf(stderr, " Windows Paths : [%s]\n",
- g_winpath ? "TRUE" : "FALSE");
- #endif
- fprintf(stderr, " Windows Native : [%s]\n",
- g_winnative ? "TRUE" : "FALSE");
- }
- /* Check for required parameters */
- if (!g_cc)
- {
- show_usage(argv[0], "ERROR: No compiler specified", EXIT_FAILURE);
- }
- if (!g_files)
- {
- /* Don't report an error --
- * this happens normally in some configurations
- */
- printf("# No files specified for dependency generation\n");
- exit(EXIT_SUCCESS);
- }
- #ifdef HOST_CYGWIN
- if (g_winnative && g_winpath)
- {
- show_usage(argv[0],
- "ERROR: Both --winnative and --winpath makes no sense",
- EXIT_FAILURE);
- }
- #endif
- }
- static const char *do_expand(const char *argument)
- {
- #ifdef HOST_CYGWIN
- if (g_winpath)
- {
- const char *src;
- char *dest;
- int len;
- src = argument;
- dest = g_expand;
- len = 0;
- while (*src && len < MAX_EXPAND)
- {
- if (*src == '\\')
- {
- /* Copy backslash */
- *dest++ = *src++;
- if (++len >= MAX_EXPAND)
- {
- break;
- }
- /* Already expanded? */
- if (*src == '\\')
- {
- /* Yes... just copy all consecutive backslashes */
- do
- {
- *dest++ = *src++;
- if (++len >= MAX_EXPAND)
- {
- break;
- }
- }
- while (*src == '\\');
- }
- else
- {
- /* No.. expeand */
- *dest++ = '\\';
- if (++len >= MAX_EXPAND)
- {
- break;
- }
- }
- }
- else
- {
- *dest++ = *src++;
- len++;
- }
- }
- if (*src)
- {
- fprintf(stderr,
- "ERROR: Truncated during expansion string is too long"
- "[%zu/%u]\n", strlen(argument), MAX_EXPAND);
- exit(EXIT_FAILURE);
- }
- *dest = '\0';
- return g_expand;
- }
- else
- #endif
- {
- return argument;
- }
- }
- #ifdef HOST_CYGWIN
- static bool dequote_path(const char *winpath)
- {
- char *dest = g_dequoted;
- const char *src = winpath;
- int len = 0;
- bool quoted = false;
- while (*src && len < MAX_PATH)
- {
- if (*src != '\\' || (src[1] != ' ' && src[1] != '(' && src[1] != ')'))
- {
- *dest++ = *src;
- len++;
- }
- else
- {
- quoted = true;
- }
- src++;
- }
- if (*src || len >= MAX_PATH)
- {
- fprintf(stderr, "# ERROR: Path truncated\n");
- exit(EXIT_FAILURE);
- }
- *dest = '\0';
- return quoted;
- }
- #endif
- static const char *convert_path(const char *path)
- {
- #ifdef HOST_CYGWIN
- if (g_winpath)
- {
- const char *retptr;
- ssize_t size;
- ssize_t ret;
- bool quoted;
- quoted = dequote_path(path);
- if (quoted)
- {
- retptr = g_posixpath;
- }
- else
- {
- retptr = &g_posixpath[1];
- }
- size = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_RELATIVE, g_dequoted,
- NULL, 0);
- if (size > (MAX_PATH - 3))
- {
- fprintf(stderr, "# ERROR: POSIX path too long: %zd\n", size);
- exit(EXIT_FAILURE);
- }
- ret = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_RELATIVE, g_dequoted,
- &g_posixpath[1], MAX_PATH - 3);
- if (ret < 0)
- {
- fprintf(stderr, "# ERROR: cygwin_conv_path '%s' failed: %s\n",
- g_dequoted, strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (quoted)
- {
- size++;
- g_posixpath[0] = '"';
- g_posixpath[size] = '"';
- }
- g_posixpath[size + 1] = '\0';
- return retptr;
- }
- else
- #endif
- {
- return path;
- }
- }
- static void do_dependency(const char *file)
- {
- static const char moption[] = " -M ";
- struct stat buf;
- char *alloc;
- char *altpath;
- char *path;
- char *lasts;
- char separator;
- int cmdlen;
- int pathlen;
- int filelen;
- int totallen;
- int ret;
- /* Initialize the separator */
- #ifdef HOST_CYGWIN
- separator = (g_winnative || g_winpath) ? '\\' : '/';
- #else
- separator = g_winnative ? '\\' : '/';
- #endif
- /* Copy the compiler into the command buffer */
- cmdlen = strlen(g_cc);
- if (cmdlen >= MAX_BUFFER)
- {
- fprintf(stderr, "ERROR: Compiler string is too long [%d/%d]: %s\n",
- cmdlen, MAX_BUFFER, g_cc);
- exit(EXIT_FAILURE);
- }
- strcpy(g_command, g_cc);
- /* Copy " -MT " */
- if (g_objpath)
- {
- char tmp[NAME_MAX + 6];
- char *dupname;
- char *objname;
- char *dotptr;
- const char *expanded;
- dupname = strdup(file);
- if (!dupname)
- {
- fprintf(stderr, "ERROR: Failed to dup: %s\n", file);
- exit(EXIT_FAILURE);
- }
- objname = basename(dupname);
- dotptr = strrchr(objname, '.');
- if (dotptr)
- {
- *dotptr = '\0';
- }
- snprintf(tmp, NAME_MAX + 6, " -MT %s%c%s%s ",
- g_objpath, separator, objname, g_suffix);
- expanded = do_expand(tmp);
- cmdlen += strlen(expanded);
- if (cmdlen >= MAX_BUFFER)
- {
- fprintf(stderr, "ERROR: Option string is too long [%d/%d]: %s\n",
- cmdlen, MAX_BUFFER, moption);
- exit(EXIT_FAILURE);
- }
- strcat(g_command, expanded);
- free(dupname);
- }
- /* Copy " -M " */
- cmdlen += strlen(moption);
- if (cmdlen >= MAX_BUFFER)
- {
- fprintf(stderr, "ERROR: Option string is too long [%d/%d]: %s\n",
- cmdlen, MAX_BUFFER, moption);
- exit(EXIT_FAILURE);
- }
- strcat(g_command, moption);
- /* Copy the CFLAGS into the command buffer */
- if (g_cflags)
- {
- const char *expanded;
- expanded = do_expand(g_cflags);
- cmdlen += strlen(expanded);
- if (cmdlen >= MAX_BUFFER)
- {
- fprintf(stderr, "ERROR: CFLAG string is too long [%d/%d]: %s\n",
- cmdlen, MAX_BUFFER, g_cflags);
- exit(EXIT_FAILURE);
- }
- strcat(g_command, expanded);
- }
- /* Add a space */
- g_command[cmdlen] = ' ';
- cmdlen++;
- g_command[cmdlen] = '\0';
- /* Make a copy of g_altpath. We need to do this because at least the
- * version of strtok_r above does modify it.
- */
- alloc = strdup(g_altpath);
- if (!alloc)
- {
- fprintf(stderr, "ERROR: Failed to strdup paths\n");
- exit(EXIT_FAILURE);
- }
- altpath = alloc;
- /* Try each path. This loop will continue until each path has been tried
- * (failure) or until stat() finds the file
- */
- while ((path = strtok_r(altpath, " ", &lasts)) != NULL)
- {
- const char *expanded;
- const char *converted;
- /* Create a full path to the file */
- pathlen = strlen(path);
- if (pathlen >= MAX_PATH)
- {
- fprintf(stderr, "ERROR: Path is too long [%d/%d]: %s\n",
- pathlen, MAX_PATH, path);
- exit(EXIT_FAILURE);
- }
- strcpy(g_path, path);
- if (g_path[pathlen] != '\0')
- {
- fprintf(stderr, "ERROR: Missing NUL terminator\n");
- exit(EXIT_FAILURE);
- }
- if (g_path[pathlen - 1] != separator)
- {
- g_path[pathlen] = separator;
- g_path[pathlen + 1] = '\0';
- pathlen++;
- }
- filelen = strlen(file);
- pathlen += filelen;
- if (pathlen >= MAX_PATH)
- {
- fprintf(stderr, "ERROR: Path+file is too long [%d/%d]\n",
- pathlen, MAX_PATH);
- exit(EXIT_FAILURE);
- }
- strcat(g_path, file);
- /* Check that a file actually exists at this path */
- if (g_debug)
- {
- fprintf(stderr, "Trying path=%s file=%s fullpath=%s\n",
- path, file, g_path);
- }
- converted = convert_path(g_path);
- ret = stat(converted, &buf);
- if (ret < 0)
- {
- altpath = NULL;
- continue;
- }
- if (!S_ISREG(buf.st_mode))
- {
- fprintf(stderr,
- "ERROR: File %s exists but is not a regular file\n",
- g_path);
- exit(EXIT_FAILURE);
- }
- /* Append the expanded path to the command */
- expanded = do_expand(g_path);
- pathlen = strlen(expanded);
- totallen = cmdlen + pathlen;
- if (totallen >= MAX_BUFFER)
- {
- fprintf(stderr, "ERROR: Path string is too long [%d/%d]: %s\n",
- totallen, MAX_BUFFER, g_path);
- exit(EXIT_FAILURE);
- }
- strcat(g_command, expanded);
- /* Okay.. we have everything. Create the dependency. One a failure
- * to start the compiler, system() will return -1; Otherwise, the
- * returned value from the compiler is in WEXITSTATUS(ret).
- */
- if (g_debug)
- {
- fprintf(stderr, "Executing: %s\n", g_command);
- }
- ret = system(g_command);
- #ifdef WEXITSTATUS
- if (ret < 0 || WEXITSTATUS(ret) != 0)
- {
- if (ret < 0)
- {
- fprintf(stderr, "ERROR: system failed: %s\n", strerror(errno));
- }
- else
- {
- fprintf(stderr,
- "ERROR: %s failed: %d\n", g_cc, WEXITSTATUS(ret));
- }
- fprintf(stderr, " command: %s\n", g_command);
- exit(EXIT_FAILURE);
- }
- #else
- if (ret < 0)
- {
- fprintf(stderr, "ERROR: system failed: %s\n", strerror(errno));
- fprintf(stderr, " command: %s\n", g_command);
- exit(EXIT_FAILURE);
- }
- #endif
- /* We don't really know that the command succeeded...
- * Let's assume that it did
- */
- free(alloc);
- return;
- }
- printf("# ERROR: File \"%s\" not found at any location\n", file);
- exit(EXIT_FAILURE);
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- int main(int argc, char **argv, char **envp)
- {
- char *lasts;
- char *files;
- char *file;
- /* Parse command line parameters */
- parse_args(argc, argv);
- /* Then generate dependencies for each path on the command line. NOTE
- * strtok_r will clobber the files list. But that is okay because we are
- * only going to traverse it once.
- */
- files = g_files;
- while ((file = strtok_r(files, " ", &lasts)) != NULL)
- {
- /* Check if we need to do path conversions for a Windows-natvive tool
- * being using in a POSIX/Cygwin environment.
- */
- do_dependency(file);
- files = NULL;
- }
- return EXIT_SUCCESS;
- }
|