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 #if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */
230 char *malloc(), *realloc();
232 #ifdef X_NOT_STDC_ENV
233 extern char *getenv();
236 #ifdef X_NOT_STDC_ENV
240 #include <sys/utsname.h>
246 # define SYS_NMLN _SYS_NMLN
248 # define SYS_NMLN 257
255 * is strstr() in <strings.h> on X_NOT_STDC_ENV?
256 * are there any X_NOT_STDC_ENV machines left in the world?
260 #include "imakemdep.h"
263 * This define of strerror is copied from (and should be identical to)
264 * Xos.h, which we don't want to include here for bootstrapping reasons.
266 #if defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4)) || defined(macII)
268 extern char *sys_errlist[];
270 # define strerror(n) \
271 (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
278 #ifdef FIXUP_CPP_WHITESPACE
279 static int InRule = FALSE;
280 # ifdef INLINE_SYNTAX
281 static int InInline = 0;
284 #ifdef MAGIC_MAKE_VARS
285 static int xvariable = 0;
286 static int xvariables[10];
290 * Some versions of cpp reduce all tabs in macro expansion to a single
291 * space. In addition, the escaped newline may be replaced with a
292 * space instead of being deleted. Blech.
294 #ifdef FIXUP_CPP_WHITESPACE
295 static void KludgeOutputLine(char **pline);
296 static void KludgeResetRule(void);
298 # define KludgeOutputLine(arg)
299 # define KludgeResetRule()
302 typedef unsigned char boolean;
306 # define DEFAULT_CC "cc"
311 # define DEFAULT_CPP CPP_PROGRAM
313 # define DEFAULT_CPP "/lib/cpp"
318 static char *cpp = NULL;
320 static char *tmpMakefile = "/tmp/Imf.XXXXXX";
321 static char *tmpImakefile = "/tmp/IIf.XXXXXX";
322 static char *make_argv[ ARGUMENTS ] = {
330 static int make_argindex;
331 static int cpp_argindex;
332 static char *Imakefile = NULL;
333 static char *Makefile = "Makefile";
334 static char *Template = "Imake.tmpl";
335 static char *ImakefileC = "Imakefile.c";
336 static boolean haveImakefileC = FALSE;
337 static char *cleanedImakefile = NULL;
338 static char *program;
339 static boolean verbose = FALSE;
340 static boolean show = TRUE;
342 static char *FindImakefile(char *);
343 static char *ReadLine(FILE *, const char *);
344 static char *CleanCppInput(char *);
345 static char *Strdup(const char *);
346 static char *Emalloc(int);
347 static void LogFatal(const char *, ...);
348 static void LogMsg(const char *, ...);
349 static void Log(const char *, va_list);
351 static void showit(FILE *);
352 static void wrapup(void);
354 #ifdef SIGNALRETURNSINT
360 static void init(void);
361 static void AddMakeArg(char *);
362 static void AddCppArg(char *);
363 static void SetOpts(int, char **);
364 static void showargs(char **);
365 static void CheckImakefileC(const char *);
366 static boolean optional_include(FILE *, const char *, const char *);
367 static void doit(FILE *, const char *, char **);
368 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
369 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
370 static void parse_utsname(struct utsname *, const char *, char *, const char *);
372 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
373 static const char *trim_version(const char *);
376 static void get_distrib(FILE *);
377 static void get_libc_version(FILE *);
378 static void get_ld_version(FILE *);
380 #if defined(sun) && defined(__SVR4)
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)
1095 get_sun_compiler_versions(FILE *inFile)
1099 static char* sunpro_cc = "/opt/solarisstudio/bin/cc";
1100 static char* sunpro_CC = "/opt/solarisstudio/bin/CC";
1101 static char* gnu_cc1 = "/usr/bin/gcc";
1102 static char* gnu_cc2 = "/usr/gnu/bin/gcc";
1103 static char* gnu_CC1 = "/usr/bin/g++";
1104 static char* gnu_CC2 = "/usr/gnu/bin/g++";
1111 if (lstat (sunpro_cc, &sb) == 0) {
1112 strncpy (cmd, sunpro_cc, PATH_MAX);
1113 strncat (cmd, " -V 2>&1", 8);
1114 if ((ccproc = popen (cmd, "r")) != NULL) {
1115 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1116 vptr = strrchr (buf, 'C');
1117 for (; !isdigit(*vptr); vptr++);
1118 ret = sscanf (vptr, "%d.%d", &cmajor, &cminor);
1120 "#define DefaultSunProCCompilerMajorVersion %d\n",
1123 "#define DefaultSunProCCompilerMinorVersion %d\n",
1126 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1130 if (lstat (sunpro_CC, &sb) == 0) {
1131 strncpy (cmd, sunpro_CC, PATH_MAX);
1132 strncat (cmd, " -V 2>&1", 8);
1133 if ((ccproc = popen (cmd, "r")) != NULL) {
1134 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1135 vptr = strrchr (buf, 'C');
1136 for (; !isdigit(*vptr); vptr++);
1137 ret = sscanf (vptr, "%d.%d", &cmajor, &cminor);
1139 "#define DefaultSunProCplusplusCompilerMajorVersion %d\n",
1142 "#define DefaultSunProCplusplusCompilerMinorVersion %d\n",
1145 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1150 if (lstat (gnu_cc1, &sb) == 0) {
1151 strncpy (cmd, gnu_cc1, PATH_MAX);
1153 else if (lstat (gnu_cc2, &sb) == 0) {
1154 strncpy (cmd, gnu_cc2, PATH_MAX);
1156 if (cmd[0] != '\0') {
1157 strncat (cmd, " --version 2>&1", 15);
1158 if ((ccproc = popen (cmd, "r")) != NULL) {
1159 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1160 vptr = strrchr (buf, 'G');
1161 for (; !isdigit(*vptr); vptr++);
1162 ret = sscanf (vptr, "%d.%d", &cmajor, &cminor);
1164 "#define DefaultGnuCCompilerMajorVersion %d\n",
1167 "#define DefaultGnuCCompilerMinorVersion %d\n",
1170 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1175 if (lstat (gnu_CC1, &sb) == 0) {
1176 strncpy (cmd, gnu_CC1, PATH_MAX);
1178 else if (lstat (gnu_CC2, &sb) == 0) {
1179 strncpy (cmd, gnu_CC2, PATH_MAX);
1181 if (cmd[0] != '\0') {
1182 strncat (cmd, " --version 2>&1", 15);
1183 if ((ccproc = popen (cmd, "r")) != NULL) {
1184 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1185 vptr = strrchr (buf, 'G');
1186 for (; !isdigit(*vptr); vptr++);
1187 ret = sscanf (vptr, "%d.%d", &cmajor, &cminor);
1189 "#define DefaultGnuCplusplusCompilerMajorVersion %d\n",
1192 "#define DefaultGnuCplusplusCompilerMinorVersion %d\n",
1195 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1204 get_gcc_incdir(FILE *inFile)
1206 static char* gcc_path[] = {
1208 "/usr/bin/cc", /* for Linux PostIncDir */
1214 "/usr/local/bin/gcc",
1224 memset(buf, 0, PATH_MAX);
1225 for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
1226 if (lstat (gcc_path[i], &sb) == 0) {
1227 strncpy (cmd, gcc_path[i], PATH_MAX - 1 );
1228 strncat (cmd, " --print-libgcc-file-name", PATH_MAX - 1);
1229 if ((gccproc = popen (cmd, "r")) != NULL) {
1230 if (fgets (buf, PATH_MAX - 1, gccproc) != NULL) {
1231 ptr = strstr (buf, "libgcc.a");
1232 if (ptr) strncpy (ptr, "include", 8);
1234 (void) pclose (gccproc);
1240 fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1244 define_os_defaults(FILE *inFile)
1247 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1248 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
1249 struct utsname name;
1250 char buf[SYS_NMLN * 5 + 1];
1252 /* Obtain the system information. */
1253 if (uname(&name) < 0)
1254 LogFatal("Cannot invoke uname");
1256 # ifdef DEFAULT_OS_NAME
1257 parse_utsname(&name, DEFAULT_OS_NAME, buf,
1258 "Bad DEFAULT_OS_NAME syntax %s");
1260 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1263 # ifdef DEFAULT_OS_MAJOR_REV
1264 parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1265 "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1266 fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1267 *buf ? trim_version(buf) : "0");
1270 # ifdef DEFAULT_OS_MINOR_REV
1271 parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1272 "Bad DEFAULT_OS_MINOR_REV syntax %s");
1273 fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1274 *buf ? trim_version(buf) : "0");
1277 # ifdef DEFAULT_OS_TEENY_REV
1278 parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1279 "Bad DEFAULT_OS_TEENY_REV syntax %s");
1280 fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1281 *buf ? trim_version(buf) : "0");
1285 get_distrib (inFile);
1286 get_libc_version (inFile);
1287 get_ld_version(inFile);
1289 get_gcc_incdir(inFile);
1290 #if defined (sun) && defined(SVR4)
1291 get_sun_compiler_versions (inFile);
1295 static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
1297 memset(&osvi, 0, sizeof(OSVERSIONINFO));
1298 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1299 GetVersionEx (&osvi);
1301 fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
1302 os_names[osvi.dwPlatformId]);
1304 fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
1305 fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
1306 fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
1307 osvi.dwBuildNumber & 0xFFFF);
1313 cppit(const char *imakefile, const char *template, const char *masterc, FILE *outfd, const char *outfname)
1317 haveImakefileC = TRUE;
1318 inFile = fopen(masterc, "w");
1320 LogFatal("Cannot open %s for output.", masterc);
1321 if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1322 define_os_defaults(inFile) ||
1323 optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1324 optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1325 fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1326 fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1327 fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1328 optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1329 optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1332 LogFatal("Cannot write to %s.", masterc);
1336 doit(outfd, cpp, cpp_argv);
1337 CleanCppOutput(outfd, outfname);
1343 doit(NULL, make_argv[0], make_argv);
1347 CleanCppInput(char *imakefile)
1349 FILE *outFile = NULL;
1351 char *buf, /* buffer for file content */
1352 *pbuf, /* walking pointer to buf */
1353 *punwritten, /* pointer to unwritten portion of buf */
1354 *ptoken, /* pointer to # token */
1355 *pend, /* pointer to end of # token */
1356 savec; /* temporary character holder */
1361 * grab the entire file.
1363 if (!(inFile = fopen(imakefile, "r")))
1364 LogFatal("Cannot open %s for input.", imakefile);
1365 if (fstat(fileno(inFile), &st) < 0)
1366 LogFatal("Cannot stat %s for size.", imakefile);
1367 buf = Emalloc((int)st.st_size+3);
1368 count = fread(buf + 2, 1, st.st_size, inFile);
1369 if (count == 0 && st.st_size != 0)
1370 LogFatal("Cannot read %s:", imakefile);
1374 buf[count + 2] = '\0';
1376 punwritten = pbuf = buf + 2;
1378 /* for compatibility, replace make comments for cpp */
1379 if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1381 while (*ptoken == ' ' || *ptoken == '\t')
1384 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1388 if (strcmp(ptoken, "define") &&
1389 strcmp(ptoken, "if") &&
1390 strcmp(ptoken, "ifdef") &&
1391 strcmp(ptoken, "ifndef") &&
1392 strcmp(ptoken, "include") &&
1393 strcmp(ptoken, "line") &&
1394 strcmp(ptoken, "else") &&
1395 strcmp(ptoken, "elif") &&
1396 strcmp(ptoken, "endif") &&
1397 strcmp(ptoken, "error") &&
1398 strcmp(ptoken, "pragma") &&
1399 strcmp(ptoken, "undef")) {
1400 if (outFile == NULL) {
1401 tmpImakefile = Strdup(tmpImakefile);
1402 int ret = mkstemp(tmpImakefile);
1404 outFile = fopen(tmpImakefile, "w");
1405 if (outFile == NULL)
1406 LogFatal("Cannot open %s for write.",
1409 writetmpfile(outFile, punwritten, pbuf-punwritten,
1411 if (ptoken > pbuf + 1)
1412 writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1414 writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1415 punwritten = pbuf + 1;
1422 writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1424 return tmpImakefile;
1431 CleanCppOutput(FILE *tmpfd, const char *tmpfname)
1436 while ((input = ReadLine(tmpfd, tmpfname))) {
1437 if (isempty(input)) {
1443 KludgeOutputLine(&input);
1444 writetmpfile(tmpfd, input, strlen(input), tmpfname);
1446 writetmpfile(tmpfd, "\n", 1, tmpfname);
1449 #ifdef NFS_STDOUT_BUG
1451 * On some systems, NFS seems to leave a large number of nulls at
1452 * the end of the file. Ralph Swick says that this kludge makes the
1455 ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1460 * Determine if a line has nothing in it. As a side effect, we trim white
1461 * space from the end of the line. Cpp magic cookies are also thrown away.
1462 * "XCOMM" token is transformed to "#".
1470 * Check for lines of the form
1479 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1480 pend[3] == 'e' && pend[4] == ' ')
1482 if (isdigit((int)*pend)) {
1485 } while (isdigit((int)*pend));
1486 if (*pend == '\n' || *pend == '\0')
1488 if (*pend++ == ' ' && *pend == '"')
1494 for (pend = line; *pend; pend++) {
1495 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1496 pend[3] == 'M' && pend[4] == 'M' &&
1497 (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1498 (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1501 strncpy(pend+1, pend+5, 1);
1503 #ifdef MAGIC_MAKE_VARS
1504 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1510 if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1511 pend[7] >= '0' && pend[7] <= '9')
1514 snprintf(varbuf, 5, "%0.4d", xvariable);
1515 strncpy(pend+4, varbuf, 4);
1516 xvariables[i] = xvariable;
1517 xvariable = (xvariable + 1) % 10000;
1519 else if (pend[4] == 'u' && pend[5] == 's' &&
1520 pend[6] == 'e' && pend[7] >= '0' &&
1524 snprintf(varbuf, 5, "%0.4d", xvariables[i]);
1525 strncpy(pend+4, varbuf, 4);
1531 while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1533 return (*line == '\0');
1538 ReadLine(FILE *tmpfd, const char *tmpfname)
1540 static boolean initialized = FALSE;
1541 static char *buf, *pline, *end;
1544 if (! initialized) {
1555 if (fstat(fileno(tmpfd), &st) < 0)
1556 LogFatal("cannot stat %s for size", tmpMakefile);
1557 pline = buf = Emalloc((int)st.st_size+1);
1558 total_red = fread(buf, 1, st.st_size, tmpfd);
1559 if (total_red == 0 && st.st_size != 0)
1560 LogFatal("cannot read %s", tmpMakefile);
1561 end = buf + total_red;
1564 #if defined(SYSV) || defined(WIN32)
1565 tmpfd = freopen(tmpfname, "w+", tmpfd);
1567 if (! tmpfd) /* if failed try again */
1568 tmpfd = freopen(tmpfname, "w+", fp);
1571 LogFatal("cannot reopen %s.", tmpfname);
1573 int ret = ftruncate(fileno(tmpfd), (off_t) 0);
1577 fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1578 fprintf (tmpfd, "# %s\n",
1579 "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
1582 for (p1 = pline; p1 < end; p1++) {
1583 if (*p1 == '@' && *(p1+1) == '@'
1584 /* ignore ClearCase version-extended pathnames */
1585 && !(p1 != pline && !isspace((int)*(p1-1))
1589 p1++; /* skip over second @ */
1592 else if (*p1 == '\n') { /* real EOL */
1594 if (p1 > pline && p1[-1] == '\r')
1603 * return NULL at the end of the file.
1605 p2 = (pline == p1 ? NULL : pline);
1611 writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
1613 if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1614 LogFatal("Cannot write to %s.", fname);
1622 if ((p = malloc(size)) == NULL)
1623 LogFatal("Cannot allocate %d bytes.", size);
1627 #ifdef FIXUP_CPP_WHITESPACE
1629 KludgeOutputLine(char **pline)
1632 char quotechar = '\0';
1635 case '#': /*Comment - ignore*/
1637 case '\t': /*Already tabbed - ignore it*/
1639 case ' ': /*May need a tab*/
1641 # ifdef INLINE_SYNTAX
1642 if (*p == '<' && p[1] == '<') { /* inline file close */
1649 * The following cases should not be treated as beginning of
1651 * variable := name (GNU make)
1652 * variable = .*:.* (':' should be allowed as value)
1653 * sed 's:/a:/b:' (: used in quoted values)
1657 if (quotechar == '\\' ||
1682 # ifdef REMOVE_CPP_LEADSPACE
1683 if (!InRule && **pline == ' ') {
1684 while (**pline == ' ')
1689 # ifdef INLINE_SYNTAX
1691 if (p[1] == '<') /* inline file start */
1698 while (**pline == ' ')
1705 if (InRule && **pline == ' ')
1712 KludgeResetRule(void)
1716 #endif /* FIXUP_CPP_WHITESPACE */
1719 Strdup(const char *cp)
1721 char *new = Emalloc(strlen(cp) + 1);
1723 memcpy(new, cp, strlen(cp) + 1);