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?
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 mkstemp(tmpMakefile);
411 AddMakeArg( tmpMakefile );
412 sprintf(makeMacro, "MAKE=%s", program);
413 AddMakeArg( makeMacro );
414 sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
415 AddMakeArg( makefileMacro );
417 if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
418 LogFatal("Cannot create temporary file %s.", tmpMakefile);
420 cleanedImakefile = CleanCppInput(Imakefile);
421 cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
424 if (Makefile == NULL)
439 while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
440 writetmpfile(stdout, buf, red, "stdout");
442 LogFatal("Cannot read %s.", tmpMakefile);
448 if (tmpMakefile != Makefile)
450 if (cleanedImakefile && cleanedImakefile != Imakefile)
451 unlink(cleanedImakefile);
457 #ifdef SIGNALRETURNSINT
465 LogFatal("Signal %d.", sig);
469 * Initialize some variables.
477 while (make_argv[ make_argindex ] != NULL)
480 while (cpp_argv[ cpp_argindex ] != NULL)
484 * See if the standard include directory is different than
485 * the default. Or if cpp is not the default. Or if the make
486 * found by the PATH variable is not the default.
488 if ((p = getenv("IMAKEINCLUDE"))) {
489 if (*p != '-' || *(p+1) != 'I')
490 LogFatal("Environment var IMAKEINCLUDE %s must begin with -I");
498 if ((p = getenv("IMAKECPP")))
500 if ((p = getenv("IMAKEMAKE")))
503 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
504 signal(SIGINT, catch);
508 AddMakeArg(char *arg)
511 if (make_argindex >= ARGUMENTS-1)
512 LogFatal("Out of internal storage.");
513 make_argv[ make_argindex++ ] = arg;
514 make_argv[ make_argindex ] = NULL;
521 if (cpp_argindex >= ARGUMENTS-1)
522 LogFatal("Out of internal storage.");
523 cpp_argv[ cpp_argindex++ ] = arg;
524 cpp_argv[ cpp_argindex ] = NULL;
528 SetOpts(int argc, char **argv)
532 * Now gather the arguments for make
534 for(argc--, argv++; argc; argc--, argv++) {
536 * We intercept these flags.
538 if (argv[0][0] == '-') {
539 if (argv[0][1] == 'D') {
541 } else if (argv[0][1] == 'I') {
543 } else if (argv[0][1] == 'f') {
545 Imakefile = argv[0]+2;
549 LogFatal("No description arg after -f flag");
552 } else if (argv[0][1] == 's') {
554 Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
559 LogFatal("No description arg after -s flag");
560 Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
564 } else if (argv[0][1] == 'e') {
565 Makefile = (argv[0][2] ? argv[0]+2 : NULL);
567 } else if (argv[0][1] == 'T') {
569 Template = argv[0]+2;
573 LogFatal("No description arg after -T flag");
576 } else if (argv[0][1] == 'C') {
578 ImakefileC = argv[0]+2;
582 LogFatal("No imakeCfile arg after -C flag");
583 ImakefileC = argv[0];
585 } else if (argv[0][1] == 'v') {
603 AddCppArg(ImakefileC);
607 FindImakefile(char *Imakefile)
610 if (access(Imakefile, R_OK) < 0)
611 LogFatal("Cannot find %s.", Imakefile);
613 if (access("Imakefile", R_OK) < 0)
614 if (access("imakefile", R_OK) < 0)
615 LogFatal("No description file.");
617 Imakefile = "imakefile";
619 Imakefile = "Imakefile";
625 LogFatal(const char *s, ...)
627 static boolean entered = FALSE;
639 fprintf(stderr, "Stop.\n");
647 LogMsg(const char *s, ...)
657 Log(const char *s, va_list args)
659 int error_number = errno;
662 fprintf(stderr, "%s: ", program);
663 fprintf(stderr, "%s\n", strerror(error_number));
665 fprintf(stderr, "%s: ", program);
666 vfprintf(stderr, s, args);
667 fprintf(stderr, "\n");
671 showargs(char **argv)
673 for (; *argv; argv++)
674 fprintf(stderr, "%s ", *argv);
675 fprintf(stderr, "\n");
678 #define ImakefileCHeader "/* imake - temporary file */"
681 CheckImakefileC(const char *masterc)
686 if (access(masterc, F_OK) == 0) {
687 inFile = fopen(masterc, "r");
689 LogFatal("Refuse to overwrite: %s", masterc);
690 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
691 strncmp(mkcbuf, ImakefileCHeader,
692 sizeof(ImakefileCHeader)-1)))
695 LogFatal("Refuse to overwrite: %s", masterc);
701 #define LocalDefineFmt "#define %s \"%s\"\n"
702 #define IncludeFmt "#include %s\n"
703 #define ImakeDefSym "INCLUDE_IMAKEFILE"
704 #define ImakeTmplSym "IMAKE_TEMPLATE"
705 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
708 optional_include(FILE *inFile, const char *defsym, const char *fname)
711 if (access(fname, R_OK) == 0) {
712 LogMsg(OverrideWarning, fname);
713 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
714 fprintf(inFile, IncludeFmt, defsym) < 0);
720 doit(FILE *outfd, const char *cmd, char **argv)
726 * Fork and exec the command.
730 dup2(fileno(outfd), 1);
731 status = _spawnvp(_P_WAIT, cmd, argv);
733 LogFatal("Cannot spawn %s.", cmd);
735 LogFatal("Exit code %d.", status);
739 LogFatal("Cannot fork.");
740 if (pid) { /* parent... simply wait */
741 while (wait(&status) > 0) {
743 if (WIFSIGNALED(status))
744 LogFatal("Signal %d.", waitSig(status));
745 if (WIFEXITED(status) && waitCode(status))
746 LogFatal("Exit code %d.", waitCode(status));
749 else { /* child... dup and exec cmd */
753 dup2(fileno(outfd), 1);
755 LogFatal("Cannot exec %s.", cmd);
762 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
763 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
765 parse_utsname(struct utsname *name, const char *fmt, char *result, const char *msg)
767 char buf[SYS_NMLN * 5 + 1];
771 /* Assemble all the pieces into a buffer. */
772 for (arg = 0; fmt[arg] != ' '; arg++)
774 /* Our buffer is only guaranteed to hold 5 arguments. */
783 strcpy(ptr, name->sysname);
790 strcpy(ptr, name->nodename);
797 strcpy(ptr, name->release);
804 strcpy(ptr, name->version);
811 strcpy(ptr, name->machine);
820 /* Just in case... */
821 if (strlen(buf) >= sizeof(buf))
822 LogFatal("Buffer overflow parsing uname.");
824 /* Parse the buffer. The sscanf() return value is rarely correct. */
826 (void) sscanf(buf, fmt + arg + 1, result);
830 /* Trim leading 0's and periods from version names. The 0's cause
831 the number to be interpreted as octal numbers. Some version strings
832 have the potential for different numbers of .'s in them.
835 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
837 trim_version(const char *p)
840 if (p != 0 && *p != '\0')
842 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
853 get_distrib(FILE *inFile)
857 static char* yast = "/sbin/YaST";
858 static char* redhat = "/etc/redhat-release";
860 fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
861 fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
862 fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
863 fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
864 fprintf (inFile, "%s\n", "#define LinuxDebian 4");
865 fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
866 fprintf (inFile, "%s\n", "#define LinuxKheops 6");
867 fprintf (inFile, "%s\n", "#define LinuxPro 7");
868 fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
869 fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
870 fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
871 fprintf (inFile, "%s\n", "#define LinuxWare 11");
872 fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
874 if (lstat (yast, &sb) == 0) {
875 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
878 if (lstat (redhat, &sb) == 0) {
879 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
882 /* what's the definitive way to tell what any particular distribution is? */
884 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
885 /* would like to know what version of the distribution it is */
888 static const char libc_c[]=
889 "#include <stdio.h>\n"
890 "#include <ctype.h>\n"
893 "#pragma weak gnu_get_libc_version\n"
894 "#pragma weak __libc_version\n"
895 "#pragma weak __linux_C_lib_version\n"
897 "asm (\".weak gnu_get_libc_version\");\n"
898 "asm (\".weak __libc_version\");\n"
899 "asm (\".weak __linux_C_lib_version\");\n"
902 "extern const char * gnu_get_libc_version (void);\n"
903 "extern const char * __linux_C_lib_version;\n"
904 "extern const char __libc_version [];\n"
909 " int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
911 " if (((&__linux_C_lib_version != 0)\n"
912 " && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
913 " || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
914 " && !(gnu_get_libc_version != 0)))\n"
922 " const char * ptr;\n"
923 " int glibcmajor = 0;\n"
925 " if (gnu_get_libc_version != 0)\n"
927 " ptr = gnu_get_libc_version ();\n"
930 " else if (&__libc_version != 0)\n"
932 " ptr = __libc_version;\n"
936 " ptr = __linux_C_lib_version;\n"
938 " while (!isdigit (*ptr))\n"
941 " sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
942 " libcmajor += glibcmajor;\n"
945 " printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
946 " printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
947 " printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
954 get_libc_version(FILE *inFile)
960 int libcmajor, libcminor, libcteeny;
964 * If we are on a 64-bit Linux system and we see /usr/lib64/libc.so,
965 * we should use it. Otherwise go with /usr/lib/libc.so. It is entirely
966 * possible that someone will be running a 32-bit userland on a 64-bit
969 if (uname(&u) == -1) {
970 fprintf(stderr, "%s (%d): %s\n", __func__, __LINE__, strerror(errno));
974 if (!strcmp(u.sysname, "Linux") &&
975 (!strcmp(u.machine, "x86_64"))) {
976 if (!lstat ("/usr/lib64/libc.so", &sb) && S_ISREG(sb.st_mode)) {
977 libcso = strdup("/usr/lib64/libc.so");
981 if (libcso == NULL) {
982 libcso = strdup("/usr/lib/libc.so");
985 if (lstat (libcso, &sb) == 0) {
986 if (S_ISLNK (sb.st_mode)) {
988 * /usr/lib/libc.so is a symlink -- this is libc 5.x
989 * we can do this the quick way
991 if (readlink (libcso, buf, PATH_MAX) >= 0) {
992 for (ptr = buf; *ptr && !isdigit (*ptr); ptr++);
993 (void) sscanf (ptr, "%d.%d.%d", &libcmajor, &libcminor, &libcteeny);
994 fprintf(inFile, "#define DefaultLinuxCLibMajorVersion %d\n", libcmajor);
995 fprintf(inFile, "#define DefaultLinuxCLibMinorVersion %d\n", libcminor);
996 fprintf(inFile, "#define DefaultLinuxCLibTeenyVersion %d\n", libcteeny);
1000 * /usr/lib/libc.so is NOT a symlink -- this is libc 6.x / glibc 2.x
1001 * now we have to figure this out the hard way.
1003 char *aout = tmpnam (NULL);
1005 const char *format = "%s -o %s -x c -";
1013 len = strlen (aout) + strlen (format) + strlen (cc);
1014 if (len < 128) len = 128;
1015 command = alloca (len);
1017 if (snprintf (command , len, format, cc, aout) == len)
1020 fp = popen (command, "w");
1021 if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 || pclose (fp) != 0)
1024 fp = popen (aout, "r");
1028 while (fgets (command, len, fp))
1029 fprintf (inFile, command);
1042 get_ld_version(FILE *inFile)
1044 FILE* ldprog = popen ("ld -v", "r");
1046 int ldmajor, ldminor;
1051 } while (c != EOF && !isdigit (c));
1053 (void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
1054 fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
1055 ldmajor * 10 + ldminor);
1062 #define PATH_MAX 1024
1065 #if defined(sun) && defined(__SVR4)
1067 get_sun_compiler_versions(FILE *inFile)
1071 static char* sunpro_cc = "/opt/SUNWspro/bin/cc";
1072 static char* sunpro_CC = "/opt/SUNWspro/bin/CC";
1078 if (lstat (sunpro_cc, &sb) == 0) {
1079 strcpy (cmd, sunpro_cc);
1080 strcat (cmd, " -V 2>&1");
1081 if ((ccproc = popen (cmd, "r")) != NULL) {
1082 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1083 vptr = strrchr (buf, 'C');
1084 for (; !isdigit(*vptr); vptr++);
1085 (void) sscanf (vptr, "%d.%d", &cmajor, &cminor);
1087 "#define DefaultSunProCCompilerMajorVersion %d\n",
1090 "#define DefaultSunProCCompilerMinorVersion %d\n",
1093 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1097 if (lstat (sunpro_CC, &sb) == 0) {
1098 strcpy (cmd, sunpro_CC);
1099 strcat (cmd, " -V 2>&1");
1100 if ((ccproc = popen (cmd, "r")) != NULL) {
1101 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1102 vptr = strrchr (buf, 'C');
1103 for (; !isdigit(*vptr); vptr++);
1104 (void) sscanf (vptr, "%d.%d", &cmajor, &cminor);
1106 "#define DefaultSunProCplusplusCompilerMajorVersion %d\n",
1109 "#define DefaultSunProCplusplusCompilerMinorVersion %d\n",
1112 while (fgets (buf, PATH_MAX, ccproc) != NULL) {};
1120 get_gcc_incdir(FILE *inFile)
1122 static char* gcc_path[] = {
1124 "/usr/bin/cc", /* for Linux PostIncDir */
1126 "/usr/local/bin/gcc",
1137 for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
1138 if (lstat (gcc_path[i], &sb) == 0) {
1139 strcpy (cmd, gcc_path[i]);
1140 strcat (cmd, " --print-libgcc-file-name");
1141 if ((gccproc = popen (cmd, "r")) != NULL) {
1142 if (fgets (buf, PATH_MAX, gccproc) != NULL) {
1143 ptr = strstr (buf, "libgcc.a");
1144 if (ptr) strcpy (ptr, "include");
1146 (void) pclose (gccproc);
1152 fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1156 define_os_defaults(FILE *inFile)
1159 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1160 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
1161 struct utsname name;
1162 char buf[SYS_NMLN * 5 + 1];
1164 /* Obtain the system information. */
1165 if (uname(&name) < 0)
1166 LogFatal("Cannot invoke uname");
1168 # ifdef DEFAULT_OS_NAME
1169 parse_utsname(&name, DEFAULT_OS_NAME, buf,
1170 "Bad DEFAULT_OS_NAME syntax %s");
1172 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1175 # ifdef DEFAULT_OS_MAJOR_REV
1176 parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1177 "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1178 fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1179 *buf ? trim_version(buf) : "0");
1182 # ifdef DEFAULT_OS_MINOR_REV
1183 parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1184 "Bad DEFAULT_OS_MINOR_REV syntax %s");
1185 fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1186 *buf ? trim_version(buf) : "0");
1189 # ifdef DEFAULT_OS_TEENY_REV
1190 parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1191 "Bad DEFAULT_OS_TEENY_REV syntax %s");
1192 fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1193 *buf ? trim_version(buf) : "0");
1197 get_distrib (inFile);
1198 get_libc_version (inFile);
1199 get_ld_version(inFile);
1201 get_gcc_incdir(inFile);
1202 #if defined (sun) && defined(SVR4)
1203 get_sun_compiler_versions (inFile);
1207 static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
1209 memset(&osvi, 0, sizeof(OSVERSIONINFO));
1210 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1211 GetVersionEx (&osvi);
1213 fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
1214 os_names[osvi.dwPlatformId]);
1216 fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
1217 fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
1218 fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
1219 osvi.dwBuildNumber & 0xFFFF);
1225 cppit(const char *imakefile, const char *template, const char *masterc, FILE *outfd, const char *outfname)
1229 haveImakefileC = TRUE;
1230 inFile = fopen(masterc, "w");
1232 LogFatal("Cannot open %s for output.", masterc);
1233 if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1234 define_os_defaults(inFile) ||
1235 optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1236 optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1237 fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1238 fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1239 fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1240 optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1241 optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1244 LogFatal("Cannot write to %s.", masterc);
1248 doit(outfd, cpp, cpp_argv);
1249 CleanCppOutput(outfd, outfname);
1255 doit(NULL, make_argv[0], make_argv);
1259 CleanCppInput(char *imakefile)
1261 FILE *outFile = NULL;
1263 char *buf, /* buffer for file content */
1264 *pbuf, /* walking pointer to buf */
1265 *punwritten, /* pointer to unwritten portion of buf */
1266 *ptoken, /* pointer to # token */
1267 *pend, /* pointer to end of # token */
1268 savec; /* temporary character holder */
1273 * grab the entire file.
1275 if (!(inFile = fopen(imakefile, "r")))
1276 LogFatal("Cannot open %s for input.", imakefile);
1277 if (fstat(fileno(inFile), &st) < 0)
1278 LogFatal("Cannot stat %s for size.", imakefile);
1279 buf = Emalloc((int)st.st_size+3);
1280 count = fread(buf + 2, 1, st.st_size, inFile);
1281 if (count == 0 && st.st_size != 0)
1282 LogFatal("Cannot read %s:", imakefile);
1286 buf[count + 2] = '\0';
1288 punwritten = pbuf = buf + 2;
1290 /* for compatibility, replace make comments for cpp */
1291 if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1293 while (*ptoken == ' ' || *ptoken == '\t')
1296 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1300 if (strcmp(ptoken, "define") &&
1301 strcmp(ptoken, "if") &&
1302 strcmp(ptoken, "ifdef") &&
1303 strcmp(ptoken, "ifndef") &&
1304 strcmp(ptoken, "include") &&
1305 strcmp(ptoken, "line") &&
1306 strcmp(ptoken, "else") &&
1307 strcmp(ptoken, "elif") &&
1308 strcmp(ptoken, "endif") &&
1309 strcmp(ptoken, "error") &&
1310 strcmp(ptoken, "pragma") &&
1311 strcmp(ptoken, "undef")) {
1312 if (outFile == NULL) {
1313 tmpImakefile = Strdup(tmpImakefile);
1314 mkstemp(tmpImakefile);
1315 outFile = fopen(tmpImakefile, "w");
1316 if (outFile == NULL)
1317 LogFatal("Cannot open %s for write.",
1320 writetmpfile(outFile, punwritten, pbuf-punwritten,
1322 if (ptoken > pbuf + 1)
1323 writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1325 writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1326 punwritten = pbuf + 1;
1333 writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1335 return tmpImakefile;
1342 CleanCppOutput(FILE *tmpfd, const char *tmpfname)
1347 while ((input = ReadLine(tmpfd, tmpfname))) {
1348 if (isempty(input)) {
1354 KludgeOutputLine(&input);
1355 writetmpfile(tmpfd, input, strlen(input), tmpfname);
1357 writetmpfile(tmpfd, "\n", 1, tmpfname);
1360 #ifdef NFS_STDOUT_BUG
1362 * On some systems, NFS seems to leave a large number of nulls at
1363 * the end of the file. Ralph Swick says that this kludge makes the
1366 ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1371 * Determine if a line has nothing in it. As a side effect, we trim white
1372 * space from the end of the line. Cpp magic cookies are also thrown away.
1373 * "XCOMM" token is transformed to "#".
1381 * Check for lines of the form
1390 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1391 pend[3] == 'e' && pend[4] == ' ')
1393 if (isdigit(*pend)) {
1396 } while (isdigit(*pend));
1397 if (*pend == '\n' || *pend == '\0')
1399 if (*pend++ == ' ' && *pend == '"')
1405 for (pend = line; *pend; pend++) {
1406 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1407 pend[3] == 'M' && pend[4] == 'M' &&
1408 (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1409 (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1412 strcpy(pend+1, pend+5);
1414 #ifdef MAGIC_MAKE_VARS
1415 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1421 if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1422 pend[7] >= '0' && pend[7] <= '9')
1425 sprintf(varbuf, "%0.4d", xvariable);
1426 strncpy(pend+4, varbuf, 4);
1427 xvariables[i] = xvariable;
1428 xvariable = (xvariable + 1) % 10000;
1430 else if (pend[4] == 'u' && pend[5] == 's' &&
1431 pend[6] == 'e' && pend[7] >= '0' &&
1435 sprintf(varbuf, "%0.4d", xvariables[i]);
1436 strncpy(pend+4, varbuf, 4);
1442 while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1444 return (*line == '\0');
1449 ReadLine(FILE *tmpfd, const char *tmpfname)
1451 static boolean initialized = FALSE;
1452 static char *buf, *pline, *end;
1455 if (! initialized) {
1466 if (fstat(fileno(tmpfd), &st) < 0)
1467 LogFatal("cannot stat %s for size", tmpMakefile);
1468 pline = buf = Emalloc((int)st.st_size+1);
1469 total_red = fread(buf, 1, st.st_size, tmpfd);
1470 if (total_red == 0 && st.st_size != 0)
1471 LogFatal("cannot read %s", tmpMakefile);
1472 end = buf + total_red;
1475 #if defined(SYSV) || defined(WIN32)
1476 tmpfd = freopen(tmpfname, "w+", tmpfd);
1478 if (! tmpfd) /* if failed try again */
1479 tmpfd = freopen(tmpfname, "w+", fp);
1482 LogFatal("cannot reopen %s.", tmpfname);
1484 ftruncate(fileno(tmpfd), (off_t) 0);
1487 fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1488 fprintf (tmpfd, "# %s\n",
1489 "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
1492 for (p1 = pline; p1 < end; p1++) {
1493 if (*p1 == '@' && *(p1+1) == '@'
1494 /* ignore ClearCase version-extended pathnames */
1495 && !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/'))
1498 p1++; /* skip over second @ */
1501 else if (*p1 == '\n') { /* real EOL */
1503 if (p1 > pline && p1[-1] == '\r')
1512 * return NULL at the end of the file.
1514 p2 = (pline == p1 ? NULL : pline);
1520 writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
1522 if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1523 LogFatal("Cannot write to %s.", fname);
1531 if ((p = malloc(size)) == NULL)
1532 LogFatal("Cannot allocate %d bytes.", size);
1536 #ifdef FIXUP_CPP_WHITESPACE
1538 KludgeOutputLine(char **pline)
1541 char quotechar = '\0';
1544 case '#': /*Comment - ignore*/
1546 case '\t': /*Already tabbed - ignore it*/
1548 case ' ': /*May need a tab*/
1550 # ifdef INLINE_SYNTAX
1551 if (*p == '<' && p[1] == '<') { /* inline file close */
1558 * The following cases should not be treated as beginning of
1560 * variable := name (GNU make)
1561 * variable = .*:.* (':' should be allowed as value)
1562 * sed 's:/a:/b:' (: used in quoted values)
1566 if (quotechar == '\\' ||
1591 # ifdef REMOVE_CPP_LEADSPACE
1592 if (!InRule && **pline == ' ') {
1593 while (**pline == ' ')
1598 # ifdef INLINE_SYNTAX
1600 if (p[1] == '<') /* inline file start */
1607 while (**pline == ' ')
1614 if (InRule && **pline == ' ')
1621 KludgeResetRule(void)
1625 #endif /* FIXUP_CPP_WHITESPACE */
1628 Strdup(const char *cp)
1630 char *new = Emalloc(strlen(cp) + 1);