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 librararies 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?
259 #include "imakemdep.h"
262 * This define of strerror is copied from (and should be identical to)
263 * Xos.h, which we don't want to include here for bootstrapping reasons.
265 #if defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4)) || defined(macII)
267 extern char *sys_errlist[];
269 # define strerror(n) \
270 (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
277 #ifdef FIXUP_CPP_WHITESPACE
279 # ifdef INLINE_SYNTAX
283 #ifdef MAGIC_MAKE_VARS
289 * Some versions of cpp reduce all tabs in macro expansion to a single
290 * space. In addition, the escaped newline may be replaced with a
291 * space instead of being deleted. Blech.
293 #ifdef FIXUP_CPP_WHITESPACE
294 void KludgeOutputLine(), KludgeResetRule();
296 # define KludgeOutputLine(arg)
297 # define KludgeResetRule()
300 typedef unsigned char boolean;
304 # define DEFAULT_CC "cc"
309 # define DEFAULT_CPP CPP_PROGRAM
311 # define DEFAULT_CPP "/lib/cpp"
318 char *tmpMakefile = "/tmp/Imf.XXXXXX";
319 char *tmpImakefile = "/tmp/IIf.XXXXXX";
320 char *make_argv[ ARGUMENTS ] = {
330 char *Imakefile = NULL;
331 char *Makefile = "Makefile";
332 char *Template = "Imake.tmpl";
333 char *ImakefileC = "Imakefile.c";
334 boolean haveImakefileC = FALSE;
335 char *cleanedImakefile = NULL;
337 char *FindImakefile();
339 char *CleanCppInput();
342 void LogFatalI(), LogFatal(), LogMsg();
350 void CheckImakefileC();
353 void CleanCppOutput();
357 boolean verbose = FALSE;
366 char makeMacro[ BUFSIZ ];
367 char makefileMacro[ BUFSIZ ];
373 Imakefile = FindImakefile(Imakefile);
374 CheckImakefileC(ImakefileC);
376 tmpMakefile = Makefile;
378 tmpMakefile = Strdup(tmpMakefile);
379 (void) mktemp(tmpMakefile);
382 AddMakeArg( tmpMakefile );
383 sprintf(makeMacro, "MAKE=%s", program);
384 AddMakeArg( makeMacro );
385 sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
386 AddMakeArg( makefileMacro );
388 if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
389 LogFatal("Cannot create temporary file %s.", tmpMakefile);
391 cleanedImakefile = CleanCppInput(Imakefile);
392 cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
395 if (Makefile == NULL)
411 while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
412 writetmpfile(stdout, buf, red, "stdout");
414 LogFatal("Cannot read %s.", tmpMakefile);
420 if (tmpMakefile != Makefile)
422 if (cleanedImakefile && cleanedImakefile != Imakefile)
423 unlink(cleanedImakefile);
428 #ifdef SIGNALRETURNSINT
437 LogFatalI("Signal %d.", sig);
441 * Initialize some variables.
449 while (make_argv[ make_argindex ] != NULL)
452 while (cpp_argv[ cpp_argindex ] != NULL)
456 * See if the standard include directory is different than
457 * the default. Or if cpp is not the default. Or if the make
458 * found by the PATH variable is not the default.
460 if (p = getenv("IMAKEINCLUDE")) {
461 if (*p != '-' || *(p+1) != 'I')
462 LogFatal("Environment var IMAKEINCLUDE %s",
463 "must begin with -I");
471 if (p = getenv("IMAKECPP"))
473 if (p = getenv("IMAKEMAKE"))
476 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
477 signal(SIGINT, catch);
485 if (make_argindex >= ARGUMENTS-1)
486 LogFatal("Out of internal storage.", "");
487 make_argv[ make_argindex++ ] = arg;
488 make_argv[ make_argindex ] = NULL;
496 if (cpp_argindex >= ARGUMENTS-1)
497 LogFatal("Out of internal storage.", "");
498 cpp_argv[ cpp_argindex++ ] = arg;
499 cpp_argv[ cpp_argindex ] = NULL;
509 * Now gather the arguments for make
511 for(argc--, argv++; argc; argc--, argv++) {
513 * We intercept these flags.
515 if (argv[0][0] == '-') {
516 if (argv[0][1] == 'D') {
518 } else if (argv[0][1] == 'I') {
520 } else if (argv[0][1] == 'f') {
522 Imakefile = argv[0]+2;
526 LogFatal("No description arg after -f flag", "");
529 } else if (argv[0][1] == 's') {
531 Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
536 LogFatal("No description arg after -s flag", "");
537 Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
541 } else if (argv[0][1] == 'e') {
542 Makefile = (argv[0][2] ? argv[0]+2 : NULL);
544 } else if (argv[0][1] == 'T') {
546 Template = argv[0]+2;
550 LogFatal("No description arg after -T flag", "");
553 } else if (argv[0][1] == 'C') {
555 ImakefileC = argv[0]+2;
559 LogFatal("No imakeCfile arg after -C flag", "");
560 ImakefileC = argv[0];
562 } else if (argv[0][1] == 'v') {
580 AddCppArg(ImakefileC);
584 FindImakefile(Imakefile)
588 if (access(Imakefile, R_OK) < 0)
589 LogFatal("Cannot find %s.", Imakefile);
591 if (access("Imakefile", R_OK) < 0)
592 if (access("imakefile", R_OK) < 0)
593 LogFatal("No description file.", "");
595 Imakefile = "imakefile";
597 Imakefile = "Imakefile";
608 LogFatal(s, (char *)i);
615 static boolean entered = FALSE;
622 fprintf(stderr, " Stop.\n");
631 int error_number = errno;
634 fprintf(stderr, "%s: ", program);
635 fprintf(stderr, "%s\n", strerror(error_number));
637 fprintf(stderr, "%s: ", program);
638 fprintf(stderr, x0, x1);
639 fprintf(stderr, "\n");
646 for (; *argv; argv++)
647 fprintf(stderr, "%s ", *argv);
648 fprintf(stderr, "\n");
651 #define ImakefileCHeader "/* imake - temporary file */"
654 CheckImakefileC(masterc)
660 if (access(masterc, F_OK) == 0) {
661 inFile = fopen(masterc, "r");
663 LogFatal("Refuse to overwrite: %s", masterc);
664 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
665 strncmp(mkcbuf, ImakefileCHeader,
666 sizeof(ImakefileCHeader)-1)))
669 LogFatal("Refuse to overwrite: %s", masterc);
675 #define LocalDefineFmt "#define %s \"%s\"\n"
676 #define IncludeFmt "#include %s\n"
677 #define ImakeDefSym "INCLUDE_IMAKEFILE"
678 #define ImakeTmplSym "IMAKE_TEMPLATE"
679 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
682 optional_include(inFile, defsym, fname)
688 if (access(fname, R_OK) == 0) {
689 LogMsg(OverrideWarning, fname);
690 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
691 fprintf(inFile, IncludeFmt, defsym) < 0);
697 doit(outfd, cmd, argv)
706 * Fork and exec the command.
710 dup2(fileno(outfd), 1);
711 status = _spawnvp(_P_WAIT, cmd, argv);
713 LogFatal("Cannot spawn %s.", cmd);
715 LogFatalI("Exit code %d.", status);
719 LogFatal("Cannot fork.", "");
720 if (pid) { /* parent... simply wait */
721 while (wait(&status) > 0) {
723 if (WIFSIGNALED(status))
724 LogFatalI("Signal %d.", waitSig(status));
725 if (WIFEXITED(status) && waitCode(status))
726 LogFatalI("Exit code %d.", waitCode(status));
729 else { /* child... dup and exec cmd */
733 dup2(fileno(outfd), 1);
735 LogFatal("Cannot exec %s.", cmd);
742 parse_utsname(name, fmt, result, msg)
743 struct utsname *name;
748 char buf[SYS_NMLN * 5 + 1];
752 /* Assemble all the pieces into a buffer. */
753 for (arg = 0; fmt[arg] != ' '; arg++)
755 /* Our buffer is only guaranteed to hold 5 arguments. */
764 strcpy(ptr, name->sysname);
771 strcpy(ptr, name->nodename);
778 strcpy(ptr, name->release);
785 strcpy(ptr, name->version);
792 strcpy(ptr, name->machine);
801 /* Just in case... */
802 if (strlen(buf) >= sizeof(buf))
803 LogFatal("Buffer overflow parsing uname.", "");
805 /* Parse the buffer. The sscanf() return value is rarely correct. */
807 (void) sscanf(buf, fmt + arg + 1, result);
810 /* Trim leading 0's and periods from version names. The 0's cause
811 the number to be interpreted as octal numbers. Some version strings
812 have the potential for different numbers of .'s in them.
820 if (p != 0 && *p != '\0')
822 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
830 static void get_distrib(inFile)
835 static char* yast = "/sbin/YaST";
836 static char* redhat = "/etc/redhat-release";
838 fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
839 fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
840 fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
841 fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
842 fprintf (inFile, "%s\n", "#define LinuxDebian 4");
843 fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
844 fprintf (inFile, "%s\n", "#define LinuxKheops 6");
845 fprintf (inFile, "%s\n", "#define LinuxPro 7");
846 fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
847 fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
848 fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
849 fprintf (inFile, "%s\n", "#define LinuxWare 11");
850 fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
852 if (lstat (yast, &sb) == 0) {
853 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
856 if (lstat (redhat, &sb) == 0) {
857 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
860 /* what's the definitive way to tell what any particular distribution is? */
862 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
863 /* would like to know what version of the distribution it is */
866 static const char *libc_c=
867 "#include <stdio.h>\n"
868 "#include <ctype.h>\n"
871 "#pragma weak gnu_get_libc_version\n"
872 "#pragma weak __libc_version\n"
873 "#pragma weak __linux_C_lib_version\n"
875 "asm (\".weak gnu_get_libc_version\");\n"
876 "asm (\".weak __libc_version\");\n"
877 "asm (\".weak __linux_C_lib_version\");\n"
880 "extern const char * gnu_get_libc_version (void);\n"
881 "extern const char * __linux_C_lib_version;\n"
882 "extern const char __libc_version [];\n"
887 " int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
889 " if (((&__linux_C_lib_version != 0)\n"
890 " && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
891 " || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
892 " && !(gnu_get_libc_version != 0)))\n"
900 " const char * ptr;\n"
901 " int glibcmajor = 0;\n"
903 " if (gnu_get_libc_version != 0)\n"
905 " ptr = gnu_get_libc_version ();\n"
908 " else if (&__libc_version != 0)\n"
910 " ptr = __libc_version;\n"
914 " ptr = __linux_C_lib_version;\n"
916 " while (!isdigit (*ptr))\n"
919 " sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
920 " libcmajor += glibcmajor;\n"
923 " printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
924 " printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
925 " printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
931 static void get_libc_version(inFile)
934 static char* libcso = "/usr/lib/libc.so";
938 int libcmajor, libcminor, libcteeny;
940 if (lstat (libcso, &sb) == 0) {
941 if (S_ISLNK (sb.st_mode)) {
943 * /usr/lib/libc.so is a symlink -- this is libc 5.x
944 * we can do this the quick way
946 if (readlink (libcso, buf, PATH_MAX) >= 0) {
947 for (ptr = buf; *ptr && !isdigit (*ptr); ptr++);
948 (void) sscanf (ptr, "%d.%d.%d", &libcmajor, &libcminor, &libcteeny);
949 fprintf(inFile, "#define DefaultLinuxCLibMajorVersion %d\n", libcmajor);
950 fprintf(inFile, "#define DefaultLinuxCLibMinorVersion %d\n", libcminor);
951 fprintf(inFile, "#define DefaultLinuxCLibTeenyVersion %d\n", libcteeny);
955 * /usr/lib/libc.so is NOT a symlink -- this is libc 6.x / glibc 2.x
956 * now we have to figure this out the hard way.
958 char *aout = tmpnam (NULL);
960 const char *format = "%s -o %s -x c -";
968 len = strlen (aout) + strlen (format) + strlen (cc);
969 if (len < 128) len = 128;
970 command = alloca (len);
972 if (snprintf (command , len, format, cc, aout) == len)
975 fp = popen (command, "w");
976 if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 || pclose (fp) != 0)
979 fp = popen (aout, "r");
983 while (fgets (command, len, fp))
984 fprintf (inFile, command);
994 static void get_ld_version(inFile)
997 FILE* ldprog = popen ("ld -v", "r");
999 int ldmajor, ldminor;
1004 } while (c != EOF && !isdigit (c));
1006 (void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
1007 fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
1008 ldmajor * 10 + ldminor);
1015 #define PATH_MAX 1024
1018 #if defined(sun) && defined(__SVR4)
1019 static void get_sun_compiler_versions (inFile)
1024 static char* sunpro_cc = "/opt/SUNWspro/bin/cc";
1025 static char* sunpro_CC = "/opt/SUNWspro/bin/CC";
1031 if (lstat (sunpro_cc, &sb) == 0) {
1032 strcpy (cmd, sunpro_cc);
1033 strcat (cmd, " -V 2>&1");
1034 if ((ccproc = popen (cmd, "r")) != NULL) {
1035 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1036 vptr = strrchr (buf, 'C');
1037 for (; !isdigit(*vptr); vptr++);
1038 (void) sscanf (vptr, "%d.%d", &cmajor, &cminor);
1040 "#define DefaultSunProCCompilerMajorVersion %d\n",
1043 "#define DefaultSunProCCompilerMinorVersion %d\n",
1046 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1050 if (lstat (sunpro_CC, &sb) == 0) {
1051 strcpy (cmd, sunpro_CC);
1052 strcat (cmd, " -V 2>&1");
1053 if ((ccproc = popen (cmd, "r")) != NULL) {
1054 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1055 vptr = strrchr (buf, 'C');
1056 for (; !isdigit(*vptr); vptr++);
1057 (void) sscanf (vptr, "%d.%d", &cmajor, &cminor);
1059 "#define DefaultSunProCplusplusCompilerMajorVersion %d\n",
1062 "#define DefaultSunProCplusplusCompilerMinorVersion %d\n",
1065 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1072 static void get_gcc_incdir(inFile)
1075 static char* gcc_path[] = {
1077 "/usr/bin/cc", /* for Linux PostIncDir */
1079 "/usr/local/bin/gcc",
1090 for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
1091 if (lstat (gcc_path[i], &sb) == 0) {
1092 strcpy (cmd, gcc_path[i]);
1093 strcat (cmd, " --print-libgcc-file-name");
1094 if ((gccproc = popen (cmd, "r")) != NULL) {
1095 if (fgets (buf, PATH_MAX, gccproc) != NULL) {
1096 ptr = strstr (buf, "libgcc.a");
1097 if (ptr) strcpy (ptr, "include");
1099 (void) pclose (gccproc);
1105 fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1109 define_os_defaults(inFile)
1113 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1114 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAUL_OS_TEENY_REV))
1115 struct utsname name;
1116 char buf[SYS_NMLN * 5 + 1];
1118 /* Obtain the system information. */
1119 if (uname(&name) < 0)
1120 LogFatal("Cannot invoke uname", "");
1122 # ifdef DEFAULT_OS_NAME
1123 parse_utsname(&name, DEFAULT_OS_NAME, buf,
1124 "Bad DEFAULT_OS_NAME syntax %s");
1126 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1129 # ifdef DEFAULT_OS_MAJOR_REV
1130 parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1131 "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1132 fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1133 *buf ? trim_version(buf) : "0");
1136 # ifdef DEFAULT_OS_MINOR_REV
1137 parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1138 "Bad DEFAULT_OS_MINOR_REV syntax %s");
1139 fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1140 *buf ? trim_version(buf) : "0");
1143 # ifdef DEFAULT_OS_TEENY_REV
1144 parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1145 "Bad DEFAULT_OS_TEENY_REV syntax %s");
1146 fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1147 *buf ? trim_version(buf) : "0");
1151 get_distrib (inFile);
1152 get_libc_version (inFile);
1153 get_ld_version(inFile);
1155 get_gcc_incdir(inFile);
1156 #if defined (sun) && defined(SVR4)
1157 get_sun_compiler_versions (inFile);
1161 static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
1163 memset(&osvi, 0, sizeof(OSVERSIONINFO));
1164 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1165 GetVersionEx (&osvi);
1167 fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
1168 os_names[osvi.dwPlatformId]);
1170 fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
1171 fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
1172 fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
1173 osvi.dwBuildNumber & 0xFFFF);
1179 cppit(imakefile, template, masterc, outfd, outfname)
1188 haveImakefileC = TRUE;
1189 inFile = fopen(masterc, "w");
1191 LogFatal("Cannot open %s for output.", masterc);
1192 if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1193 define_os_defaults(inFile) ||
1194 optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1195 optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1196 fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1197 fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1198 fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1199 optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1200 optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1203 LogFatal("Cannot write to %s.", masterc);
1207 doit(outfd, cpp, cpp_argv);
1208 CleanCppOutput(outfd, outfname);
1214 doit(NULL, make_argv[0], make_argv);
1218 CleanCppInput(imakefile)
1221 FILE *outFile = NULL;
1223 char *buf, /* buffer for file content */
1224 *pbuf, /* walking pointer to buf */
1225 *punwritten, /* pointer to unwritten portion of buf */
1226 *ptoken, /* pointer to # token */
1227 *pend, /* pointer to end of # token */
1228 savec; /* temporary character holder */
1233 * grab the entire file.
1235 if (!(inFile = fopen(imakefile, "r")))
1236 LogFatal("Cannot open %s for input.", imakefile);
1237 if (fstat(fileno(inFile), &st) < 0)
1238 LogFatal("Cannot stat %s for size.", imakefile);
1239 buf = Emalloc((int)st.st_size+3);
1240 count = fread(buf + 2, 1, st.st_size, inFile);
1241 if (count == 0 && st.st_size != 0)
1242 LogFatal("Cannot read %s:", imakefile);
1246 buf[count + 2] = '\0';
1248 punwritten = pbuf = buf + 2;
1250 /* for compatibility, replace make comments for cpp */
1251 if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1253 while (*ptoken == ' ' || *ptoken == '\t')
1256 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1260 if (strcmp(ptoken, "define") &&
1261 strcmp(ptoken, "if") &&
1262 strcmp(ptoken, "ifdef") &&
1263 strcmp(ptoken, "ifndef") &&
1264 strcmp(ptoken, "include") &&
1265 strcmp(ptoken, "line") &&
1266 strcmp(ptoken, "else") &&
1267 strcmp(ptoken, "elif") &&
1268 strcmp(ptoken, "endif") &&
1269 strcmp(ptoken, "error") &&
1270 strcmp(ptoken, "pragma") &&
1271 strcmp(ptoken, "undef")) {
1272 if (outFile == NULL) {
1273 tmpImakefile = Strdup(tmpImakefile);
1274 (void) mktemp(tmpImakefile);
1275 outFile = fopen(tmpImakefile, "w");
1276 if (outFile == NULL)
1277 LogFatal("Cannot open %s for write.",
1280 writetmpfile(outFile, punwritten, pbuf-punwritten,
1282 if (ptoken > pbuf + 1)
1283 writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1285 writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1286 punwritten = pbuf + 1;
1293 writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1295 return tmpImakefile;
1302 CleanCppOutput(tmpfd, tmpfname)
1309 while(input = ReadLine(tmpfd, tmpfname)) {
1310 if (isempty(input)) {
1316 KludgeOutputLine(&input);
1317 writetmpfile(tmpfd, input, strlen(input), tmpfname);
1319 writetmpfile(tmpfd, "\n", 1, tmpfname);
1322 #ifdef NFS_STDOUT_BUG
1324 * On some systems, NFS seems to leave a large number of nulls at
1325 * the end of the file. Ralph Swick says that this kludge makes the
1328 ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1333 * Determine if a line has nothing in it. As a side effect, we trim white
1334 * space from the end of the line. Cpp magic cookies are also thrown away.
1335 * "XCOMM" token is transformed to "#".
1339 register char *line;
1341 register char *pend;
1344 * Check for lines of the form
1353 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1354 pend[3] == 'e' && pend[4] == ' ')
1356 if (isdigit(*pend)) {
1359 } while (isdigit(*pend));
1360 if (*pend == '\n' || *pend == '\0')
1362 if (*pend++ == ' ' && *pend == '"')
1368 for (pend = line; *pend; pend++) {
1369 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1370 pend[3] == 'M' && pend[4] == 'M' &&
1371 (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1372 (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1375 strcpy(pend+1, pend+5);
1377 #ifdef MAGIC_MAKE_VARS
1378 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1384 if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1385 pend[7] >= '0' && pend[7] <= '9')
1388 sprintf(varbuf, "%0.4d", xvariable);
1389 strncpy(pend+4, varbuf, 4);
1390 xvariables[i] = xvariable;
1391 xvariable = (xvariable + 1) % 10000;
1393 else if (pend[4] == 'u' && pend[5] == 's' &&
1394 pend[6] == 'e' && pend[7] >= '0' &&
1398 sprintf(varbuf, "%0.4d", xvariables[i]);
1399 strncpy(pend+4, varbuf, 4);
1405 while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1407 return (*line == '\0');
1412 ReadLine(tmpfd, tmpfname)
1416 static boolean initialized = FALSE;
1417 static char *buf, *pline, *end;
1418 register char *p1, *p2;
1420 if (! initialized) {
1431 if (fstat(fileno(tmpfd), &st) < 0)
1432 LogFatal("cannot stat %s for size", tmpMakefile);
1433 pline = buf = Emalloc((int)st.st_size+1);
1434 total_red = fread(buf, 1, st.st_size, tmpfd);
1435 if (total_red == 0 && st.st_size != 0)
1436 LogFatal("cannot read %s", tmpMakefile);
1437 end = buf + total_red;
1440 #if defined(SYSV) || defined(WIN32)
1441 tmpfd = freopen(tmpfname, "w+", tmpfd);
1443 if (! tmpfd) /* if failed try again */
1444 tmpfd = freopen(tmpfname, "w+", fp);
1447 LogFatal("cannot reopen %s\n", tmpfname);
1449 ftruncate(fileno(tmpfd), (off_t) 0);
1452 fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1453 fprintf (tmpfd, "# %s\n",
1454 "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
1457 for (p1 = pline; p1 < end; p1++) {
1458 if (*p1 == '@' && *(p1+1) == '@'
1459 /* ignore ClearCase version-extended pathnames */
1460 && !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/'))
1463 p1++; /* skip over second @ */
1466 else if (*p1 == '\n') { /* real EOL */
1468 if (p1 > pline && p1[-1] == '\r')
1477 * return NULL at the end of the file.
1479 p2 = (pline == p1 ? NULL : pline);
1485 writetmpfile(fd, buf, cnt, fname)
1491 if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1492 LogFatal("Cannot write to %s.", fname);
1501 if ((p = malloc(size)) == NULL)
1502 LogFatalI("Cannot allocate %d bytes", size);
1506 #ifdef FIXUP_CPP_WHITESPACE
1508 KludgeOutputLine(pline)
1512 char quotechar = '\0';
1515 case '#': /*Comment - ignore*/
1517 case '\t': /*Already tabbed - ignore it*/
1519 case ' ': /*May need a tab*/
1521 # ifdef INLINE_SYNTAX
1522 if (*p == '<' && p[1] == '<') { /* inline file close */
1529 * The following cases should not be treated as beginning of
1531 * variable := name (GNU make)
1532 * variable = .*:.* (':' should be allowed as value)
1533 * sed 's:/a:/b:' (: used in quoted values)
1537 if (quotechar == '\\' ||
1562 # ifdef REMOVE_CPP_LEADSPACE
1563 if (!InRule && **pline == ' ') {
1564 while (**pline == ' ')
1569 # ifdef INLINE_SYNTAX
1571 if (p[1] == '<') /* inline file start */
1578 while (**pline == ' ')
1585 if (InRule && **pline == ' ')
1596 #endif /* FIXUP_CPP_WHITESPACE */
1602 register char *new = Emalloc(strlen(cp) + 1);