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 # ifndef _POSIX_SOURCE
166 # define _POSIX_SOURCE
169 #include <sys/types.h>
172 # include <sys/file.h>
176 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
179 # define _POSIX_SOURCE
181 # undef _POSIX_SOURCE
183 #include <sys/stat.h>
185 # ifdef _POSIX_SOURCE
186 # include <sys/wait.h>
188 # define _POSIX_SOURCE
189 # include <sys/wait.h>
190 # undef _POSIX_SOURCE
192 # define waitCode(w) WEXITSTATUS(w)
193 # define waitSig(w) WTERMSIG(w)
194 typedef int waitType;
195 #else /* X_NOT_POSIX */
197 # define waitCode(w) (((w) >> 8) & 0x7f)
198 # define waitSig(w) ((w) & 0xff)
199 typedef int waitType;
201 # include <sys/wait.h>
202 # define waitCode(w) ((w).w_T.w_Retcode)
203 # define waitSig(w) ((w).w_T.w_Termsig)
204 typedef union wait waitType;
207 # define WIFSIGNALED(w) waitSig(w)
210 # define WIFEXITED(w) waitCode(w)
212 #endif /* X_NOT_POSIX */
213 #ifndef X_NOT_STDC_ENV
216 char *malloc(), *realloc();
219 #ifdef X_NOT_STDC_ENV
220 extern char *getenv();
223 #ifdef X_NOT_STDC_ENV
226 #include <sys/utsname.h>
229 # define SYS_NMLN _SYS_NMLN
231 # define SYS_NMLN 257
238 * is strstr() in <strings.h> on X_NOT_STDC_ENV?
239 * are there any X_NOT_STDC_ENV machines left in the world?
243 #include "imakemdep.h"
246 * This define of strerror is copied from (and should be identical to)
247 * Xos.h, which we don't want to include here for bootstrapping reasons.
249 #if defined(X_NOT_STDC_ENV) || (defined(sun) && !defined(SVR4))
251 extern char *sys_errlist[];
253 # define strerror(n) \
254 (((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
261 #ifdef FIXUP_CPP_WHITESPACE
262 static int InRule = FALSE;
263 # ifdef INLINE_SYNTAX
264 static int InInline = 0;
267 #ifdef MAGIC_MAKE_VARS
268 static int xvariable = 0;
269 static int xvariables[10];
273 * Some versions of cpp reduce all tabs in macro expansion to a single
274 * space. In addition, the escaped newline may be replaced with a
275 * space instead of being deleted. Blech.
277 #ifdef FIXUP_CPP_WHITESPACE
278 static void KludgeOutputLine(char **pline);
279 static void KludgeResetRule(void);
281 # define KludgeOutputLine(arg)
282 # define KludgeResetRule()
285 typedef unsigned char boolean;
289 # define DEFAULT_CC "cc"
294 # define DEFAULT_CPP CPP_PROGRAM
296 # define DEFAULT_CPP "/lib/cpp"
301 static char *cpp = NULL;
303 static char *tmpMakefile = "/tmp/Imf.XXXXXX";
304 static char *tmpImakefile = "/tmp/IIf.XXXXXX";
305 static char *make_argv[ ARGUMENTS ] = {"make"};
307 static int make_argindex;
308 static int cpp_argindex;
309 static char *Imakefile = NULL;
310 static char *Makefile = "Makefile";
311 static char *Template = "Imake.tmpl";
312 static char *ImakefileC = "Imakefile.c";
313 static boolean haveImakefileC = FALSE;
314 static char *cleanedImakefile = NULL;
315 static char *program;
316 static boolean verbose = FALSE;
317 static boolean show = TRUE;
319 static char *FindImakefile(char *);
320 static char *ReadLine(FILE *, const char *);
321 static char *CleanCppInput(char *);
322 static char *Strdup(const char *);
323 static char *Emalloc(int);
324 static void LogFatal(const char *, ...);
325 static void LogMsg(const char *, ...);
326 static void Log(const char *, va_list);
328 static void showit(FILE *);
329 static void wrapup(void);
331 #ifdef SIGNALRETURNSINT
337 static void init(void);
338 static void AddMakeArg(char *);
339 static void AddCppArg(char *);
340 static void SetOpts(int, char **);
341 static void showargs(char **);
342 static void CheckImakefileC(const char *);
343 static boolean optional_include(FILE *, const char *, const char *);
344 static void doit(FILE *, const char *, char **);
345 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
346 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
347 static void parse_utsname(struct utsname *, const char *, char *, const char *);
349 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
350 static const char *trim_version(const char *);
353 static void get_distrib(FILE *);
354 static void get_libc_version(FILE *);
355 static void get_ld_version(FILE *);
357 #if defined(sun) && defined(__SVR4)
358 static char *get_full_path(const char *program);
359 static int get_sun_compiler_version(const char *fspec, const char *product,
360 int *cmajor, int *cminor);
361 static void get_sun_compiler_versions(FILE *);
363 static void get_gcc_incdir(FILE *);
364 static boolean define_os_defaults(FILE *);
365 static void cppit(const char *i, const char *, const char *, FILE *, const char *);
366 static void makeit(void);
367 static void CleanCppOutput(FILE *, const char *);
368 static boolean isempty(char *);
369 static void writetmpfile(FILE *, const char *, int, const char *);
372 main(int argc, char *argv[])
375 char makeMacro[ BUFSIZ ];
376 char makefileMacro[ BUFSIZ ];
382 Imakefile = FindImakefile(Imakefile);
383 CheckImakefileC(ImakefileC);
385 tmpMakefile = Makefile;
387 tmpMakefile = Strdup(tmpMakefile);
388 int ret = mkstemp(tmpMakefile);
392 AddMakeArg( tmpMakefile );
393 snprintf(makeMacro, BUFSIZ, "MAKE=%s", program);
394 AddMakeArg( makeMacro );
395 snprintf(makefileMacro, BUFSIZ, "MAKEFILE=%s", Imakefile);
396 AddMakeArg( makefileMacro );
398 if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
399 LogFatal("Cannot create temporary file %s.", tmpMakefile);
401 cleanedImakefile = CleanCppInput(Imakefile);
402 cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
405 if (Makefile == NULL)
420 while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
421 writetmpfile(stdout, buf, red, "stdout");
423 LogFatal("Cannot read %s.", tmpMakefile);
429 if (tmpMakefile != Makefile)
431 if (cleanedImakefile && cleanedImakefile != Imakefile)
432 unlink(cleanedImakefile);
438 #ifdef SIGNALRETURNSINT
446 LogFatal("Signal %d.", sig);
450 * Initialize some variables.
458 while (make_argv[ make_argindex ] != NULL)
461 while (cpp_argv[ cpp_argindex ] != NULL)
465 * See if the standard include directory is different than
466 * the default. Or if cpp is not the default. Or if the make
467 * found by the PATH variable is not the default.
469 if ((p = getenv("IMAKEINCLUDE"))) {
470 if (*p != '-' || *(p+1) != 'I')
471 LogFatal("Environment var IMAKEINCLUDE %s must begin with -I");
479 if ((p = getenv("IMAKECPP")))
481 if ((p = getenv("IMAKEMAKE")))
484 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
485 signal(SIGINT, catch);
489 AddMakeArg(char *arg)
492 if (make_argindex >= ARGUMENTS-1)
493 LogFatal("Out of internal storage.");
494 make_argv[ make_argindex++ ] = arg;
495 make_argv[ make_argindex ] = NULL;
502 if (cpp_argindex >= ARGUMENTS-1)
503 LogFatal("Out of internal storage.");
504 cpp_argv[ cpp_argindex++ ] = arg;
505 cpp_argv[ cpp_argindex ] = NULL;
509 SetOpts(int argc, char **argv)
513 * Now gather the arguments for make
515 for(argc--, argv++; argc; argc--, argv++) {
517 * We intercept these flags.
519 if (argv[0][0] == '-') {
520 if (argv[0][1] == 'D') {
522 } else if (argv[0][1] == 'I') {
524 } else if (argv[0][1] == 'f') {
526 Imakefile = argv[0]+2;
530 LogFatal("No description arg after -f flag");
533 } else if (argv[0][1] == 's') {
535 Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
540 LogFatal("No description arg after -s flag");
541 Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
545 } else if (argv[0][1] == 'e') {
546 Makefile = (argv[0][2] ? argv[0]+2 : NULL);
548 } else if (argv[0][1] == 'T') {
550 Template = argv[0]+2;
554 LogFatal("No description arg after -T flag");
557 } else if (argv[0][1] == 'C') {
559 ImakefileC = argv[0]+2;
563 LogFatal("No imakeCfile arg after -C flag");
564 ImakefileC = argv[0];
566 } else if (argv[0][1] == 'v') {
584 AddCppArg(ImakefileC);
588 FindImakefile(char *Imakefile)
591 if (access(Imakefile, R_OK) < 0)
592 LogFatal("Cannot find %s.", Imakefile);
594 if (access("Imakefile", R_OK) < 0)
595 if (access("imakefile", R_OK) < 0)
596 LogFatal("No description file.");
598 Imakefile = "imakefile";
600 Imakefile = "Imakefile";
606 LogFatal(const char *s, ...)
608 static boolean entered = FALSE;
620 fprintf(stderr, "Stop.\n");
628 LogMsg(const char *s, ...)
638 Log(const char *s, va_list args)
640 int error_number = errno;
643 fprintf(stderr, "%s: ", program);
644 fprintf(stderr, "%s\n", strerror(error_number));
646 fprintf(stderr, "%s: ", program);
647 vfprintf(stderr, s, args);
648 fprintf(stderr, "\n");
652 showargs(char **argv)
654 for (; *argv; argv++)
655 fprintf(stderr, "%s ", *argv);
656 fprintf(stderr, "\n");
659 #define ImakefileCHeader "/* imake - temporary file */"
662 CheckImakefileC(const char *masterc)
667 if (access(masterc, F_OK) == 0) {
668 inFile = fopen(masterc, "r");
670 LogFatal("Refuse to overwrite: %s", masterc);
671 if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
672 strncmp(mkcbuf, ImakefileCHeader,
673 sizeof(ImakefileCHeader)-1)))
676 LogFatal("Refuse to overwrite: %s", masterc);
682 #define LocalDefineFmt "#define %s \"%s\"\n"
683 #define IncludeFmt "#include %s\n"
684 #define ImakeDefSym "INCLUDE_IMAKEFILE"
685 #define ImakeTmplSym "IMAKE_TEMPLATE"
686 #define OverrideWarning "Warning: local file \"%s\" overrides global macros."
689 optional_include(FILE *inFile, const char *defsym, const char *fname)
692 if (access(fname, R_OK) == 0) {
694 LogMsg(OverrideWarning, fname);
695 return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
696 fprintf(inFile, IncludeFmt, defsym) < 0);
702 doit(FILE *outfd, const char *cmd, char **argv)
708 * Fork and exec the command.
712 LogFatal("Cannot fork.");
713 if (pid) { /* parent... simply wait */
714 while (wait(&status) > 0) {
716 if (WIFSIGNALED(status))
717 LogFatal("Signal %d.", waitSig(status));
718 if (WIFEXITED(status) && waitCode(status))
719 LogFatal("Exit code %d.", waitCode(status));
722 else { /* child... dup and exec cmd */
726 dup2(fileno(outfd), 1);
728 LogFatal("Cannot exec %s.", cmd);
732 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
733 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
735 parse_utsname(struct utsname *name, const char *fmt, char *result, const char *msg)
737 char buf[SYS_NMLN * 5 + 1];
741 /* Assemble all the pieces into a buffer. */
742 for (arg = 0; fmt[arg] != ' '; arg++)
744 /* Our buffer is only guaranteed to hold 5 arguments. */
753 strncpy(ptr, name->sysname, SYS_NMLN);
760 strncpy(ptr, name->nodename, SYS_NMLN);
767 strncpy(ptr, name->release, SYS_NMLN);
774 strncpy(ptr, name->version, SYS_NMLN);
781 strncpy(ptr, name->machine, SYS_NMLN);
790 /* Just in case... */
791 if (strlen(buf) >= sizeof(buf))
792 LogFatal("Buffer overflow parsing uname.");
794 /* Parse the buffer. The sscanf() return value is rarely correct. */
796 int ret = sscanf(buf, fmt + arg + 1, result);
800 /* Trim leading 0's and periods from version names. The 0's cause
801 the number to be interpreted as octal numbers. Some version strings
802 have the potential for different numbers of .'s in them.
805 #if (defined(DEFAULT_OS_MAJOR_REV) || defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
807 trim_version(const char *p)
810 if (p != 0 && *p != '\0')
812 while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
823 get_distrib(FILE *inFile)
827 static char* yast = "/sbin/yast";
828 static char* redhat = "/etc/redhat-release";
830 fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
831 fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
832 fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
833 fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
834 fprintf (inFile, "%s\n", "#define LinuxDebian 4");
835 fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
836 fprintf (inFile, "%s\n", "#define LinuxKheops 6");
837 fprintf (inFile, "%s\n", "#define LinuxPro 7");
838 fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
839 fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
840 fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
841 fprintf (inFile, "%s\n", "#define LinuxWare 11");
842 fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
844 if (lstat (yast, &sb) == 0) {
845 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
848 if (lstat (redhat, &sb) == 0) {
849 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
852 /* what's the definitive way to tell what any particular distribution is? */
854 fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
855 /* would like to know what version of the distribution it is */
858 static const char libc_c[]=
859 "#include <stdio.h>\n"
860 "#include <ctype.h>\n"
863 "#pragma weak gnu_get_libc_version\n"
864 "#pragma weak __libc_version\n"
865 "#pragma weak __linux_C_lib_version\n"
867 "asm (\".weak gnu_get_libc_version\");\n"
868 "asm (\".weak __libc_version\");\n"
869 "asm (\".weak __linux_C_lib_version\");\n"
872 "extern const char * gnu_get_libc_version (void);\n"
873 "extern const char * __linux_C_lib_version;\n"
874 "extern const char __libc_version [];\n"
879 " int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
881 " if (((&__linux_C_lib_version != 0)\n"
882 " && ((&__libc_version != 0) || (gnu_get_libc_version != 0)))\n"
883 " || (!(&__linux_C_lib_version != 0) && !(&__libc_version != 0)\n"
884 " && !(gnu_get_libc_version != 0)))\n"
892 " const char * ptr;\n"
893 " int glibcmajor = 0;\n"
895 " if (gnu_get_libc_version != 0)\n"
897 " ptr = gnu_get_libc_version ();\n"
900 " else if (&__libc_version != 0)\n"
902 " ptr = __libc_version;\n"
906 " ptr = __linux_C_lib_version;\n"
908 " while (!isdigit (*ptr))\n"
911 " sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
912 " libcmajor += glibcmajor;\n"
915 " printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
916 " printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
917 " printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
923 #define libc32path "/usr/lib/libc.so"
924 #define libc64path "/usr/lib64/libc.so"
927 get_libc_version(FILE *inFile)
933 int libcmajor, libcminor, libcteeny;
937 * If we are on a 64-bit Linux system and we see /usr/lib64/libc.so,
938 * we should use it. Otherwise go with /usr/lib/libc.so. It is entirely
939 * possible that someone will be running a 32-bit userland on a 64-bit
942 if (uname(&u) == -1) {
943 fprintf(stderr, "%s (%d): %s\n", __func__, __LINE__, strerror(errno));
947 if (!strcmp(u.sysname, "Linux") &&
948 (!strcmp(u.machine, "x86_64"))) {
949 if (!lstat (libc64path, &sb) && S_ISREG(sb.st_mode)) {
954 if (libcso == NULL) {
958 if (lstat (libcso, &sb) == 0) {
959 if (S_ISLNK (sb.st_mode)) {
961 * /usr/lib/libc.so is a symlink -- this is libc 5.x
962 * we can do this the quick way
964 if (readlink (libcso, buf, PATH_MAX) >= 0) {
965 for (ptr = buf; *ptr && !isdigit (*ptr); ptr++);
966 int ret = sscanf (ptr, "%d.%d.%d", &libcmajor, &libcminor, &libcteeny);
968 fprintf(inFile, "#define DefaultLinuxCLibMajorVersion %d\n", libcmajor);
969 fprintf(inFile, "#define DefaultLinuxCLibMinorVersion %d\n", libcminor);
970 fprintf(inFile, "#define DefaultLinuxCLibTeenyVersion %d\n", libcteeny);
974 * /usr/lib/libc.so is NOT a symlink -- this is libc 6.x / glibc 2.x
975 * now we have to figure this out the hard way.
980 const char *format = "%s -o %s -x c -";
985 memset(aout, '\0', PATH_MAX);
987 if (!lstat(getenv("TMPDIR"), &sb) && S_ISDIR(sb.st_mode))
988 strncpy(aout, getenv("TMPDIR"), PATH_MAX - 1);
989 #ifdef P_tmpdir /* defined by XPG and XOPEN, but don't assume we have it */
990 else if (!lstat(P_tmpdir, &sb) && S_ISDIR(sb.st_mode))
991 strncpy(aout, P_tmpdir, PATH_MAX - 1);
993 else if (!lstat("/tmp", &sb) && S_ISDIR(sb.st_mode))
994 strncpy(aout, "/tmp", PATH_MAX - 1);
998 strncat(aout, "/imaketmp.XXXXXX", PATH_MAX - 1);
1000 if ((fd = mkstemp(aout)) == -1)
1003 if (close(fd) == -1)
1009 len = strlen (aout) + strlen (format) + strlen (cc);
1010 if (len < 128) len = 128;
1011 command = alloca (len);
1013 if (snprintf (command , len, format, cc, aout) == len)
1016 fp = popen (command, "w");
1017 if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0 || pclose (fp) != 0)
1020 fp = popen (aout, "r");
1024 while (fgets (command, len, fp))
1025 fprintf (inFile, "%s", command);
1036 get_ld_version(FILE *inFile)
1038 FILE* ldprog = popen ("ld -v", "r");
1040 int ldmajor, ldminor;
1045 } while (c != EOF && !isdigit (c));
1047 int ret = fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
1049 fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
1050 ldmajor * 10 + ldminor);
1057 #define PATH_MAX 1024
1060 #if defined(sun) && defined(__SVR4)
1063 get_full_path(const char *program)
1069 buf = calloc(1, PATH_MAX);
1070 asprintf(&cmd, "command -v %s", program);
1072 if ((proc = popen (cmd, "r")) != NULL)
1073 fgets (buf, PATH_MAX, proc);
1077 return strtok (buf, "\n"); /* strip newline */
1081 get_sun_compiler_version(const char *fspec, const char *product,
1082 int *cmajor, int *cminor)
1092 if (lstat (fspec, &sb) != 0)
1095 strncpy (cmd, fspec, PATH_MAX);
1096 strlcpy (vendor, product, 4);
1098 if (strcmp (vendor, "Sun") == 0)
1099 strncat (cmd, " -V 2>&1", 8);
1100 else if (strcmp (vendor, "Gnu") == 0)
1101 strncat (cmd, " --version 2>&1", 15);
1105 if ((ccproc = popen (cmd, "r")) != NULL) {
1106 if (fgets (buf, PATH_MAX, ccproc) != NULL) {
1107 for (vptr = buf; !isdigit(*vptr) && *vptr != NULL; vptr++);
1108 if (*vptr == NULL) {
1112 ret = sscanf (vptr, "%d.%d", cmajor, cminor);
1124 get_sun_compiler_versions(FILE *inFile)
1126 static const char *compilers[][2] =
1127 {{"SunProC", "/opt/solarisstudio/bin/cc"},
1128 {"SunProCplusplus", "/opt/solarisstudio/bin/CC"},
1130 {"GnuCplusplus", "g++"}};
1135 for (i = 0; i < sizeof compilers / sizeof compilers[0]; i++) {
1136 const char *product = compilers[i][0];
1137 char *fspec = get_full_path (compilers[i][1]);
1139 ret = get_sun_compiler_version (fspec, product, &cmajor, &cminor);
1144 "#define Default%sCompilerMajorVersion %d\n",
1148 "#define Default%sCompilerMinorVersion %d\n",
1151 } else if (ret == EINVAL) {
1152 printf ("Failed to detect version of compiler: %s\n", product);
1163 get_gcc_incdir(FILE *inFile)
1165 static char* gcc_path[] = {
1167 "/usr/bin/cc", /* for Linux PostIncDir */
1172 "/usr/local/bin/gcc",
1182 memset(buf, 0, PATH_MAX);
1183 for (i = 0; i < sizeof gcc_path / sizeof gcc_path[0]; i++) {
1185 gcc_path[i] = get_full_path (gcc_path[i]);
1187 if (lstat (gcc_path[i], &sb) == 0) {
1191 strncpy (cmd, gcc_path[i], PATH_MAX - 1 );
1192 strncat (cmd, " --print-libgcc-file-name", PATH_MAX - 1);
1193 if ((gccproc = popen (cmd, "r")) != NULL) {
1194 if (fgets (buf, PATH_MAX - 1, gccproc) != NULL) {
1195 ptr = strstr (buf, "libgcc.a");
1196 if (ptr) strncpy (ptr, "include", 8);
1198 (void) pclose (gccproc);
1204 fprintf (inFile, "#define DefaultGccIncludeDir %s\n", buf);
1208 define_os_defaults(FILE *inFile)
1210 #if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
1211 defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
1212 struct utsname name;
1213 char buf[SYS_NMLN * 5 + 1];
1215 /* Obtain the system information. */
1216 if (uname(&name) < 0)
1217 LogFatal("Cannot invoke uname");
1219 # ifdef DEFAULT_OS_NAME
1220 parse_utsname(&name, DEFAULT_OS_NAME, buf,
1221 "Bad DEFAULT_OS_NAME syntax %s");
1223 fprintf(inFile, "#define DefaultOSName %s\n", buf);
1226 # ifdef DEFAULT_OS_MAJOR_REV
1227 parse_utsname(&name, DEFAULT_OS_MAJOR_REV, buf,
1228 "Bad DEFAULT_OS_MAJOR_REV syntax %s");
1229 fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
1230 *buf ? trim_version(buf) : "0");
1233 # ifdef DEFAULT_OS_MINOR_REV
1234 parse_utsname(&name, DEFAULT_OS_MINOR_REV, buf,
1235 "Bad DEFAULT_OS_MINOR_REV syntax %s");
1236 fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
1237 *buf ? trim_version(buf) : "0");
1240 # ifdef DEFAULT_OS_TEENY_REV
1241 parse_utsname(&name, DEFAULT_OS_TEENY_REV, buf,
1242 "Bad DEFAULT_OS_TEENY_REV syntax %s");
1243 fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
1244 *buf ? trim_version(buf) : "0");
1248 get_distrib (inFile);
1249 get_libc_version (inFile);
1250 get_ld_version(inFile);
1252 get_gcc_incdir(inFile);
1253 #if defined (sun) && defined(SVR4)
1254 get_sun_compiler_versions (inFile);
1260 cppit(const char *imakefile, const char *template, const char *masterc, FILE *outfd, const char *outfname)
1264 haveImakefileC = TRUE;
1265 inFile = fopen(masterc, "w");
1267 LogFatal("Cannot open %s for output.", masterc);
1268 if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
1269 define_os_defaults(inFile) ||
1270 optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
1271 optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
1272 fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
1273 fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
1274 fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
1275 optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
1276 optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
1279 LogFatal("Cannot write to %s.", masterc);
1283 doit(outfd, cpp, cpp_argv);
1284 CleanCppOutput(outfd, outfname);
1290 doit(NULL, make_argv[0], make_argv);
1294 CleanCppInput(char *imakefile)
1296 FILE *outFile = NULL;
1298 char *buf, /* buffer for file content */
1299 *pbuf, /* walking pointer to buf */
1300 *punwritten, /* pointer to unwritten portion of buf */
1301 *ptoken, /* pointer to # token */
1302 *pend, /* pointer to end of # token */
1303 savec; /* temporary character holder */
1308 * grab the entire file.
1310 if (!(inFile = fopen(imakefile, "r")))
1311 LogFatal("Cannot open %s for input.", imakefile);
1312 if (fstat(fileno(inFile), &st) < 0)
1313 LogFatal("Cannot stat %s for size.", imakefile);
1314 buf = Emalloc((int)st.st_size+3);
1315 count = fread(buf + 2, 1, st.st_size, inFile);
1316 if (count == 0 && st.st_size != 0)
1317 LogFatal("Cannot read %s:", imakefile);
1321 buf[count + 2] = '\0';
1323 punwritten = pbuf = buf + 2;
1325 /* for compatibility, replace make comments for cpp */
1326 if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
1328 while (*ptoken == ' ' || *ptoken == '\t')
1331 while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
1335 if (strcmp(ptoken, "define") &&
1336 strcmp(ptoken, "if") &&
1337 strcmp(ptoken, "ifdef") &&
1338 strcmp(ptoken, "ifndef") &&
1339 strcmp(ptoken, "include") &&
1340 strcmp(ptoken, "line") &&
1341 strcmp(ptoken, "else") &&
1342 strcmp(ptoken, "elif") &&
1343 strcmp(ptoken, "endif") &&
1344 strcmp(ptoken, "error") &&
1345 strcmp(ptoken, "pragma") &&
1346 strcmp(ptoken, "undef")) {
1347 if (outFile == NULL) {
1348 tmpImakefile = Strdup(tmpImakefile);
1349 int ret = mkstemp(tmpImakefile);
1351 outFile = fopen(tmpImakefile, "w");
1352 if (outFile == NULL)
1353 LogFatal("Cannot open %s for write.",
1356 writetmpfile(outFile, punwritten, pbuf-punwritten,
1358 if (ptoken > pbuf + 1)
1359 writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
1361 writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
1362 punwritten = pbuf + 1;
1369 writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
1371 return tmpImakefile;
1378 CleanCppOutput(FILE *tmpfd, const char *tmpfname)
1383 while ((input = ReadLine(tmpfd, tmpfname))) {
1384 if (isempty(input)) {
1390 KludgeOutputLine(&input);
1391 writetmpfile(tmpfd, input, strlen(input), tmpfname);
1393 writetmpfile(tmpfd, "\n", 1, tmpfname);
1396 #ifdef NFS_STDOUT_BUG
1398 * On some systems, NFS seems to leave a large number of nulls at
1399 * the end of the file. Ralph Swick says that this kludge makes the
1402 ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
1407 * Determine if a line has nothing in it. As a side effect, we trim white
1408 * space from the end of the line. Cpp magic cookies are also thrown away.
1409 * "XCOMM" token is transformed to "#".
1417 * Check for lines of the form
1426 if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
1427 pend[3] == 'e' && pend[4] == ' ')
1429 if (isdigit((int)*pend)) {
1432 } while (isdigit((int)*pend));
1433 if (*pend == '\n' || *pend == '\0')
1435 if (*pend++ == ' ' && *pend == '"')
1441 for (pend = line; *pend; pend++) {
1442 if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
1443 pend[3] == 'M' && pend[4] == 'M' &&
1444 (pend == line || pend[-1] == ' ' || pend[-1] == '\t') &&
1445 (pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\0'))
1448 strncpy(pend+1, pend+5, 1);
1450 #ifdef MAGIC_MAKE_VARS
1451 if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
1457 if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
1458 pend[7] >= '0' && pend[7] <= '9')
1461 snprintf(varbuf, 5, "%0.4d", xvariable);
1462 strncpy(pend+4, varbuf, 4);
1463 xvariables[i] = xvariable;
1464 xvariable = (xvariable + 1) % 10000;
1466 else if (pend[4] == 'u' && pend[5] == 's' &&
1467 pend[6] == 'e' && pend[7] >= '0' &&
1471 snprintf(varbuf, 5, "%0.4d", xvariables[i]);
1472 strncpy(pend+4, varbuf, 4);
1478 while (--pend >= line && (*pend == ' ' || *pend == '\t')) ;
1480 return (*line == '\0');
1485 ReadLine(FILE *tmpfd, const char *tmpfname)
1487 static boolean initialized = FALSE;
1488 static char *buf, *pline, *end;
1491 if (! initialized) {
1499 if (fstat(fileno(tmpfd), &st) < 0)
1500 LogFatal("cannot stat %s for size", tmpMakefile);
1501 pline = buf = Emalloc((int)st.st_size+1);
1502 total_red = fread(buf, 1, st.st_size, tmpfd);
1503 if (total_red == 0 && st.st_size != 0)
1504 LogFatal("cannot read %s", tmpMakefile);
1505 end = buf + total_red;
1509 tmpfd = freopen(tmpfname, "w+", tmpfd);
1511 LogFatal("cannot reopen %s.", tmpfname);
1513 int ret = ftruncate(fileno(tmpfd), (off_t) 0);
1517 fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
1518 fprintf (tmpfd, "# %s\n",
1519 "$TOG: imake.c /main/104 1998/03/24 12:45:15 kaleb $");
1522 for (p1 = pline; p1 < end; p1++) {
1523 if (*p1 == '@' && *(p1+1) == '@'
1524 /* ignore ClearCase version-extended pathnames */
1525 && !(p1 != pline && !isspace((int)*(p1-1))
1529 p1++; /* skip over second @ */
1532 else if (*p1 == '\n') { /* real EOL */
1539 * return NULL at the end of the file.
1541 p2 = (pline == p1 ? NULL : pline);
1547 writetmpfile(FILE *fd, const char *buf, int cnt, const char *fname)
1549 if (fwrite(buf, sizeof(char), cnt, fd) == -1)
1550 LogFatal("Cannot write to %s.", fname);
1558 if ((p = malloc(size)) == NULL)
1559 LogFatal("Cannot allocate %d bytes.", size);
1563 #ifdef FIXUP_CPP_WHITESPACE
1565 KludgeOutputLine(char **pline)
1568 char quotechar = '\0';
1571 case '#': /*Comment - ignore*/
1573 case '\t': /*Already tabbed - ignore it*/
1575 case ' ': /*May need a tab*/
1577 # ifdef INLINE_SYNTAX
1578 if (*p == '<' && p[1] == '<') { /* inline file close */
1585 * The following cases should not be treated as beginning of
1587 * variable := name (GNU make)
1588 * variable = .*:.* (':' should be allowed as value)
1589 * sed 's:/a:/b:' (: used in quoted values)
1593 if (quotechar == '\\' ||
1615 # ifdef REMOVE_CPP_LEADSPACE
1616 if (!InRule && **pline == ' ') {
1617 while (**pline == ' ')
1622 # ifdef INLINE_SYNTAX
1624 if (p[1] == '<') /* inline file start */
1631 while (**pline == ' ')
1638 if (InRule && **pline == ' ')
1645 KludgeResetRule(void)
1649 #endif /* FIXUP_CPP_WHITESPACE */
1652 Strdup(const char *cp)
1654 char *new = Emalloc(strlen(cp) + 1);
1656 memcpy(new, cp, strlen(cp) + 1);