2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $ */
25 /***************************************************************************
29 * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will *
30 * be passed to the template file. *
32 ***************************************************************************/
36 Copyright (c) 1985, 1986, 1987, 1998 The Open Group
40 The above copyright notice and this permission notice shall be included in
41 all copies or substantial portions of the Software.
43 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
47 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
48 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50 Except as contained in this notice, the name of The Open Group shall not be
51 used in advertising or otherwise to promote the sale, use or other dealings
52 in this Software without prior written authorization from The Open Group.
57 * While a guest engineer at Project Athena, MIT
59 * imake: the include-make program.
61 * Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
63 * Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
64 * and runs cpp on them producing a Makefile. It then optionally runs make
67 * -D define. Same as cpp -D argument.
68 * -I Include directory. Same as cpp -I argument.
69 * -T template. Designate a template other
71 * -f specify the Imakefile file
72 * -C specify the name to use instead of Imakefile.c
73 * -s[F] show. Show the produced makefile on the standard
74 * output. Make is not run is this case. If a file
75 * argument is provided, the output is placed there.
76 * -e[F] execute instead of show; optionally name Makefile F
77 * -v verbose. Show the make command line executed.
79 * Environment variables:
81 * IMAKEINCLUDE Include directory to use in addition to "."
82 * IMAKECPP Cpp to use instead of /lib/cpp
83 * IMAKEMAKE make program to use other than what is
84 * found by searching the $PATH variable.
86 * imake reads the entire cpp output into memory and then scans it
87 * for occurences of "@@". If it encounters them, it replaces it with
88 * a newline. It also trims any trailing white space on output lines
89 * (because make gets upset at them). This helps when cpp expands
90 * multi-line macros but you want them to appear on multiple lines.
91 * It also changes occurences of "XCOMM" to "#", to avoid problems
92 * with treating commands as invalid preprocessor commands.
94 * The macros MAKEFILE and MAKE are provided as macros
95 * to make. MAKEFILE is set to imake's makefile (not the constructed,
96 * preprocessed one) and MAKE is set to argv[0], i.e. the name of
99 * Theory of operation:
100 * 1. Determine the name of the imakefile from the command line (-f)
101 * or from the content of the current directory (Imakefile or imakefile).
102 * Call this <imakefile>. This gets added to the arguments for
103 * make as MAKEFILE=<imakefile>.
104 * 2. Determine the name of the template from the command line (-T)
105 * or the default, Imake.tmpl. Call this <template>
106 * 3. Determine the name of the imakeCfile from the command line (-C)
107 * or the default, Imakefile.c. Call this <imakeCfile>
108 * 4. Store lines of input into <imakeCfile>:
109 * - A c-style comment header (see ImakefileCHeader below), used
110 * to recognize temporary files generated by imake.
111 * - If DEFAULT_OS_NAME is defined, format the utsname struct and
112 * call the result <defaultOsName>. Add:
113 * #define DefaultOSName <defaultOsName>
114 * - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct
115 * and call the result <defaultOsMajorVersion>. Add:
116 * #define DefaultOSMajorVersion <defaultOsMajorVersion>
117 * - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct
118 * and call the result <defaultOsMinorVersion>. Add:
119 * #define DefaultOSMinorVersion <defaultOsMinorVersion>
120 * - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct
121 * and call the result <defaultOsTeenyVersion>. Add:
122 * #define DefaultOSTeenyVersion <defaultOsTeenyVersion>
123 * - If the file "localdefines" is readable in the current
124 * directory, print a warning message to stderr and add:
125 * #define IMAKE_LOCAL_DEFINES "localdefines"
126 * #include IMAKE_LOCAL_DEFINES
127 * - If the file "admindefines" is readable in the current
128 * directory, print a warning message to stderr and add:
129 * #define IMAKE_ADMIN_DEFINES "admindefines"
130 * #include IMAKE_ADMIN_DEFINES
131 * - The following lines:
132 * #define INCLUDE_IMAKEFILE < <imakefile> >
133 * #define IMAKE_TEMPLATE " <template> "
134 * #include IMAKE_TEMPLATE
135 * - If the file "adminmacros" is readable in the current
136 * directory, print a warning message to stderr and add:
137 * #define IMAKE_ADMIN_MACROS "adminmacros"
138 * #include IMAKE_ADMIN_MACROS
139 * - If the file "localmacros" is readable in the current
140 * directory, print a warning message to stderr and add:
141 * #define IMAKE_LOCAL_MACROS "localmacros"
142 * #include IMAKE_LOCAL_MACROS
143 * 5. Start up cpp and provide it with this file.
144 * Note that the define for INCLUDE_IMAKEFILE is intended for
145 * use in the template file. This implies that the imake is
146 * useless unless the template file contains at least the line
147 * #include INCLUDE_IMAKEFILE
148 * 6. Gather the output from cpp, and clean it up, expanding @@ to
149 * newlines, stripping trailing white space, cpp control lines,
150 * and extra blank lines, and changing XCOMM to #. This cleaned
151 * output is placed in a new file, default "Makefile", but can
152 * be specified with -s or -e options.
153 * 7. Optionally start up make on the resulting file.
155 * The design of the template makefile should therefore be:
156 * <set global macros like CFLAGS, etc.>
157 * <include machine dependent additions>
158 * #include INCLUDE_IMAKEFILE
159 * <add any global targets like 'clean' and long dependencies>
165 # include "Xw32defs.h"
168 # ifndef _POSIX_SOURCE
169 # define _POSIX_SOURCE
172 #include <sys/types.h>
176 # include <sys/file.h>
181 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
184 # define _POSIX_SOURCE
186 # undef _POSIX_SOURCE
188 #include <sys/stat.h>
190 # ifdef _POSIX_SOURCE
191 # include <sys/wait.h>
193 # define _POSIX_SOURCE
194 # include <sys/wait.h>
195 # undef _POSIX_SOURCE
197 # define waitCode(w) WEXITSTATUS(w)
198 # define waitSig(w) WTERMSIG(w)
199 typedef int waitType;
200 #else /* X_NOT_POSIX */
202 # define waitCode(w) (((w) >> 8) & 0x7f)
203 # define waitSig(w) ((w) & 0xff)
204 typedef int waitType;
207 # include <process.h>
208 typedef int waitType;
210 # include <sys/wait.h>
211 # define waitCode(w) ((w).w_T.w_Retcode)
212 # define waitSig(w) ((w).w_T.w_Termsig)
213 typedef union wait waitType;
217 # define WIFSIGNALED(w) waitSig(w)
220 # define WIFEXITED(w) waitCode(w)
222 #endif /* X_NOT_POSIX */
223 #ifndef X_NOT_STDC_ENV
226 char *malloc(), *realloc();
229 #ifdef X_NOT_STDC_ENV
230 extern char *getenv();
233 #ifdef X_NOT_STDC_ENV
237 #include <sys/utsname.h>
243 # define SYS_NMLN _SYS_NMLN
245 # define SYS_NMLN 257
252 * is strstr() in <strings.h> on X_NOT_STDC_ENV?
253 * are there any X_NOT_STDC_ENV machines left in the world?
257 #include "imakemdep.h"
260 * This define of strerror is copied from (and should be identical to)
261 * Xos.h, which we don't want to include here for bootstrapping reasons.
263 #if defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4))
265 extern char *sys_errlist[];
267 # define strerror(n) \
268 (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
275 #ifdef FIXUP_CPP_WHITESPACE
276 static int InRule = FALSE;
277 # ifdef INLINE_SYNTAX
278 static int InInline = 0;
281 #ifdef MAGIC_MAKE_VARS
282 static int xvariable = 0;
283 static int xvariables[10];
287 * Some versions of cpp reduce all tabs in macro expansion to a single
288 * space. In addition, the escaped newline may be replaced with a
289 * space instead of being deleted. Blech.
291 #ifdef FIXUP_CPP_WHITESPACE
292 static void KludgeOutputLine(char **pline);
293 static void KludgeResetRule(void);
295 # define KludgeOutputLine(arg)
296 # define KludgeResetRule()
299 typedef unsigned char boolean;
303 # define DEFAULT_CC "cc"
308 # define DEFAULT_CPP CPP_PROGRAM
310 # define DEFAULT_CPP "/lib/cpp"
315 static char *cpp = NULL;
317 static char *tmpMakefile = "/tmp/Imf.XXXXXX";
318 static char *tmpImakefile = "/tmp/IIf.XXXXXX";
319 static char *make_argv[ ARGUMENTS ] = {
327 static int make_argindex;
328 static int cpp_argindex;
329 static char *Imakefile = NULL;
330 static char *Makefile = "Makefile";
331 static char *Template = "Imake.tmpl";
332 static char *ImakefileC = "Imakefile.c";
333 static boolean haveImakefileC = FALSE;
334 static char *cleanedImakefile = NULL;
335 static char *program;
336 static boolean verbose = FALSE;
337 static boolean show = TRUE;
339 static char *FindImakefile(char *);
340 static char *ReadLine(FILE *, const char *);
341 static char *CleanCppInput(char *);
342 static char *Strdup(const char *);
343 static char *Emalloc(int);
344 static void LogFatal(const char *, ...);
345 static void LogMsg(const char *, ...);
346 static void Log(const char *, va_list);
348 static void showit(FILE *);
349 static void wrapup(void);
351 #ifdef SIGNALRETURNSINT
357 static void init(void);
358 static void AddMakeArg(char *);
359 static void AddCppArg(char *);
360 static void SetOpts(int, char **);
361 static void showargs(char **);
362 static void CheckImakefileC(const char *);
363 static boolean optional_include(FILE *, const char *, const char *);
364 static void doit(FILE *, const char *, char **);
365 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
366 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
367 static void parse_utsname(struct utsname *, const char *, char *, const char *);
369 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
370 static const char *trim_version(const char *);
373 static void get_distrib(FILE *);
374 static void get_libc_version(FILE *);
375 static void get_ld_version(FILE *);
377 #if defined(sun) && defined(__SVR4)
378 static char *get_full_path(const char *program);
379 static int get_sun_compiler_version(const char *fspec, const char *product,
380 int *cmajor, int *cminor);
381 static void get_sun_compiler_versions(FILE *);
383 static void get_gcc_incdir(FILE *);
384 static boolean define_os_defaults(FILE *);
385 static void cppit(const char *i, const char *, const char *, FILE *, const char *);
386 static void makeit(void);
387 static void CleanCppOutput(FILE *, const char *);
388 static boolean isempty(char *);
389 static void writetmpfile(FILE *, const char *, int, const char *);
392 main(int argc, char *argv[])
395 char makeMacro[ BUFSIZ ];
396 char makefileMacro[ BUFSIZ ];
402 Imakefile = FindImakefile(Imakefile);
403 CheckImakefileC(ImakefileC);
405 tmpMakefile = Makefile;
407 tmpMakefile = Strdup(tmpMakefile);
408 int ret = mkstemp(tmpMakefile);
412 AddMakeArg( tmpMakefile );
413 snprintf(makeMacro, BUFSIZ, "MAKE=%s", program);
414 AddMakeArg( makeMacro );
415 snprintf(makefileMacro, BUFSIZ, "MAKEFILE=%s", Imakefile);
416 AddMakeArg( makefileMacro );
418 if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
419 LogFatal("Cannot create temporary file %s.", tmpMakefile);
421 cleanedImakefile = CleanCppInput(Imakefile);
422 cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
425 if (Makefile == NULL)
440 while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
441 writetmpfile(stdout, buf, red, "stdout");
443 LogFatal("Cannot read %s.", tmpMakefile);
449 if (tmpMakefile != Makefile)
451 if (cleanedImakefile && cleanedImakefile != Imakefile)
452 unlink(cleanedImakefile);
458 #ifdef SIGNALRETURNSINT
466 LogFatal("Signal %d.", sig);
470 * Initialize some variables.
478 while (make_argv[ make_argindex ] != NULL)
481 while (cpp_argv[ cpp_argindex ] != NULL)
485 * See if the standard include directory is different than
486 * the default. Or if cpp is not the default. Or if the make
487 * found by the PATH variable is not the default.
489 if ((p = getenv("IMAKEINCLUDE"))) {
490 if (*p != '-' || *(p+1) != 'I')
491 LogFatal("Environment var IMAKEINCLUDE %s must begin with -I");
499 if ((p = getenv("IMAKECPP")))
501 if ((p = getenv("IMAKEMAKE")))
504 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
505 signal(SIGINT, catch);
509 AddMakeArg(char *arg)
512 if (make_argindex >= ARGUMENTS-1)
513 LogFatal("Out of internal storage.");
514 make_argv[ make_argindex++ ] = arg;
515 make_argv[ make_argindex ] = NULL;
522 if (cpp_argindex >= ARGUMENTS-1)
523 LogFatal("Out of internal storage.");
524 cpp_argv[ cpp_argindex++ ] = arg;
525 cpp_argv[ cpp_argindex ] = NULL;
529 SetOpts(int argc, char **argv)
533 * Now gather the arguments for make
535 for(argc--, argv++; argc; argc--, argv++) {
537 * We intercept these flags.
539 if (argv[0][0] == '-') {
540 if (argv[0][1] == 'D') {
542 } else if (argv[0][1] == 'I') {
544 } else if (argv[0][1] == 'f') {
546 Imakefile = argv[0]+2;
550 LogFatal("No description arg after -f flag");
553 } else if (argv[0][1] == 's') {
555 Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
560 LogFatal("No description arg after -s flag");
561 Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
565 } else if (argv[0][1] == 'e') {
566 Makefile = (argv[0][2] ? argv[0]+2 : NULL);
568 } else if (argv[0][1] == 'T') {
570 Template = argv[0]+2;
574 LogFatal("No description arg after -T flag");
577 } else if (argv[0][1] == 'C') {
579 ImakefileC = argv[0]+2;
583 LogFatal("No imakeCfile arg after -C flag");
584 ImakefileC = argv[0];
586 } else if (argv[0][1] == 'v') {
604 AddCppArg(ImakefileC);
608 FindImakefile(char *Imakefile)
611 if (access(Imakefile, R_OK) < 0)
612 LogFatal("Cannot find %s.", Imakefile);
614 if (access("Imakefile", R_OK) < 0)
615 if (access("imakefile", R_OK) < 0)
616 LogFatal("No description file.");
618 Imakefile = "imakefile";
620 Imakefile = "Imakefile";
626 LogFatal(const char *s, ...)
628 static boolean entered = FALSE;
640 fprintf(stderr, "Stop.\n");
648 LogMsg(const char *s, ...)
658 Log(const char *s, va_list args)
660 int error_number = errno;
663 fprintf(stderr, "%s: ", program);
664 fprintf(stderr, "%s\n", strerror(error_number));
666 fprintf(stderr, "%s: ", program);
667 vfprintf(stderr, s, args);
668 fprintf(stderr, "\n");
672 showargs(char **argv)
674 for (; *argv; argv++)
675 fprintf(stderr, "%s ", *argv);
676 fprintf(stderr, "\n");
679 #define ImakefileCHeader "/* imake - temporary file */"
682 CheckImakefileC(const char *masterc)
687 if (access(masterc, F_OK) == 0) {
688 inFile = fopen(masterc, "r");
690 LogFatal("Refuse to overwrite: %s", masterc);
691 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
692 strncmp(mkcbuf, ImakefileCHeader,
693 sizeof(ImakefileCHeader)-1)))
696 LogFatal("Refuse to overwrite: %s", masterc);
702 #define LocalDefineFmt "#define %s \"%s\"\n"
703 #define IncludeFmt "#include %s\n"
704 #define ImakeDefSym "INCLUDE_IMAKEFILE"
705 #define ImakeTmplSym "IMAKE_TEMPLATE"
706 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
709 optional_include(FILE *inFile, const char *defsym, const char *fname)
712 if (access(fname, R_OK) == 0) {
714 LogMsg(OverrideWarning, fname);
715 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
716 fprintf(inFile, IncludeFmt, defsym) < 0);
722 doit(FILE *outfd, const char *cmd, char **argv)
728 * Fork and exec the command.
732 dup2(fileno(outfd), 1);
733 status = _spawnvp(_P_WAIT, cmd, argv);
735 LogFatal("Cannot spawn %s.", cmd);
737 LogFatal("Exit code %d.", status);
741 LogFatal("Cannot fork.");
742 if (pid) { /* parent... simply wait */
743 while (wait(&status) > 0) {
745 if (WIFSIGNALED(status))
746 LogFatal("Signal %d.", waitSig(status));
747 if (WIFEXITED(status) && waitCode(status))
748 LogFatal("Exit code %d.", waitCode(status));
751 else { /* child... dup and exec cmd */
755 dup2(fileno(outfd), 1);
757 LogFatal("Cannot exec %s.", cmd);
764 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
765 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
767 parse_utsname(struct utsname *name, const char *fmt, char *result, const char *msg)
769 char buf[SYS_NMLN * 5 + 1];
773 /* Assemble all the pieces into a buffer. */
774 for (arg = 0; fmt[arg] != ' '; arg++)
776 /* Our buffer is only guaranteed to hold 5 arguments. */
785 strncpy(ptr, name->sysname, SYS_NMLN);
792 strncpy(ptr, name->nodename, SYS_NMLN);
799 strncpy(ptr, name->release, SYS_NMLN);
806 strncpy(ptr, name->version, SYS_NMLN);
813 strncpy(ptr, name->machine, SYS_NMLN);
822 /* Just in case... */
823 if (strlen(buf) >= sizeof(buf))
824 LogFatal("Buffer overflow parsing uname.");
826 /* Parse the buffer. The sscanf() return value is rarely correct. */
828 int ret = sscanf(buf, fmt + arg + 1, result);
833 /* Trim leading 0's and periods from version names. The 0's cause
834 the number to be interpreted as octal numbers. Some version strings
835 have the potential for different numbers of .'s in them.
838 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
840 trim_version(const char *p)
843 if (p != 0 && *p != '\0')
845 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
856 get_distrib(FILE *inFile)
860 static char* yast = "/sbin/YaST";
861 static char* redhat = "/etc/redhat-release";
863 fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
864 fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
865 fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
866 fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
867 fprintf (inFile, "%s\n", "#define LinuxDebian 4");
868 fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
869 fprintf (inFile, "%s\n", "#define LinuxKheops 6");
870 fprintf (inFile, "%s\n", "#define LinuxPro 7");
871 fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
872 fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
873 fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
874 fprintf (inFile, "%s\n", "#define LinuxWare 11");
875 fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
877 if (lstat (yast, &sb) == 0) {
878 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
881 if (lstat (redhat, &sb) == 0) {
882 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
885 /* what's the definitive way to tell what any particular distribution is? */
887 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
888 /* would like to know what version of the distribution it is */
891 static const char libc_c[]=
892 "#include <stdio.h>\n"
893 "#include <ctype.h>\n"
896 "#pragma weak gnu_get_libc_version\n"
897 "#pragma weak __libc_version\n"
898 "#pragma weak __linux_C_lib_version\n"
900 "asm (\".weak gnu_get_libc_version\");\n"
901 "asm (\".weak __libc_version\");\n"
902 "asm (\".weak __linux_C_lib_version\");\n"
905 "extern const char * gnu_get_libc_version (void);\n"
906 "extern const char * __linux_C_lib_version;\n"
907 "extern const char __libc_version [];\n"
912 " int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
914 " if (((&__linux_C_lib_version != 0)\n"
915 " && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
916 " || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
917 " && !(gnu_get_libc_version != 0)))\n"
925 " const char * ptr;\n"
926 " int glibcmajor = 0;\n"
928 " if (gnu_get_libc_version != 0)\n"
930 " ptr = gnu_get_libc_version ();\n"
933 " else if (&__libc_version != 0)\n"
935 " ptr = __libc_version;\n"
939 " ptr = __linux_C_lib_version;\n"
941 " while (!isdigit (*ptr))\n"
944 " sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
945 " libcmajor += glibcmajor;\n"
948 " printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
949 " printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
950 " printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
956 #define libc32path "/usr/lib/libc.so"
957 #define libc64path "/usr/lib64/libc.so"
960 get_libc_version(FILE *inFile)
966 int libcmajor, libcminor, libcteeny;
970 * If we are on a 64-bit Linux system and we see /usr/lib64/libc.so,
971 * we should use it. Otherwise go with /usr/lib/libc.so. It is entirely
972 * possible that someone will be running a 32-bit userland on a 64-bit
975 if (uname(&u) == -1) {
976 fprintf(stderr, "%s (%d): %s\n", __func__, __LINE__, strerror(errno));
980 if (!strcmp(u.sysname, "Linux") &&
981 (!strcmp(u.machine, "x86_64"))) {
982 if (!lstat (libc64path, &sb) && S_ISREG(sb.st_mode)) {
987 if (libcso == NULL) {
991 if (lstat (libcso, &sb) == 0) {
992 if (S_ISLNK (sb.st_mode)) {
994 * /usr/lib/libc.so is a symlink -- this is libc 5.x
995 * we can do this the quick way
997 if (readlink (libcso, buf, PATH_MAX) >= 0) {
998 for (ptr = buf; *ptr && !isdigit (*ptr); ptr++);
999 int ret = sscanf (ptr, "%d.%d.%d", &libcmajor, &libcminor, &libcteeny);
1001 fprintf(inFile, "#define DefaultLinuxCLibMajorVersion %d\n", libcmajor);
1002 fprintf(inFile, "#define DefaultLinuxCLibMinorVersion %d\n", libcminor);
1003 fprintf(inFile, "#define DefaultLinuxCLibTeenyVersion %d\n", libcteeny);
1007 * /usr/lib/libc.so is NOT a symlink -- this is libc 6.x / glibc 2.x
1008 * now we have to figure this out the hard way.
1010 char aout[PATH_MAX];
1013 const char *format = "%s -o %s -x c -";
1018 memset(aout, '\0', PATH_MAX);
1020 if (!lstat(getenv("TMPDIR"), &sb) && S_ISDIR(sb.st_mode))
1021 strncpy(aout, getenv("TMPDIR"), PATH_MAX - 1);
1022 #ifdef P_tmpdir /* defined by XPG and XOPEN, but don't assume we have it */
1023 else if (!lstat(P_tmpdir, &sb) && S_ISDIR(sb.st_mode))
1024 strncpy(aout, P_tmpdir, PATH_MAX - 1);
1026 else if (!lstat("/tmp", &sb) && S_ISDIR(sb.st_mode))
1027 strncpy(aout, "/tmp", PATH_MAX - 1);
1031 strncat(aout, "/imaketmp.XXXXXX", PATH_MAX - 1);
1033 if ((fd = mkstemp(aout)) == -1)
1036 if (close(fd) == -1)
1042 len = strlen (aout) + strlen (format) + strlen (cc);
1043 if (len < 128) len = 128;
1044 command = alloca (len);
1046 if (snprintf (command , len, format, cc, aout) == len)
1049 fp = popen (command, "w");
1050 if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 || pclose (fp) != 0)
1053 fp = popen (aout, "r");
1057 while (fgets (command, len, fp))
1058 fprintf (inFile, "%s", command);
1069 get_ld_version(FILE *inFile)
1071 FILE* ldprog = popen ("ld -v", "r");
1073 int ldmajor, ldminor;
1078 } while (c != EOF && !isdigit (c));
1080 int ret = fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
1082 fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
1083 ldmajor * 10 + ldminor);
1090 #define PATH_MAX 1024
1093 #if defined(sun) && defined(__SVR4)
1096 get_full_path(const char *program)
1102 buf = calloc(1, PATH_MAX);
1103 asprintf(&cmd, "command -v %s", program);
1105 if ((proc = popen (cmd, "r")) != NULL)
1106 fgets (buf, PATH_MAX, proc);
1110 return strtok (buf, "\n"); /* strip newline */
1114 get_sun_compiler_version(const char *fspec, const char *product,
1115 int *cmajor, int *cminor)
1125 if (lstat (fspec, &sb) != 0)
1128 strncpy (cmd, fspec, PATH_MAX);
1129 strlcpy (vendor, product, 4);
1131 if (strcmp (vendor, "Sun") == 0)
1132 strncat (cmd, " -V 2>&1", 8);
1133 else if (strcmp (vendor, "Gnu") == 0)
1134 strncat (cmd, " --version 2>&1", 15);
1138 if ((ccproc = popen (cmd, "r")) != NULL) {
1139 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1140 for (vptr = buf; !isdigit(*vptr) && *vptr != NULL; vptr++);
1141 if (*vptr == NULL) {
1145 ret = sscanf (vptr, "%d.%d", cmajor, cminor);
1157 get_sun_compiler_versions(FILE *inFile)
1159 static const char *compilers[][2] =
1160 {{"SunProC", "/opt/solarisstudio/bin/cc"},
1161 {"SunProCplusplus", "/opt/solarisstudio/bin/CC"},
1163 {"GnuCplusplus", "g++"}};
1168 for (i = 0; i < sizeof compilers / sizeof compilers[0]; i++) {
1169 const char *product = compilers[i][0];
1170 char *fspec = get_full_path (compilers[i][1]);
1172 ret = get_sun_compiler_version (fspec, product, &cmajor, &cminor);
1177 "#define Default%sCompilerMajorVersion %d\n",
1181 "#define Default%sCompilerMinorVersion %d\n",
1184 } else if (ret == EINVAL) {
1185 printf ("Failed to detect version of compiler: %s\n", product);
1196 get_gcc_incdir(FILE *inFile)
1198 static char* gcc_path[] = {
1200 "/usr/bin/cc", /* for Linux PostIncDir */
1205 "/usr/local/bin/gcc",
1215 memset(buf, 0, PATH_MAX);
1216 for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
1218 gcc_path[i] = get_full_path (gcc_path[i]);
1220 if (lstat (gcc_path[i], &sb) == 0) {
1224 strncpy (cmd, gcc_path[i], PATH_MAX - 1 );
1225 strncat (cmd, " --print-libgcc-file-name", PATH_MAX - 1);
1226 if ((gccproc = popen (cmd, "r")) != NULL) {
1227 if (fgets (buf, PATH_MAX - 1, gccproc) != NULL) {
1228 ptr = strstr (buf, "libgcc.a");
1229 if (ptr) strncpy (ptr, "include", 8);
1231 (void) pclose (gccproc);
1237 fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1241 define_os_defaults(FILE *inFile)
1244 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1245 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
1246 struct utsname name;
1247 char buf[SYS_NMLN * 5 + 1];
1249 /* Obtain the system information. */
1250 if (uname(&name) < 0)
1251 LogFatal("Cannot invoke uname");
1253 # ifdef DEFAULT_OS_NAME
1254 parse_utsname(&name, DEFAULT_OS_NAME, buf,
1255 "Bad DEFAULT_OS_NAME syntax %s");
1257 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1260 # ifdef DEFAULT_OS_MAJOR_REV
1261 parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1262 "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1263 fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1264 *buf ? trim_version(buf) : "0");
1267 # ifdef DEFAULT_OS_MINOR_REV
1268 parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1269 "Bad DEFAULT_OS_MINOR_REV syntax %s");
1270 fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1271 *buf ? trim_version(buf) : "0");
1274 # ifdef DEFAULT_OS_TEENY_REV
1275 parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1276 "Bad DEFAULT_OS_TEENY_REV syntax %s");
1277 fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1278 *buf ? trim_version(buf) : "0");
1282 get_distrib (inFile);
1283 get_libc_version (inFile);
1284 get_ld_version(inFile);
1286 get_gcc_incdir(inFile);
1287 #if defined (sun) && defined(SVR4)
1288 get_sun_compiler_versions (inFile);
1292 static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
1294 memset(&osvi, 0, sizeof(OSVERSIONINFO));
1295 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1296 GetVersionEx (&osvi);
1298 fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
1299 os_names[osvi.dwPlatformId]);
1301 fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
1302 fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
1303 fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
1304 osvi.dwBuildNumber & 0xFFFF);
1310 cppit(const char *imakefile, const char *template, const char *masterc, FILE *outfd, const char *outfname)
1314 haveImakefileC = TRUE;
1315 inFile = fopen(masterc, "w");
1317 LogFatal("Cannot open %s for output.", masterc);
1318 if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1319 define_os_defaults(inFile) ||
1320 optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1321 optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1322 fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1323 fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1324 fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1325 optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1326 optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1329 LogFatal("Cannot write to %s.", masterc);
1333 doit(outfd, cpp, cpp_argv);
1334 CleanCppOutput(outfd, outfname);
1340 doit(NULL, make_argv[0], make_argv);
1344 CleanCppInput(char *imakefile)
1346 FILE *outFile = NULL;
1348 char *buf, /* buffer for file content */
1349 *pbuf, /* walking pointer to buf */
1350 *punwritten, /* pointer to unwritten portion of buf */
1351 *ptoken, /* pointer to # token */
1352 *pend, /* pointer to end of # token */
1353 savec; /* temporary character holder */
1358 * grab the entire file.
1360 if (!(inFile = fopen(imakefile, "r")))
1361 LogFatal("Cannot open %s for input.", imakefile);
1362 if (fstat(fileno(inFile), &st) < 0)
1363 LogFatal("Cannot stat %s for size.", imakefile);
1364 buf = Emalloc((int)st.st_size+3);
1365 count = fread(buf + 2, 1, st.st_size, inFile);
1366 if (count == 0 && st.st_size != 0)
1367 LogFatal("Cannot read %s:", imakefile);
1371 buf[count + 2] = '\0';
1373 punwritten = pbuf = buf + 2;
1375 /* for compatibility, replace make comments for cpp */
1376 if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1378 while (*ptoken == ' ' || *ptoken == '\t')
1381 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1385 if (strcmp(ptoken, "define") &&
1386 strcmp(ptoken, "if") &&
1387 strcmp(ptoken, "ifdef") &&
1388 strcmp(ptoken, "ifndef") &&
1389 strcmp(ptoken, "include") &&
1390 strcmp(ptoken, "line") &&
1391 strcmp(ptoken, "else") &&
1392 strcmp(ptoken, "elif") &&
1393 strcmp(ptoken, "endif") &&
1394 strcmp(ptoken, "error") &&
1395 strcmp(ptoken, "pragma") &&
1396 strcmp(ptoken, "undef")) {
1397 if (outFile == NULL) {
1398 tmpImakefile = Strdup(tmpImakefile);
1399 int ret = mkstemp(tmpImakefile);
1401 outFile = fopen(tmpImakefile, "w");
1402 if (outFile == NULL)
1403 LogFatal("Cannot open %s for write.",
1406 writetmpfile(outFile, punwritten, pbuf-punwritten,
1408 if (ptoken > pbuf + 1)
1409 writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1411 writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1412 punwritten = pbuf + 1;
1419 writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1421 return tmpImakefile;
1428 CleanCppOutput(FILE *tmpfd, const char *tmpfname)
1433 while ((input = ReadLine(tmpfd, tmpfname))) {
1434 if (isempty(input)) {
1440 KludgeOutputLine(&input);
1441 writetmpfile(tmpfd, input, strlen(input), tmpfname);
1443 writetmpfile(tmpfd, "\n", 1, tmpfname);
1446 #ifdef NFS_STDOUT_BUG
1448 * On some systems, NFS seems to leave a large number of nulls at
1449 * the end of the file. Ralph Swick says that this kludge makes the
1452 ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1457 * Determine if a line has nothing in it. As a side effect, we trim white
1458 * space from the end of the line. Cpp magic cookies are also thrown away.
1459 * "XCOMM" token is transformed to "#".
1467 * Check for lines of the form
1476 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1477 pend[3] == 'e' && pend[4] == ' ')
1479 if (isdigit((int)*pend)) {
1482 } while (isdigit((int)*pend));
1483 if (*pend == '\n' || *pend == '\0')
1485 if (*pend++ == ' ' && *pend == '"')
1491 for (pend = line; *pend; pend++) {
1492 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1493 pend[3] == 'M' && pend[4] == 'M' &&
1494 (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1495 (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1498 strncpy(pend+1, pend+5, 1);
1500 #ifdef MAGIC_MAKE_VARS
1501 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1507 if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1508 pend[7] >= '0' && pend[7] <= '9')
1511 snprintf(varbuf, 5, "%0.4d", xvariable);
1512 strncpy(pend+4, varbuf, 4);
1513 xvariables[i] = xvariable;
1514 xvariable = (xvariable + 1) % 10000;
1516 else if (pend[4] == 'u' && pend[5] == 's' &&
1517 pend[6] == 'e' && pend[7] >= '0' &&
1521 snprintf(varbuf, 5, "%0.4d", xvariables[i]);
1522 strncpy(pend+4, varbuf, 4);
1528 while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1530 return (*line == '\0');
1535 ReadLine(FILE *tmpfd, const char *tmpfname)
1537 static boolean initialized = FALSE;
1538 static char *buf, *pline, *end;
1541 if (! initialized) {
1552 if (fstat(fileno(tmpfd), &st) < 0)
1553 LogFatal("cannot stat %s for size", tmpMakefile);
1554 pline = buf = Emalloc((int)st.st_size+1);
1555 total_red = fread(buf, 1, st.st_size, tmpfd);
1556 if (total_red == 0 && st.st_size != 0)
1557 LogFatal("cannot read %s", tmpMakefile);
1558 end = buf + total_red;
1561 #if defined(SYSV) || defined(WIN32)
1562 tmpfd = freopen(tmpfname, "w+", tmpfd);
1564 if (! tmpfd) /* if failed try again */
1565 tmpfd = freopen(tmpfname, "w+", fp);
1568 LogFatal("cannot reopen %s.", tmpfname);
1570 int ret = ftruncate(fileno(tmpfd), (off_t) 0);
1574 fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1575 fprintf (tmpfd, "# %s\n",
1576 "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
1579 for (p1 = pline; p1 < end; p1++) {
1580 if (*p1 == '@' && *(p1+1) == '@'
1581 /* ignore ClearCase version-extended pathnames */
1582 && !(p1 != pline && !isspace((int)*(p1-1))
1586 p1++; /* skip over second @ */
1589 else if (*p1 == '\n') { /* real EOL */
1591 if (p1 > pline && p1[-1] == '\r')
1600 * return NULL at the end of the file.
1602 p2 = (pline == p1 ? NULL : pline);
1608 writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
1610 if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1611 LogFatal("Cannot write to %s.", fname);
1619 if ((p = malloc(size)) == NULL)
1620 LogFatal("Cannot allocate %d bytes.", size);
1624 #ifdef FIXUP_CPP_WHITESPACE
1626 KludgeOutputLine(char **pline)
1629 char quotechar = '\0';
1632 case '#': /*Comment - ignore*/
1634 case '\t': /*Already tabbed - ignore it*/
1636 case ' ': /*May need a tab*/
1638 # ifdef INLINE_SYNTAX
1639 if (*p == '<' && p[1] == '<') { /* inline file close */
1646 * The following cases should not be treated as beginning of
1648 * variable := name (GNU make)
1649 * variable = .*:.* (':' should be allowed as value)
1650 * sed 's:/a:/b:' (: used in quoted values)
1654 if (quotechar == '\\' ||
1679 # ifdef REMOVE_CPP_LEADSPACE
1680 if (!InRule && **pline == ' ') {
1681 while (**pline == ' ')
1686 # ifdef INLINE_SYNTAX
1688 if (p[1] == '<') /* inline file start */
1695 while (**pline == ' ')
1702 if (InRule && **pline == ' ')
1709 KludgeResetRule(void)
1713 #endif /* FIXUP_CPP_WHITESPACE */
1716 Strdup(const char *cp)
1718 char *new = Emalloc(strlen(cp) + 1);
1720 memcpy(new, cp, strlen(cp) + 1);