2215 lines
54 KiB
C
2215 lines
54 KiB
C
|
|
/***************************************************************************
|
|
* *
|
|
* Porting Note *
|
|
* *
|
|
* Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will *
|
|
* be passed to the template file. *
|
|
* *
|
|
***************************************************************************/
|
|
/* $XFree86: xc/config/imake/imake.c,v 3.63tsi Exp $ */
|
|
|
|
/*
|
|
*
|
|
Copyright (c) 1985, 1986, 1987, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
*
|
|
* Original Author:
|
|
* Todd Brunhoff
|
|
* Tektronix, inc.
|
|
* While a guest engineer at Project Athena, MIT
|
|
*
|
|
* imake: the include-make program.
|
|
*
|
|
* Usage: imake [-Idir] [-Ddefine] [-T template] [-f imakefile ] [-C Imakefile.c ] [-s] [-e] [-v] [make flags]
|
|
*
|
|
* Imake takes a template file (Imake.tmpl) and a prototype (Imakefile)
|
|
* and runs cpp on them producing a Makefile. It then optionally runs make
|
|
* on the Makefile.
|
|
* Options:
|
|
* -D define. Same as cpp -D argument.
|
|
* -U undefine. Same as cpp -U argument.
|
|
* -W warning. Same as cpp -W argument.
|
|
* -I Include directory. Same as cpp -I argument.
|
|
* -T template. Designate a template other
|
|
* than Imake.tmpl
|
|
* -f specify the Imakefile file
|
|
* -C specify the name to use instead of Imakefile.c
|
|
* -s[F] show. Show the produced makefile on the standard
|
|
* output. Make is not run is this case. If a file
|
|
* argument is provided, the output is placed there.
|
|
* -e[F] execute instead of show; optionally name Makefile F
|
|
* -v verbose. Show the make command line executed.
|
|
*
|
|
* Environment variables:
|
|
*
|
|
* IMAKEINCLUDE Include directory to use in addition to "."
|
|
* IMAKECPP Cpp to use instead of /lib/cpp
|
|
* IMAKEMAKE make program to use other than what is
|
|
* found by searching the $PATH variable.
|
|
* Other features:
|
|
* imake reads the entire cpp output into memory and then scans it
|
|
* for occurences of "@@". If it encounters them, it replaces it with
|
|
* a newline. It also trims any trailing white space on output lines
|
|
* (because make gets upset at them). This helps when cpp expands
|
|
* multi-line macros but you want them to appear on multiple lines.
|
|
* It also changes occurences of "XCOMM" to "#", to avoid problems
|
|
* with treating commands as invalid preprocessor commands.
|
|
*
|
|
* The macros MAKEFILE and MAKE are provided as macros
|
|
* to make. MAKEFILE is set to imake's makefile (not the constructed,
|
|
* preprocessed one) and MAKE is set to argv[0], i.e. the name of
|
|
* the imake program.
|
|
*
|
|
* Theory of operation:
|
|
* 1. Determine the name of the imakefile from the command line (-f)
|
|
* or from the content of the current directory (Imakefile or imakefile).
|
|
* Call this <imakefile>. This gets added to the arguments for
|
|
* make as MAKEFILE=<imakefile>.
|
|
* 2. Determine the name of the template from the command line (-T)
|
|
* or the default, Imake.tmpl. Call this <template>
|
|
* 3. Determine the name of the imakeCfile from the command line (-C)
|
|
* or the default, Imakefile.c. Call this <imakeCfile>
|
|
* 4. Store lines of input into <imakeCfile>:
|
|
* - A c-style comment header (see ImakefileCHeader below), used
|
|
* to recognize temporary files generated by imake.
|
|
* - If DEFAULT_OS_NAME is defined, format the utsname struct and
|
|
* call the result <defaultOsName>. Add:
|
|
* #define DefaultOSName <defaultOsName>
|
|
* - If DEFAULT_OS_MAJOR_REV is defined, format the utsname struct
|
|
* and call the result <defaultOsMajorVersion>. Add:
|
|
* #define DefaultOSMajorVersion <defaultOsMajorVersion>
|
|
* - If DEFAULT_OS_MINOR_REV is defined, format the utsname struct
|
|
* and call the result <defaultOsMinorVersion>. Add:
|
|
* #define DefaultOSMinorVersion <defaultOsMinorVersion>
|
|
* - If DEFAULT_OS_TEENY_REV is defined, format the utsname struct
|
|
* and call the result <defaultOsTeenyVersion>. Add:
|
|
* #define DefaultOSTeenyVersion <defaultOsTeenyVersion>
|
|
* - If DEFAULT_MACHINE_ARCITECTURE is defined, format the utsname struct
|
|
* and define the corresponding macro. (For example on the amiga,
|
|
* this will define amiga in addition to m68k).
|
|
* - If the file "localdefines" is readable in the current
|
|
* directory, print a warning message to stderr and add:
|
|
* #define IMAKE_LOCAL_DEFINES "localdefines"
|
|
* #include IMAKE_LOCAL_DEFINES
|
|
* - If the file "admindefines" is readable in the current
|
|
* directory, print a warning message to stderr and add:
|
|
* #define IMAKE_ADMIN_DEFINES "admindefines"
|
|
* #include IMAKE_ADMIN_DEFINES
|
|
* - The following lines:
|
|
* #define INCLUDE_IMAKEFILE < <imakefile> >
|
|
* #define IMAKE_TEMPLATE " <template> "
|
|
* #include IMAKE_TEMPLATE
|
|
* - If the file "adminmacros" is readable in the current
|
|
* directory, print a warning message to stderr and add:
|
|
* #define IMAKE_ADMIN_MACROS "adminmacros"
|
|
* #include IMAKE_ADMIN_MACROS
|
|
* - If the file "localmacros" is readable in the current
|
|
* directory, print a warning message to stderr and add:
|
|
* #define IMAKE_LOCAL_MACROS "localmacros"
|
|
* #include IMAKE_LOCAL_MACROS
|
|
* 5. Start up cpp and provide it with this file.
|
|
* Note that the define for INCLUDE_IMAKEFILE is intended for
|
|
* use in the template file. This implies that the imake is
|
|
* useless unless the template file contains at least the line
|
|
* #include INCLUDE_IMAKEFILE
|
|
* 6. Gather the output from cpp, and clean it up, expanding @@ to
|
|
* newlines, stripping trailing white space, cpp control lines,
|
|
* and extra blank lines, and changing XCOMM to #. This cleaned
|
|
* output is placed in a new file, default "Makefile", but can
|
|
* be specified with -s or -e options.
|
|
* 7. Optionally start up make on the resulting file.
|
|
*
|
|
* The design of the template makefile should therefore be:
|
|
* <set global macros like CFLAGS, etc.>
|
|
* <include machine dependent additions>
|
|
* #include INCLUDE_IMAKEFILE
|
|
* <add any global targets like 'clean' and long dependencies>
|
|
*/
|
|
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
|
/* This needs to be before _POSIX_SOURCE gets defined */
|
|
# include <sys/param.h>
|
|
# include <sys/types.h>
|
|
# include <sys/sysctl.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#ifdef MONOLITH
|
|
# include "Xosdefs.h"
|
|
#else
|
|
# include <X11/Xosdefs.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#ifdef WIN32
|
|
# include "Xw32defs.h"
|
|
#endif
|
|
#if 0
|
|
#ifndef X_NOT_POSIX
|
|
# ifndef _POSIX_SOURCE
|
|
# define _POSIX_SOURCE
|
|
# endif
|
|
#endif
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#ifdef X_NOT_POSIX
|
|
# ifndef WIN32
|
|
# include <sys/file.h>
|
|
# endif
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
#ifdef ISC
|
|
# include <unistd.h>
|
|
#endif
|
|
#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
|
|
# include <signal.h>
|
|
#else
|
|
# define _POSIX_SOURCE
|
|
# include <signal.h>
|
|
# undef _POSIX_SOURCE
|
|
#endif
|
|
#if !defined(SIGCHLD) && defined(SIGCLD)
|
|
# define SIGCHLD SIGCLD
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#ifndef X_NOT_POSIX
|
|
# ifdef _POSIX_SOURCE
|
|
# ifdef __SCO__
|
|
# include <sys/procset.h>
|
|
# include <sys/siginfo.h>
|
|
# endif
|
|
# include <sys/wait.h>
|
|
# else
|
|
# define _POSIX_SOURCE
|
|
# include <sys/wait.h>
|
|
# undef _POSIX_SOURCE
|
|
# endif
|
|
# define waitCode(w) WEXITSTATUS(w)
|
|
# define waitSig(w) WTERMSIG(w)
|
|
typedef int waitType;
|
|
#else /* X_NOT_POSIX */
|
|
# ifdef SYSV
|
|
# define waitCode(w) (((w) >> 8) & 0x7f)
|
|
# define waitSig(w) ((w) & 0xff)
|
|
typedef int waitType;
|
|
# else /* SYSV */
|
|
# ifdef WIN32
|
|
# include <process.h>
|
|
typedef int waitType;
|
|
# else
|
|
# include <sys/wait.h>
|
|
# define waitCode(w) ((w).w_T.w_Retcode)
|
|
# define waitSig(w) ((w).w_T.w_Termsig)
|
|
typedef union wait waitType;
|
|
# endif
|
|
# endif
|
|
# ifndef WIFSIGNALED
|
|
# define WIFSIGNALED(w) waitSig(w)
|
|
# endif
|
|
# ifndef WIFEXITED
|
|
# define WIFEXITED(w) waitCode(w)
|
|
# endif
|
|
#endif /* X_NOT_POSIX */
|
|
# include <stdlib.h>
|
|
#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */
|
|
char *malloc(), *realloc();
|
|
#endif /* macII */
|
|
#include <errno.h>
|
|
#ifdef __minix_vmd
|
|
#define USE_FREOPEN 1
|
|
#endif
|
|
|
|
#if !((defined(sun) && !defined(SVR4)) || defined(macII))
|
|
#define USE_STRERROR 1
|
|
#endif
|
|
#ifndef WIN32
|
|
#include <sys/utsname.h>
|
|
#else
|
|
#include <windows.h>
|
|
#endif
|
|
#ifndef SYS_NMLN
|
|
# ifdef _SYS_NMLN
|
|
# define SYS_NMLN _SYS_NMLN
|
|
# else
|
|
# define SYS_NMLN 257
|
|
# endif
|
|
#endif
|
|
#if defined(linux) || defined(__GNU__) || defined(__GLIBC__)
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#endif
|
|
#ifdef __QNX__
|
|
#include <unix.h>
|
|
#endif
|
|
|
|
/*
|
|
* This define of strerror is copied from (and should be identical to)
|
|
* Xos.h, which we don't want to include here for bootstrapping reasons.
|
|
*/
|
|
#ifndef USE_STRERROR
|
|
# ifndef strerror
|
|
extern char *sys_errlist[];
|
|
extern int sys_nerr;
|
|
# define strerror(n) \
|
|
(((n) >= 0 && (n) < sys_nerr) ? sys_errlist[n] : "unknown error")
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(__NetBSD__) /* see code clock in init() below */
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
|
|
#if !(defined(Lynx) || defined(__Lynx__) || (defined(SVR4) && !defined(sun))) && !defined (__CYGWIN__)
|
|
#define HAS_MKSTEMP
|
|
#endif
|
|
|
|
typedef unsigned char boolean;
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
# include "imakemdep.h"
|
|
#ifdef CROSSCOMPILE
|
|
# include "imakemdep_cpp.h"
|
|
#endif
|
|
|
|
#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
|
|
int InRule = FALSE;
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined INLINE_SYNTAX
|
|
int InInline = 0;
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS
|
|
int xvariable = 0;
|
|
int xvariables[10];
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
|
|
/*
|
|
* Some versions of cpp reduce all tabs in macro expansion to a single
|
|
* space. In addition, the escaped newline may be replaced with a
|
|
* space instead of being deleted. Blech.
|
|
*/
|
|
void KludgeOutputLine(char **), KludgeResetRule(void);
|
|
|
|
#ifndef CROSSCOMPILE
|
|
# ifdef USE_CC_E
|
|
# ifndef DEFAULT_CC
|
|
# define DEFAULT_CC "cc"
|
|
# endif
|
|
# else
|
|
# ifndef DEFAULT_CPP
|
|
# ifdef CPP_PROGRAM
|
|
# define DEFAULT_CPP CPP_PROGRAM
|
|
# else
|
|
# define DEFAULT_CPP "/lib/cpp"
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
char *cpp = NULL;
|
|
|
|
char *tmpMakefile = "/tmp/Imf.XXXXXX";
|
|
char *tmpImakefile = "/tmp/IIf.XXXXXX";
|
|
char *make_argv[ ARGUMENTS ] = {
|
|
#ifdef WIN32
|
|
"nmake"
|
|
#else
|
|
"make"
|
|
#endif
|
|
};
|
|
|
|
int make_argindex;
|
|
int cpp_argindex;
|
|
char *Imakefile = NULL;
|
|
char *Makefile = "Makefile";
|
|
char *Template = "Imake.tmpl";
|
|
char *ImakefileC = "Imakefile.c";
|
|
boolean haveImakefileC = FALSE;
|
|
char *cleanedImakefile = NULL;
|
|
char *program;
|
|
char *FindImakefile(char *Imakefile);
|
|
char *ReadLine(FILE *tmpfd, char *tmpfname);
|
|
char *CleanCppInput(char *imakefile);
|
|
char *Strdup(char *cp);
|
|
char *Emalloc(int size);
|
|
void LogFatalI(char *s, int i), LogFatal(char *x0, char *x1),
|
|
LogMsg(char *x0, char *x1);
|
|
|
|
void showit(FILE *fd);
|
|
void wrapup(void);
|
|
void init(void);
|
|
void AddMakeArg(char *arg);
|
|
void AddCppArg(char *arg);
|
|
#ifdef CROSSCOMPILE
|
|
char *CrossCompileCPP(void);
|
|
#endif
|
|
void SetOpts(int argc, char **argv);
|
|
void CheckImakefileC(char *masterc);
|
|
void cppit(char *imakefile, char *template, char *masterc,
|
|
FILE *outfd, char *outfname);
|
|
void makeit(void);
|
|
void CleanCppOutput(FILE *tmpfd, char *tmpfname);
|
|
boolean isempty(char *line);
|
|
void writetmpfile(FILE *fd, char *buf, int cnt, char *fname);
|
|
#ifdef SIGNALRETURNSINT
|
|
int catch(int sig);
|
|
#else
|
|
void catch(int sig);
|
|
#endif
|
|
void showargs(char **argv);
|
|
boolean optional_include(FILE *inFile, char *defsym, char *fname);
|
|
void doit(FILE *outfd, char *cmd, char **argv);
|
|
boolean define_os_defaults(FILE *inFile);
|
|
#ifdef CROSSCOMPILE
|
|
static void get_cross_compile_dir(FILE *inFile);
|
|
#endif
|
|
#ifdef CROSSCOMPILEDIR
|
|
char *CrossCompileDir = CROSSCOMPILEDIR;
|
|
#else
|
|
char *CrossCompileDir = "";
|
|
#endif
|
|
boolean CrossCompiling = FALSE;
|
|
|
|
|
|
|
|
boolean verbose = FALSE;
|
|
boolean show = TRUE;
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
FILE *tmpfd = NULL;
|
|
char makeMacro[ BUFSIZ ];
|
|
char makefileMacro[ BUFSIZ ];
|
|
int lenCrossCompileDir = 0;
|
|
|
|
program = argv[0];
|
|
init();
|
|
|
|
lenCrossCompileDir = strlen(CrossCompileDir);
|
|
if (lenCrossCompileDir) {
|
|
if (lenCrossCompileDir > (PATH_MAX - 20))
|
|
LogFatal("Cross compile directory path too long %s\n",
|
|
CrossCompileDir);
|
|
else
|
|
CrossCompiling = TRUE;
|
|
}
|
|
|
|
SetOpts(argc, argv);
|
|
Imakefile = FindImakefile(Imakefile);
|
|
CheckImakefileC(ImakefileC);
|
|
if (Makefile) {
|
|
tmpMakefile = Makefile;
|
|
if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
|
|
LogFatal("Cannot create temporary file %s.", tmpMakefile);
|
|
} else {
|
|
#ifdef HAS_MKSTEMP
|
|
int fd;
|
|
#endif
|
|
tmpMakefile = Strdup(tmpMakefile);
|
|
#ifndef HAS_MKSTEMP
|
|
if (mktemp(tmpMakefile) == NULL ||
|
|
(tmpfd = fopen(tmpMakefile, "w+")) == NULL) {
|
|
LogFatal("Cannot create temporary file %s.", tmpMakefile);
|
|
}
|
|
#else
|
|
fd = mkstemp(tmpMakefile);
|
|
if (fd == -1 || (tmpfd = fdopen(fd, "w+")) == NULL) {
|
|
if (fd != -1) {
|
|
unlink(tmpMakefile); close(fd);
|
|
}
|
|
LogFatal("Cannot create temporary file %s.", tmpMakefile);
|
|
}
|
|
#endif
|
|
}
|
|
AddMakeArg("-f");
|
|
AddMakeArg( tmpMakefile );
|
|
sprintf(makeMacro, "MAKE=%s", program);
|
|
AddMakeArg( makeMacro );
|
|
sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
|
|
AddMakeArg( makefileMacro );
|
|
|
|
cleanedImakefile = CleanCppInput(Imakefile);
|
|
cppit(cleanedImakefile, Template, ImakefileC, tmpfd, tmpMakefile);
|
|
|
|
if (show) {
|
|
if (Makefile == NULL)
|
|
showit(tmpfd);
|
|
} else
|
|
makeit();
|
|
wrapup();
|
|
exit(0);
|
|
}
|
|
|
|
void
|
|
showit(FILE *fd)
|
|
{
|
|
char buf[ BUFSIZ ];
|
|
int red;
|
|
|
|
fseek(fd, 0, 0);
|
|
while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
|
|
writetmpfile(stdout, buf, red, "stdout");
|
|
if (red < 0)
|
|
LogFatal("Cannot read %s.", tmpMakefile);
|
|
}
|
|
|
|
void
|
|
wrapup(void)
|
|
{
|
|
if (tmpMakefile != Makefile)
|
|
unlink(tmpMakefile);
|
|
if (cleanedImakefile && cleanedImakefile != Imakefile)
|
|
unlink(cleanedImakefile);
|
|
if (haveImakefileC)
|
|
unlink(ImakefileC);
|
|
}
|
|
|
|
#ifdef SIGNALRETURNSINT
|
|
int
|
|
#else
|
|
void
|
|
#endif
|
|
catch(int sig)
|
|
{
|
|
errno = 0;
|
|
LogFatalI("Signal %d.", sig);
|
|
}
|
|
|
|
/*
|
|
* Initialize some variables.
|
|
*/
|
|
void
|
|
init(void)
|
|
{
|
|
register char *p;
|
|
|
|
make_argindex=0;
|
|
while (make_argv[ make_argindex ] != NULL)
|
|
make_argindex++;
|
|
cpp_argindex = 0;
|
|
while (cpp_argv[ cpp_argindex ] != NULL)
|
|
cpp_argindex++;
|
|
|
|
#if defined CROSSCOMPILE
|
|
if (sys == netBSD)
|
|
if (CrossCompiling) {
|
|
LogFatal("fix imake to do crosscompiling for NetBSD\n","");
|
|
} else
|
|
#endif
|
|
#if defined(__NetBSD__) || defined CROSSCOMPILE
|
|
{
|
|
struct utsname uts;
|
|
static char argument[512];
|
|
|
|
/*
|
|
* Sharable imake configurations require a
|
|
* machine identifier.
|
|
*/
|
|
if (uname(&uts) != 0)
|
|
LogFatal("uname(3) failed; can't tell what %s",
|
|
"kind of machine you have.");
|
|
|
|
memset(argument, 0, sizeof(argument));
|
|
(void)snprintf(argument, sizeof(argument) - 1,
|
|
"-D__%s__", uts.machine);
|
|
|
|
AddCppArg(argument);
|
|
}
|
|
#endif /* __NetBSD__ */
|
|
|
|
/*
|
|
* See if the standard include directory is different than
|
|
* the default. Or if cpp is not the default. Or if the make
|
|
* found by the PATH variable is not the default.
|
|
*/
|
|
if ((p = getenv("IMAKEINCLUDE"))) {
|
|
if (*p != '-' || *(p+1) != 'I')
|
|
LogFatal("Environment var IMAKEINCLUDE %s",
|
|
"must begin with -I");
|
|
AddCppArg(p);
|
|
for (; *p; p++)
|
|
if (*p == ' ') {
|
|
*p++ = '\0';
|
|
AddCppArg(p);
|
|
}
|
|
}
|
|
if ((p = getenv("IMAKECPP")))
|
|
cpp = p;
|
|
if ((p = getenv("IMAKEMAKE")))
|
|
make_argv[0] = p;
|
|
|
|
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
|
signal(SIGINT, catch);
|
|
#ifdef SIGCHLD
|
|
signal(SIGCHLD, SIG_DFL);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
AddMakeArg(char *arg)
|
|
{
|
|
errno = 0;
|
|
if (make_argindex >= ARGUMENTS-1)
|
|
LogFatal("Out of internal storage.", "");
|
|
make_argv[ make_argindex++ ] = arg;
|
|
make_argv[ make_argindex ] = NULL;
|
|
}
|
|
|
|
void
|
|
AddCppArg(char *arg)
|
|
{
|
|
errno = 0;
|
|
if (cpp_argindex >= ARGUMENTS-1)
|
|
LogFatal("Out of internal storage.", "");
|
|
cpp_argv[ cpp_argindex++ ] = arg;
|
|
cpp_argv[ cpp_argindex ] = NULL;
|
|
}
|
|
|
|
void
|
|
SetOpts(int argc, char **argv)
|
|
{
|
|
|
|
errno = 0;
|
|
/*
|
|
* Now gather the arguments for make
|
|
*/
|
|
for(argc--, argv++; argc; argc--, argv++) {
|
|
/*
|
|
* We intercept these flags.
|
|
*/
|
|
if (argv[0][0] == '-') {
|
|
if (argv[0][1] == 'D') {
|
|
AddCppArg(argv[0]);
|
|
} else if (argv[0][1] == 'I') {
|
|
AddCppArg(argv[0]);
|
|
} else if (argv[0][1] == 'U') {
|
|
AddCppArg(argv[0]);
|
|
} else if (argv[0][1] == 'W') {
|
|
AddCppArg(argv[0]);
|
|
} else if (argv[0][1] == 'f') {
|
|
if (argv[0][2])
|
|
Imakefile = argv[0]+2;
|
|
else {
|
|
argc--, argv++;
|
|
if (! argc)
|
|
LogFatal("No description arg after -f flag", "");
|
|
Imakefile = argv[0];
|
|
}
|
|
} else if (argv[0][1] == 's') {
|
|
if (argv[0][2])
|
|
Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
|
|
NULL : argv[0]+2;
|
|
else {
|
|
argc--, argv++;
|
|
if (!argc)
|
|
LogFatal("No description arg after -s flag", "");
|
|
Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
|
|
NULL : argv[0];
|
|
}
|
|
show = TRUE;
|
|
} else if (argv[0][1] == 'e') {
|
|
Makefile = (argv[0][2] ? argv[0]+2 : NULL);
|
|
show = FALSE;
|
|
} else if (argv[0][1] == 'T') {
|
|
if (argv[0][2])
|
|
Template = argv[0]+2;
|
|
else {
|
|
argc--, argv++;
|
|
if (! argc)
|
|
LogFatal("No description arg after -T flag", "");
|
|
Template = argv[0];
|
|
}
|
|
} else if (argv[0][1] == 'C') {
|
|
if (argv[0][2])
|
|
ImakefileC = argv[0]+2;
|
|
else {
|
|
argc--, argv++;
|
|
if (! argc)
|
|
LogFatal("No imakeCfile arg after -C flag", "");
|
|
ImakefileC = argv[0];
|
|
}
|
|
} else if (argv[0][1] == 'v') {
|
|
verbose = TRUE;
|
|
} else
|
|
AddMakeArg(argv[0]);
|
|
} else
|
|
AddMakeArg(argv[0]);
|
|
}
|
|
|
|
#ifndef CROSSCOMPILE
|
|
# ifdef USE_CC_E
|
|
if (!cpp)
|
|
{
|
|
AddCppArg("-E");
|
|
#ifdef __GNUC__
|
|
if (verbose)
|
|
AddCppArg("-v");
|
|
#endif
|
|
cpp = DEFAULT_CC;
|
|
}
|
|
# else
|
|
if (!cpp)
|
|
cpp = DEFAULT_CPP;
|
|
# endif
|
|
#else
|
|
if (!cpp)
|
|
cpp = CrossCompileCPP();
|
|
#endif
|
|
|
|
cpp_argv[0] = cpp;
|
|
AddCppArg(ImakefileC);
|
|
}
|
|
|
|
char *
|
|
FindImakefile(char *Imakefile)
|
|
{
|
|
if (Imakefile) {
|
|
if (access(Imakefile, R_OK) < 0)
|
|
LogFatal("Cannot find %s.", Imakefile);
|
|
} else {
|
|
if (access("Imakefile", R_OK) < 0) {
|
|
if (access("imakefile", R_OK) < 0)
|
|
LogFatal("No description file.", "");
|
|
else
|
|
Imakefile = "imakefile";
|
|
} else
|
|
Imakefile = "Imakefile";
|
|
}
|
|
return(Imakefile);
|
|
}
|
|
|
|
void
|
|
LogFatalI(char *s, int i)
|
|
{
|
|
/*NOSTRICT*/
|
|
LogFatal(s, (char *)(long)i);
|
|
}
|
|
|
|
void
|
|
LogFatal(char *x0, char *x1)
|
|
{
|
|
static boolean entered = FALSE;
|
|
|
|
if (entered)
|
|
return;
|
|
entered = TRUE;
|
|
|
|
LogMsg(x0, x1);
|
|
fprintf(stderr, " Stop.\n");
|
|
wrapup();
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
LogMsg(char *x0, char *x1)
|
|
{
|
|
int error_number = errno;
|
|
|
|
if (error_number) {
|
|
fprintf(stderr, "%s: ", program);
|
|
fprintf(stderr, "%s\n", strerror(error_number));
|
|
}
|
|
fprintf(stderr, "%s: ", program);
|
|
fprintf(stderr, x0, x1);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
void
|
|
showargs(char **argv)
|
|
{
|
|
for (; *argv; argv++)
|
|
fprintf(stderr, "%s ", *argv);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
#define ImakefileCHeader "/* imake - temporary file */"
|
|
|
|
void
|
|
CheckImakefileC(char *masterc)
|
|
{
|
|
char mkcbuf[1024];
|
|
FILE *inFile;
|
|
|
|
if (access(masterc, F_OK) == 0) {
|
|
inFile = fopen(masterc, "r");
|
|
if (inFile == NULL)
|
|
LogFatal("Refuse to overwrite: %s", masterc);
|
|
if ((fgets(mkcbuf, sizeof(mkcbuf), inFile) &&
|
|
strncmp(mkcbuf, ImakefileCHeader,
|
|
sizeof(ImakefileCHeader)-1)))
|
|
{
|
|
fclose(inFile);
|
|
LogFatal("Refuse to overwrite: %s", masterc);
|
|
}
|
|
fclose(inFile);
|
|
}
|
|
}
|
|
|
|
#define LocalDefineFmt "#define %s \"%s\"\n"
|
|
#define IncludeFmt "#include %s\n"
|
|
#define ImakeDefSym "INCLUDE_IMAKEFILE"
|
|
#define ImakeTmplSym "IMAKE_TEMPLATE"
|
|
#define OverrideWarning "Warning: local file \"%s\" overrides global macros."
|
|
|
|
boolean
|
|
optional_include(FILE *inFile, char *defsym, char *fname)
|
|
{
|
|
errno = 0;
|
|
if (access(fname, R_OK) == 0) {
|
|
LogMsg(OverrideWarning, fname);
|
|
return (fprintf(inFile, LocalDefineFmt, defsym, fname) < 0 ||
|
|
fprintf(inFile, IncludeFmt, defsym) < 0);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
doit(FILE *outfd, char *cmd, char **argv)
|
|
{
|
|
int pid;
|
|
waitType status;
|
|
|
|
/*
|
|
* Fork and exec the command.
|
|
*/
|
|
#ifdef WIN32
|
|
if (outfd)
|
|
dup2(fileno(outfd), 1);
|
|
status = _spawnvp(_P_WAIT, cmd, argv);
|
|
if (status < 0)
|
|
LogFatal("Cannot spawn %s.", cmd);
|
|
if (status > 0)
|
|
LogFatalI("Exit code %d.", status);
|
|
#else
|
|
pid = fork();
|
|
if (pid < 0)
|
|
LogFatal("Cannot fork.", "");
|
|
if (pid) { /* parent... simply wait */
|
|
while (wait(&status) > 0) {
|
|
errno = 0;
|
|
if (WIFSIGNALED(status))
|
|
LogFatalI("Signal %d.", waitSig(status));
|
|
if (WIFEXITED(status) && waitCode(status))
|
|
LogFatalI("Exit code %d.", waitCode(status));
|
|
}
|
|
}
|
|
else { /* child... dup and exec cmd */
|
|
if (verbose)
|
|
showargs(argv);
|
|
if (outfd)
|
|
dup2(fileno(outfd), 1);
|
|
execvp(cmd, argv);
|
|
LogFatal("Cannot exec %s.", cmd);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined WIN32
|
|
static void
|
|
parse_utsname(struct utsname *name, char *fmt, char *result, char *msg)
|
|
{
|
|
char buf[SYS_NMLN * 5 + 1];
|
|
char *ptr = buf;
|
|
int arg;
|
|
|
|
if (!name)
|
|
LogFatal(msg,fmt);
|
|
|
|
/* Assemble all the pieces into a buffer. */
|
|
for (arg = 0; fmt[arg] != ' '; arg++)
|
|
{
|
|
/* Our buffer is only guaranteed to hold 5 arguments. */
|
|
if (arg >= 5)
|
|
LogFatal(msg, fmt);
|
|
|
|
switch (fmt[arg])
|
|
{
|
|
case 's':
|
|
if (arg > 0)
|
|
*ptr++ = ' ';
|
|
strcpy(ptr, name->sysname);
|
|
ptr += strlen(ptr);
|
|
break;
|
|
|
|
case 'n':
|
|
if (arg > 0)
|
|
*ptr++ = ' ';
|
|
strcpy(ptr, name->nodename);
|
|
ptr += strlen(ptr);
|
|
break;
|
|
|
|
case 'r':
|
|
if (arg > 0)
|
|
*ptr++ = ' ';
|
|
strcpy(ptr, name->release);
|
|
ptr += strlen(ptr);
|
|
break;
|
|
|
|
case 'v':
|
|
if (arg > 0)
|
|
*ptr++ = ' ';
|
|
strcpy(ptr, name->version);
|
|
ptr += strlen(ptr);
|
|
break;
|
|
|
|
case 'm':
|
|
if (arg > 0)
|
|
*ptr++ = ' ';
|
|
strcpy(ptr, name->machine);
|
|
ptr += strlen(ptr);
|
|
break;
|
|
|
|
default:
|
|
LogFatal(msg, fmt);
|
|
}
|
|
}
|
|
|
|
/* Just in case... */
|
|
if (strlen(buf) >= sizeof(buf))
|
|
LogFatal("Buffer overflow parsing uname.", "");
|
|
|
|
/* Parse the buffer. The sscanf() return value is rarely correct. */
|
|
*result = '\0';
|
|
(void) sscanf(buf, fmt + arg + 1, result);
|
|
}
|
|
|
|
/* Trim leading 0's and periods from version names. The 0's cause
|
|
the number to be interpreted as octal numbers. Some version strings
|
|
have the potential for different numbers of .'s in them.
|
|
*/
|
|
|
|
static char *
|
|
trim_version(char *p)
|
|
{
|
|
|
|
if (p != 0 && *p != '\0')
|
|
{
|
|
while ((*p == '0' || *p == '.') && *(p + 1) != '\0')
|
|
++p;
|
|
}
|
|
return (p);
|
|
}
|
|
#endif
|
|
|
|
#if defined(linux) || defined(__GLIBC__)
|
|
const char *libc_c=
|
|
"#include <stdio.h>\n"
|
|
"#include <ctype.h>\n"
|
|
"\n"
|
|
"#if 1\n"
|
|
"#pragma weak gnu_get_libc_version\n"
|
|
"#pragma weak __libc_version\n"
|
|
"#pragma weak __linux_C_lib_version\n"
|
|
"#endif\n"
|
|
"\n"
|
|
"extern const char * gnu_get_libc_version (void);\n"
|
|
"extern const char * __linux_C_lib_version;\n"
|
|
"extern const char __libc_version [];\n"
|
|
"\n"
|
|
"int\n"
|
|
"main ()\n"
|
|
"{\n"
|
|
" int libcmajor = 0, libcminor = 0, libcteeny = 0;\n"
|
|
" const char * ptr = NULL;\n"
|
|
" int glibcmajor = 0;\n"
|
|
"\n"
|
|
" if (gnu_get_libc_version != 0)\n"
|
|
" {\n"
|
|
" ptr = gnu_get_libc_version ();\n"
|
|
" glibcmajor = 4;\n"
|
|
" }\n"
|
|
" else if (&__libc_version != 0)\n"
|
|
" {\n"
|
|
" ptr = __libc_version;\n"
|
|
" glibcmajor = 4;\n"
|
|
" }\n"
|
|
" else if (&__linux_C_lib_version != 0)\n"
|
|
" {\n"
|
|
" ptr = __linux_C_lib_version;\n"
|
|
" }\n"
|
|
" else\n"
|
|
" {\n"
|
|
" libcmajor = 0; libcminor = 0; libcteeny = 0;\n"
|
|
" }\n"
|
|
"\n"
|
|
" if (ptr)\n"
|
|
" {\n"
|
|
" while (!isdigit (*ptr))\n"
|
|
" ptr++;\n"
|
|
"\n"
|
|
" sscanf (ptr, \"%d.%d.%d\", &libcmajor, &libcminor, &libcteeny);\n"
|
|
" libcmajor += glibcmajor;\n"
|
|
" }\n"
|
|
"\n"
|
|
" printf(\"#define DefaultLinuxCLibMajorVersion %d\\n\", libcmajor);\n"
|
|
" printf(\"#define DefaultLinuxCLibMinorVersion %d\\n\", libcminor);\n"
|
|
" printf(\"#define DefaultLinuxCLibTeenyVersion %d\\n\", libcteeny);\n"
|
|
"\n"
|
|
" return 0;\n"
|
|
"}\n"
|
|
;
|
|
|
|
static void
|
|
get_libc_version(FILE *inFile)
|
|
{
|
|
char aout[4096], *tmpdir;
|
|
FILE *fp;
|
|
const char *format = "%s -o %s -x c -";
|
|
char *cc;
|
|
int len;
|
|
char *command;
|
|
|
|
/* If $TMPDIR is defined and has an acceptable length,
|
|
* use that as tmp dir, else use /tmp. That fixes
|
|
* problems with /tmp mounted "noexec".
|
|
*/
|
|
if((tmpdir = getenv("TMPDIR")) != NULL && strlen(tmpdir) < (4096-13))
|
|
strcpy(aout, tmpdir);
|
|
else
|
|
strcpy(aout, "/tmp");
|
|
strcat(aout, "/imakeXXXXXX");
|
|
|
|
/* Pre-create temp file safely */
|
|
{
|
|
/* Linux + ELF has mkstemp() */
|
|
int tmpfd;
|
|
if ((tmpfd = mkstemp(aout)) == -1) {
|
|
perror("mkstemp");
|
|
abort();
|
|
}
|
|
close(tmpfd);
|
|
}
|
|
cc = getenv ("CC");
|
|
if (cc == NULL)
|
|
cc = "gcc";
|
|
len = strlen (aout) + strlen (format) + strlen (cc);
|
|
if (len < 128) len = 128;
|
|
if((command = alloca (len)) == NULL)
|
|
abort();
|
|
|
|
if (snprintf (command , len, format, cc, aout) == len)
|
|
abort ();
|
|
|
|
fp = popen (command, "w");
|
|
if (fp == NULL || fprintf (fp, "%s\n", libc_c) < 0
|
|
|| pclose (fp) != 0)
|
|
abort ();
|
|
|
|
fp = popen (aout, "r");
|
|
if (fp == NULL)
|
|
abort ();
|
|
|
|
while (fgets (command, len, fp))
|
|
fprintf (inFile, command);
|
|
|
|
len = pclose (fp);
|
|
remove (aout);
|
|
if (len)
|
|
abort ();
|
|
}
|
|
#endif
|
|
|
|
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
|
static void
|
|
get_stackprotector(FILE *inFile)
|
|
{
|
|
FILE *fp;
|
|
char *cc;
|
|
char command[1024], buf[1024];
|
|
|
|
cc = getenv("CC");
|
|
if (cc == NULL) {
|
|
cc = "cc";
|
|
}
|
|
snprintf(command, sizeof(command), "%s -v 2>&1", cc);
|
|
fp = popen(command, "r");
|
|
if (fp == NULL)
|
|
abort();
|
|
while (fgets(buf, sizeof(buf), fp)) {
|
|
if (strstr(buf, "propolice") != NULL) {
|
|
fprintf(inFile, "#define ProPoliceSupport YES\n");
|
|
break;
|
|
}
|
|
}
|
|
if (pclose(fp))
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
|
|
static void
|
|
get_distrib(FILE *inFile)
|
|
{
|
|
struct stat sb;
|
|
|
|
static char* suse = "/etc/SuSE-release";
|
|
static char* redhat = "/etc/redhat-release";
|
|
static char* debian = "/etc/debian_version";
|
|
|
|
fprintf (inFile, "%s\n", "#define LinuxUnknown 0");
|
|
fprintf (inFile, "%s\n", "#define LinuxSuSE 1");
|
|
fprintf (inFile, "%s\n", "#define LinuxCaldera 2");
|
|
fprintf (inFile, "%s\n", "#define LinuxCraftworks 3");
|
|
fprintf (inFile, "%s\n", "#define LinuxDebian 4");
|
|
fprintf (inFile, "%s\n", "#define LinuxInfoMagic 5");
|
|
fprintf (inFile, "%s\n", "#define LinuxKheops 6");
|
|
fprintf (inFile, "%s\n", "#define LinuxPro 7");
|
|
fprintf (inFile, "%s\n", "#define LinuxRedHat 8");
|
|
fprintf (inFile, "%s\n", "#define LinuxSlackware 9");
|
|
fprintf (inFile, "%s\n", "#define LinuxTurbo 10");
|
|
fprintf (inFile, "%s\n", "#define LinuxWare 11");
|
|
fprintf (inFile, "%s\n", "#define LinuxYggdrasil 12");
|
|
|
|
#ifdef CROSSCOMPILE
|
|
if (CrossCompiling) {
|
|
fprintf (inFile, "%s\n",
|
|
"#define DefaultLinuxDistribution LinuxUnknown");
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown");
|
|
return;
|
|
}
|
|
#endif
|
|
if (lstat (suse, &sb) == 0) {
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxSuSE");
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistName SuSE");
|
|
return;
|
|
}
|
|
if (lstat (redhat, &sb) == 0) {
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxRedHat");
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistName RedHat");
|
|
return;
|
|
}
|
|
if (lstat (debian, &sb) == 0) {
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxDebian");
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Debian");
|
|
/* You could also try to get the version of the Debian distrib by looking
|
|
* at the content of /etc/debian_version */
|
|
return;
|
|
}
|
|
/* what's the definitive way to tell what any particular distribution is? */
|
|
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistribution LinuxUnknown");
|
|
fprintf (inFile, "%s\n", "#define DefaultLinuxDistName Unknown");
|
|
/* would like to know what version of the distribution it is */
|
|
}
|
|
|
|
static void
|
|
get_ld_version(FILE *inFile)
|
|
{
|
|
FILE* ldprog;
|
|
signed char c;
|
|
int ldmajor, ldminor;
|
|
const char *ld = "ld -v";
|
|
|
|
#ifdef CROSSCOMPILE
|
|
if (CrossCompiling) {
|
|
char cmd[PATH_MAX];
|
|
strcpy (cmd, CrossCompileDir);
|
|
strcat (cmd,"/");
|
|
strcat (cmd,ld);
|
|
ldprog = popen (cmd, "r");
|
|
} else
|
|
#endif
|
|
ldprog = popen (ld, "r");
|
|
|
|
if (ldprog) {
|
|
do {
|
|
c = fgetc (ldprog);
|
|
} while (c != EOF && !isdigit (c));
|
|
ungetc (c, ldprog);
|
|
(void) fscanf (ldprog, "%d.%d", &ldmajor, &ldminor);
|
|
/* Start conversion to a more rational number */
|
|
if ((ldmajor > 2) || ((ldmajor == 2) && (ldminor > 9)))
|
|
ldmajor *= 100;
|
|
else
|
|
ldmajor *= 10;
|
|
|
|
fprintf(inFile, "#define DefaultLinuxBinUtilsMajorVersion %d\n",
|
|
ldmajor + ldminor);
|
|
pclose (ldprog);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined __FreeBSD__
|
|
static void
|
|
get_binary_format(FILE *inFile)
|
|
{
|
|
int mib[2];
|
|
size_t len;
|
|
int osrel = 0;
|
|
FILE *objprog = NULL;
|
|
int iself = 0;
|
|
char buf[10];
|
|
char cmd[PATH_MAX];
|
|
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = KERN_OSRELDATE;
|
|
len = sizeof(osrel);
|
|
sysctl(mib, 2, &osrel, &len, NULL, 0);
|
|
if (CrossCompiling) {
|
|
strcpy (cmd, CrossCompileDir);
|
|
strcat (cmd, "/");
|
|
strcat (cmd,"objformat");
|
|
} else
|
|
strcpy (cmd, "objformat");
|
|
|
|
if (osrel >= 300004 &&
|
|
(objprog = popen(cmd, "r")) != NULL &&
|
|
fgets(buf, sizeof(buf), objprog) != NULL &&
|
|
strncmp(buf, "elf", 3) == 0)
|
|
iself = 1;
|
|
if (objprog)
|
|
pclose(objprog);
|
|
|
|
fprintf(inFile, "#define DefaultToElfFormat %s\n", iself ? "YES" : "NO");
|
|
}
|
|
#endif
|
|
|
|
#if defined(sun) && defined(__SVR4)
|
|
/* Runs Sun compiler command and parses output - this is a bit of a hack
|
|
* as it depends on the particular output format of the -V flag, but it's
|
|
* worked for many releases.
|
|
*
|
|
* Input : cmd - command to run (called with -V flag)
|
|
* path - path to command to run (use $PATH if NULL)
|
|
* Output: cmajor & cminor - major and minor versions if found
|
|
* Returns: 0 if successful, -1 if not.
|
|
*/
|
|
static int
|
|
ask_sun_compiler_for_versions(const char *cmd, const char *path,
|
|
int *cmajor, int *cminor)
|
|
{
|
|
char buf[BUFSIZ];
|
|
char cmdtorun[PATH_MAX];
|
|
char* vptr;
|
|
FILE* ccproc;
|
|
const char vflag[] = " -V 2>&1";
|
|
int retval = -1;
|
|
|
|
int len = strlen(cmd) + sizeof(vflag);
|
|
|
|
if (path != NULL) {
|
|
len += strlen(path) + 1;
|
|
}
|
|
|
|
if (len < sizeof(cmdtorun)) {
|
|
if (path != NULL) {
|
|
sprintf(cmdtorun, "%s/%s %s", path, cmd, vflag);
|
|
} else {
|
|
sprintf(cmdtorun, "%s %s", cmd, vflag);
|
|
}
|
|
|
|
if ((ccproc = popen (cmdtorun, "r")) != NULL) {
|
|
if (fgets (buf, sizeof(buf), ccproc) != NULL) {
|
|
vptr = strrchr (buf, 'C');
|
|
if (vptr) {
|
|
for (; (*vptr != '\0') && !isdigit(*vptr); vptr++) {
|
|
/* Do nothing - just scanning for first digit */
|
|
}
|
|
if (*vptr != '\0') {
|
|
if (sscanf (vptr, "%d.%d", cmajor, cminor) == 2) {
|
|
retval = 0;
|
|
}
|
|
}
|
|
}
|
|
if (retval != 0) {
|
|
fprintf(stderr,
|
|
"warning: could not parse version number in output of:\n"
|
|
" %s\n", cmdtorun);
|
|
}
|
|
while (fgets (buf, sizeof(buf), ccproc) != NULL) {};
|
|
}
|
|
pclose (ccproc);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/* Find Sun compilers and their versions if present */
|
|
static void
|
|
get_sun_compiler_versions (FILE *inFile)
|
|
{
|
|
const char* sunpro_path = "/opt/SUNWspro/bin";
|
|
int cmajor, cminor, found = 0;
|
|
struct stat sb;
|
|
|
|
/* If cross-compiling, only check CrossCompilerDir for compilers.
|
|
* If not cross-compiling, first check cc in users $PATH,
|
|
* then try /opt/SUNWspro if not found in the users $PATH
|
|
*/
|
|
|
|
#if defined CROSSCOMPILE
|
|
if (CrossCompiling) {
|
|
if (ask_sun_compiler_for_versions("cc", CrossCompileDir,
|
|
&cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (ask_sun_compiler_for_versions("cc", NULL, &cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
} else if (ask_sun_compiler_for_versions("cc", sunpro_path,
|
|
&cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
fprintf(inFile, "#define DefaultSunProCCompilerDir %s", sunpro_path);
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
fprintf (inFile,
|
|
"#define DefaultSunProCCompilerMajorVersion %d\n", cmajor);
|
|
fprintf (inFile,
|
|
"#define DefaultSunProCCompilerMinorVersion %d\n", cminor);
|
|
}
|
|
|
|
/* Now do it again for C++ compiler (CC) */
|
|
found = 0;
|
|
#if defined CROSSCOMPILE
|
|
if (CrossCompiling) {
|
|
if (ask_sun_compiler_for_versions("CC", CrossCompileDir,
|
|
&cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (ask_sun_compiler_for_versions("CC", NULL, &cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
} else if (ask_sun_compiler_for_versions("CC", sunpro_path,
|
|
&cmajor, &cminor) == 0) {
|
|
found = 1;
|
|
fprintf(inFile,
|
|
"#define DefaultSunProCplusplusCompilerDir %s", sunpro_path);
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
fprintf (inFile,
|
|
"#define DefaultSunProCplusplusCompilerMajorVersion %d\n",
|
|
cmajor);
|
|
fprintf (inFile,
|
|
"#define DefaultSunProCplusplusCompilerMinorVersion %d\n",
|
|
cminor);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined CROSSCOMPILE || defined __GNUC__
|
|
static void
|
|
get_gcc_version(FILE *inFile, char *name)
|
|
{
|
|
fprintf (inFile, "#define HasGcc 1\n");
|
|
#ifdef CROSSCOMPILE
|
|
if (CrossCompiling)
|
|
{
|
|
if (gnu_c > 1) {
|
|
fprintf (inFile, "#define HasGcc2 1\n");
|
|
if (gnu_c > 2)
|
|
fprintf (inFile, "#define HasGcc3 1\n");
|
|
}
|
|
fprintf (inFile, "#define GccMajorVersion %d\n", gnu_c);
|
|
fprintf (inFile, "#define GccMinorVersion %d\n", gnu_c_minor);
|
|
} else
|
|
#endif
|
|
{
|
|
#if __GNUC__ > 1
|
|
fprintf (inFile, "#define HasGcc2 1\n");
|
|
# if __GNUC__ > 2
|
|
fprintf (inFile, "#define HasGcc3 1\n");
|
|
# endif
|
|
#endif
|
|
fprintf (inFile, "#define GccMajorVersion %d\n", __GNUC__);
|
|
fprintf (inFile, "#define GccMinorVersion %d\n", __GNUC_MINOR__);
|
|
}
|
|
#if defined(HAS_MERGE_CONSTANTS)
|
|
fprintf (inFile, "#define HasGccMergeConstants %d\n", HAS_MERGE_CONSTANTS);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static boolean
|
|
get_gcc(char *cmd)
|
|
{
|
|
struct stat sb;
|
|
static char* gcc_path[] = {
|
|
# if defined(linux) || \
|
|
defined(__NetBSD__) || \
|
|
defined(__OpenBSD__) || \
|
|
defined(__FreeBSD__) || \
|
|
defined(__DragonFly__) || \
|
|
defined(__APPLE__) || \
|
|
defined(__CYGWIN__) || \
|
|
defined(__MINGW32__) || \
|
|
defined(__GNU__) || \
|
|
defined(__GLIBC__)
|
|
"/usr/bin/cc", /* for Linux PostIncDir */
|
|
# endif
|
|
"/usr/local/bin/gcc",
|
|
"/opt/gnu/bin/gcc",
|
|
"/usr/pkg/bin/gcc"
|
|
};
|
|
|
|
#ifdef CROSSCOMPILE
|
|
static char* cross_cc_name[] = {
|
|
"cc",
|
|
"gcc"
|
|
};
|
|
|
|
if (CrossCompiling) {
|
|
int i;
|
|
for (i = 0; i < sizeof (cross_cc_name) / sizeof cross_cc_name[0]; i++){
|
|
strcpy (cmd, CrossCompileDir);
|
|
strcat (cmd, "/");
|
|
strcat (cmd, cross_cc_name[i]);
|
|
if (lstat (cmd, &sb) == 0) {
|
|
return TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
int i;
|
|
for (i = 0; i < sizeof (gcc_path) / sizeof gcc_path[0]; i++) {
|
|
if (lstat (gcc_path[i], &sb) == 0) {
|
|
strcpy (cmd, gcc_path[i]);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#if defined CROSSCOMPILE || !defined __UNIXOS2__
|
|
static void
|
|
get_gcc_incdir(FILE *inFile, char* name)
|
|
{
|
|
FILE* gccproc;
|
|
char buf[PATH_MAX];
|
|
char cmd[PATH_MAX];
|
|
char* ptr;
|
|
|
|
strcpy(cmd,name);
|
|
|
|
buf[0] = '\0';
|
|
strcat (cmd, " --print-libgcc-file-name");
|
|
if ((gccproc = popen (cmd, "r")) != NULL) {
|
|
if (fgets (buf, PATH_MAX, gccproc) != NULL) {
|
|
ptr = strstr (buf, "libgcc.a");
|
|
if (ptr) strcpy (ptr, "include");
|
|
}
|
|
(void) pclose (gccproc);
|
|
}
|
|
|
|
if (buf[0])
|
|
fprintf (inFile, "#define DefaultGccIncludeDir \"%s\"\n", buf);
|
|
}
|
|
#endif
|
|
|
|
boolean
|
|
define_os_defaults(FILE *inFile)
|
|
{
|
|
#if defined CROSSCOMPILE || ( !defined(WIN32) && !defined(__UNIXOS2__) )
|
|
#ifdef CROSSCOMPILE
|
|
#ifdef __GNUC__
|
|
if (1)
|
|
#else
|
|
if ((sys != win32) && (sys != emx))
|
|
#endif
|
|
#endif
|
|
{
|
|
# if (defined(DEFAULT_OS_NAME) || defined(DEFAULT_OS_MAJOR_REV) || \
|
|
defined(DEFAULT_OS_MINOR_REV) || defined(DEFAULT_OS_TEENY_REV))
|
|
struct utsname *name = NULL;
|
|
struct utsname uts_name;
|
|
char buf[SYS_NMLN * 5 + 1];
|
|
|
|
/* Obtain the system information. */
|
|
#ifdef CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
#endif
|
|
{
|
|
if (uname(&uts_name) < 0)
|
|
LogFatal("Cannot invoke uname", "");
|
|
else
|
|
name = &uts_name;
|
|
}
|
|
#if defined CROSSCOMPILE && (defined linux || defined(__GLIBC__))
|
|
else {
|
|
strncpy(uts_name.sysname,cross_uts_sysname,SYS_NMLN);
|
|
strncpy(uts_name.release,cross_uts_release,SYS_NMLN);
|
|
strncpy(uts_name.version,cross_uts_version,SYS_NMLN);
|
|
strncpy(uts_name.machine,cross_uts_machine,SYS_NMLN);
|
|
name = &uts_name;
|
|
}
|
|
#endif
|
|
# ifdef __FreeBSD__
|
|
/* Override for compiling in chroot of other OS version, such as
|
|
* in the bento build cluster.
|
|
*/
|
|
{
|
|
char *e;
|
|
if ((e = getenv("OSREL")) != NULL &&
|
|
strlen(name->sysname) + strlen(e) + 1 < SYS_NMLN) {
|
|
strcpy(name->release, e);
|
|
strcpy(name->version, name->sysname);
|
|
strcat(name->version, " ");
|
|
strcat(name->version, e);
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# if defined DEFAULT_OS_NAME
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
{
|
|
parse_utsname(name, DEFAULT_OS_NAME, buf,
|
|
"Bad DEFAULT_OS_NAME syntax %s");
|
|
# ifdef DEFAULT_OS_NAME_FROB
|
|
DEFAULT_OS_NAME_FROB(buf, sizeof buf);
|
|
# endif
|
|
if (buf[0] != '\0')
|
|
fprintf(inFile, "#define DefaultOSName %s\n", buf);
|
|
}
|
|
# endif
|
|
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && defaultOsName) {
|
|
parse_utsname(name, defaultOsName, buf,
|
|
"Bad DEFAULT_OS_NAME syntax %s");
|
|
if (defaultOsNameFrob)
|
|
defaultOsNameFrob(buf, sizeof buf);
|
|
if (buf[0] != '\0')
|
|
fprintf(inFile, "#define DefaultOSName %s\n", buf);
|
|
}
|
|
# endif
|
|
|
|
# ifdef DEFAULT_OS_MAJOR_REV
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
{
|
|
parse_utsname(name, DEFAULT_OS_MAJOR_REV, buf,
|
|
"Bad DEFAULT_OS_MAJOR_REV syntax %s");
|
|
# ifdef DEFAULT_OS_MAJOR_REV_FROB
|
|
DEFAULT_OS_MAJOR_REV_FROB(buf, sizeof buf);
|
|
# endif
|
|
fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && defaultOsMajorRev) {
|
|
parse_utsname(name, defaultOsMajorRev, buf,
|
|
"Bad defaultOsMajorRev syntax %s");
|
|
if (defaultOsMajorRevFrob)
|
|
defaultOsMajorRevFrob(buf, sizeof buf);
|
|
fprintf(inFile, "#define DefaultOSMajorVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# ifdef DEFAULT_OS_MINOR_REV
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
{
|
|
parse_utsname(name, DEFAULT_OS_MINOR_REV, buf,
|
|
"Bad DEFAULT_OS_MINOR_REV syntax %s");
|
|
# ifdef DEFAULT_OS_MINOR_REV_FROB
|
|
DEFAULT_OS_MINOR_REV_FROB(buf, sizeof buf);
|
|
# endif
|
|
fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && defaultOsMinorRev) {
|
|
parse_utsname(name, defaultOsMinorRev, buf,
|
|
"Bad defaultOsMinorRev syntax %s");
|
|
if (defaultOsMinorRevFrob)
|
|
defaultOsMinorRevFrob(buf, sizeof buf);
|
|
fprintf(inFile, "#define DefaultOSMinorVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# ifdef DEFAULT_OS_TEENY_REV
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
{
|
|
parse_utsname(name, DEFAULT_OS_TEENY_REV, buf,
|
|
"Bad DEFAULT_OS_TEENY_REV syntax %s");
|
|
# ifdef DEFAULT_OS_TEENY_REV_FROB
|
|
DEFAULT_OS_TEENY_REV_FROB(buf, sizeof buf);
|
|
# endif
|
|
fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && defaultOsTeenyRev) {
|
|
parse_utsname(name, defaultOsTeenyRev, buf,
|
|
"Bad defaultOsTeenyRev syntax %s");
|
|
if (defaultOsTeenyRevFrob)
|
|
defaultOsTeenyRevFrob(buf, sizeof buf);
|
|
fprintf(inFile, "#define DefaultOSTeenyVersion %s\n",
|
|
*buf ? trim_version(buf) : "0");
|
|
}
|
|
# endif
|
|
|
|
# ifdef DEFAULT_MACHINE_ARCHITECTURE
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
{
|
|
parse_utsname(name, DEFAULT_MACHINE_ARCHITECTURE, buf,
|
|
"Bad DEFAULT_MACHINE_ARCHITECTURE %s");
|
|
fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf);
|
|
}
|
|
# endif
|
|
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && defaultMachineArchitecture) {
|
|
parse_utsname(name, defaultMachineArchitecture, buf,
|
|
"Bad defaultMachineArchitecture syntax %s");
|
|
fprintf(inFile, "#ifndef %s\n# define %s\n#endif\n", buf, buf);
|
|
}
|
|
# endif
|
|
# endif
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling)
|
|
get_cross_compile_dir(inFile);
|
|
else
|
|
# endif
|
|
fprintf(inFile, "#define CrossCompiling NO\n");
|
|
# if defined CROSSCOMPILE
|
|
if (CrossCompiling && sys == LinuX)
|
|
# endif
|
|
# if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
|
|
# if defined(CROSSCOMPILE) && defined(__linux__)
|
|
if (sys == LinuX)
|
|
# endif
|
|
get_distrib (inFile);
|
|
# endif
|
|
# if defined linux || defined(__GLIBC__)
|
|
# if defined CROSSCOMPILE
|
|
if (!CrossCompiling)
|
|
# endif
|
|
get_libc_version (inFile);
|
|
# if defined CROSSCOMPILE
|
|
else {
|
|
fprintf(inFile,"#define DefaultLinuxCLibMajorVersion %d\n",
|
|
glibc_major);
|
|
fprintf(inFile,"#define DefaultLinuxCLibMinorVersion %d\n",
|
|
glibc_minor);
|
|
fprintf(inFile,"#define DefaultLinuxCLibTeenyVersion 0\n");
|
|
}
|
|
# endif
|
|
# endif /* linux || __GLIBC__ */
|
|
# if defined CROSSCOMPILE || defined linux || defined(__GLIBC__)
|
|
# if defined CROSSCOMPILE && defined(__linux__)
|
|
if (sys == LinuX)
|
|
# endif
|
|
get_ld_version(inFile);
|
|
# endif
|
|
# if defined (sun) && defined(SVR4)
|
|
get_sun_compiler_versions (inFile);
|
|
# endif
|
|
# if defined CROSSCOMPILE || defined __GNUC__
|
|
# if defined CROSSCOMPILE
|
|
if (gnu_c)
|
|
# endif
|
|
{
|
|
char name[PATH_MAX];
|
|
if (get_gcc(name)) {
|
|
get_gcc_version (inFile,name);
|
|
# if defined CROSSCOMPILE || !defined __UNIXOS2__
|
|
# if defined CROSSCOMPILE
|
|
if (sys != emx)
|
|
# endif
|
|
get_gcc_incdir(inFile,name);
|
|
# endif
|
|
}
|
|
}
|
|
# endif
|
|
# if defined __FreeBSD__
|
|
# if defined CROSSCOMPILE
|
|
if (sys == freeBSD)
|
|
# endif
|
|
get_binary_format(inFile);
|
|
# endif
|
|
}
|
|
#endif /* !WIN32 && !__UNIXOS2__*/
|
|
#if defined WIN32
|
|
# ifdef CROSSCOMPILE
|
|
else if (sys == win32 && !CrossCompiling)
|
|
# endif
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
static char* os_names[] = { "Win32s", "Windows 95", "Windows NT" };
|
|
|
|
memset(&osvi, 0, sizeof(OSVERSIONINFO));
|
|
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
GetVersionEx (&osvi);
|
|
|
|
fprintf (inFile, "#define DefaultOSName Microsoft %s\n",
|
|
os_names[osvi.dwPlatformId]);
|
|
|
|
fprintf(inFile, "#define DefaultOSMajorVersion %d\n", osvi.dwMajorVersion);
|
|
fprintf(inFile, "#define DefaultOSMinorVersion %d\n", osvi.dwMinorVersion);
|
|
fprintf(inFile, "#define DefaultOSTeenyVersion %d\n",
|
|
osvi.dwBuildNumber & 0xFFFF);
|
|
}
|
|
#endif /* WIN32 */
|
|
#ifdef CROSSCOMPILE
|
|
else if (sys == emx)
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined __UNIXOS2__
|
|
{
|
|
fprintf(inFile, "#define DefaultOSMajorVersion 4\n");
|
|
fprintf(inFile, "#define DefaultOSMinorVersion 0\n");
|
|
fprintf(inFile, "#define DefaultOSTeenyVersion 0\n");
|
|
}
|
|
#endif /* EMX */
|
|
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
|
get_stackprotector(inFile);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
cppit(char *imakefile, char *template, char *masterc,
|
|
FILE *outfd, char *outfname)
|
|
{
|
|
FILE *inFile;
|
|
|
|
haveImakefileC = TRUE;
|
|
inFile = fopen(masterc, "w");
|
|
if (inFile == NULL)
|
|
LogFatal("Cannot open %s for output.", masterc);
|
|
if (fprintf(inFile, "%s\n", ImakefileCHeader) < 0 ||
|
|
define_os_defaults(inFile) ||
|
|
optional_include(inFile, "IMAKE_LOCAL_DEFINES", "localdefines") ||
|
|
optional_include(inFile, "IMAKE_ADMIN_DEFINES", "admindefines") ||
|
|
fprintf(inFile, "#define %s <%s>\n", ImakeDefSym, imakefile) < 0 ||
|
|
fprintf(inFile, LocalDefineFmt, ImakeTmplSym, template) < 0 ||
|
|
fprintf(inFile, IncludeFmt, ImakeTmplSym) < 0 ||
|
|
optional_include(inFile, "IMAKE_ADMIN_MACROS", "adminmacros") ||
|
|
optional_include(inFile, "IMAKE_LOCAL_MACROS", "localmacros") ||
|
|
fflush(inFile) ||
|
|
fclose(inFile))
|
|
LogFatal("Cannot write to %s.", masterc);
|
|
/*
|
|
* Fork and exec cpp
|
|
*/
|
|
doit(outfd, cpp, cpp_argv);
|
|
CleanCppOutput(outfd, outfname);
|
|
}
|
|
|
|
void
|
|
makeit(void)
|
|
{
|
|
doit(NULL, make_argv[0], make_argv);
|
|
}
|
|
|
|
char *
|
|
CleanCppInput(char *imakefile)
|
|
{
|
|
FILE *outFile = NULL;
|
|
FILE *inFile;
|
|
char *buf, /* buffer for file content */
|
|
*pbuf, /* walking pointer to buf */
|
|
*punwritten, /* pointer to unwritten portion of buf */
|
|
*ptoken, /* pointer to # token */
|
|
*pend, /* pointer to end of # token */
|
|
savec; /* temporary character holder */
|
|
int count;
|
|
struct stat st;
|
|
|
|
/*
|
|
* grab the entire file.
|
|
*/
|
|
if (!(inFile = fopen(imakefile, "r")))
|
|
LogFatal("Cannot open %s for input.", imakefile);
|
|
if (fstat(fileno(inFile), &st) < 0)
|
|
LogFatal("Cannot stat %s for size.", imakefile);
|
|
buf = Emalloc((int)st.st_size+3);
|
|
count = fread(buf + 2, 1, st.st_size, inFile);
|
|
if (count == 0 && st.st_size != 0)
|
|
LogFatal("Cannot read %s:", imakefile);
|
|
fclose(inFile);
|
|
buf[0] = '\n';
|
|
buf[1] = '\n';
|
|
buf[count + 2] = '\0';
|
|
|
|
punwritten = pbuf = buf + 2;
|
|
while (*pbuf) {
|
|
/* for compatibility, replace make comments for cpp */
|
|
if (*pbuf == '#' && pbuf[-1] == '\n' && pbuf[-2] != '\\') {
|
|
ptoken = pbuf+1;
|
|
while (*ptoken == ' ' || *ptoken == '\t')
|
|
ptoken++;
|
|
pend = ptoken;
|
|
while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n' && *pend != '\r')
|
|
pend++;
|
|
savec = *pend;
|
|
*pend = '\0';
|
|
if (strcmp(ptoken, "define") &&
|
|
strcmp(ptoken, "if") &&
|
|
strcmp(ptoken, "ifdef") &&
|
|
strcmp(ptoken, "ifndef") &&
|
|
strcmp(ptoken, "include") &&
|
|
strcmp(ptoken, "line") &&
|
|
strcmp(ptoken, "else") &&
|
|
strcmp(ptoken, "elif") &&
|
|
strcmp(ptoken, "endif") &&
|
|
strcmp(ptoken, "error") &&
|
|
strcmp(ptoken, "pragma") &&
|
|
strcmp(ptoken, "undef")) {
|
|
if (outFile == NULL) {
|
|
#ifdef HAS_MKSTEMP
|
|
int fd;
|
|
#endif
|
|
tmpImakefile = Strdup(tmpImakefile);
|
|
#ifndef HAS_MKSTEMP
|
|
if (mktemp(tmpImakefile) == NULL ||
|
|
(outFile = fopen(tmpImakefile, "w+")) == NULL) {
|
|
LogFatal("Cannot open %s for write.",
|
|
tmpImakefile);
|
|
}
|
|
#else
|
|
fd=mkstemp(tmpImakefile);
|
|
if (fd != -1)
|
|
outFile = fdopen(fd, "w");
|
|
if (outFile == NULL) {
|
|
if (fd != -1) {
|
|
unlink(tmpImakefile); close(fd);
|
|
}
|
|
LogFatal("Cannot open %s for write.",
|
|
tmpImakefile);
|
|
}
|
|
#endif
|
|
}
|
|
writetmpfile(outFile, punwritten, pbuf-punwritten,
|
|
tmpImakefile);
|
|
if (ptoken > pbuf + 1)
|
|
writetmpfile(outFile, "XCOMM", 5, tmpImakefile);
|
|
else
|
|
writetmpfile(outFile, "XCOMM ", 6, tmpImakefile);
|
|
punwritten = pbuf + 1;
|
|
}
|
|
*pend = savec;
|
|
}
|
|
pbuf++;
|
|
}
|
|
if (outFile) {
|
|
writetmpfile(outFile, punwritten, pbuf-punwritten, tmpImakefile);
|
|
fclose(outFile);
|
|
|
|
return tmpImakefile;
|
|
}
|
|
|
|
return(imakefile);
|
|
}
|
|
|
|
void
|
|
CleanCppOutput(FILE *tmpfd, char *tmpfname)
|
|
{
|
|
char *input;
|
|
int blankline = 0;
|
|
|
|
while((input = ReadLine(tmpfd, tmpfname))) {
|
|
if (isempty(input)) {
|
|
if (blankline++)
|
|
continue;
|
|
#ifdef CROSSCOMPILE
|
|
if (fixup_whitespace)
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
|
|
KludgeResetRule();
|
|
#endif
|
|
} else {
|
|
blankline = 0;
|
|
#ifdef CROSSCOMPILE
|
|
if (fixup_whitespace)
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
|
|
KludgeOutputLine(&input);
|
|
#endif
|
|
writetmpfile(tmpfd, input, strlen(input), tmpfname);
|
|
}
|
|
writetmpfile(tmpfd, "\n", 1, tmpfname);
|
|
}
|
|
fflush(tmpfd);
|
|
#ifdef NFS_STDOUT_BUG
|
|
/*
|
|
* On some systems, NFS seems to leave a large number of nulls at
|
|
* the end of the file. Ralph Swick says that this kludge makes the
|
|
* problem go away.
|
|
*/
|
|
ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Determine if a line has nothing in it. As a side effect, we trim white
|
|
* space from the end of the line. Cpp magic cookies are also thrown away.
|
|
* "XCOMM" token is transformed to "#".
|
|
*/
|
|
boolean
|
|
isempty(char *line)
|
|
{
|
|
char *pend;
|
|
|
|
/*
|
|
* Check for lines of the form
|
|
* # n "...
|
|
* or
|
|
* # line n "...
|
|
*/
|
|
if (*line == '#') {
|
|
pend = line+1;
|
|
if (*pend == ' ')
|
|
pend++;
|
|
if (*pend == 'l' && pend[1] == 'i' && pend[2] == 'n' &&
|
|
pend[3] == 'e' && pend[4] == ' ')
|
|
pend += 5;
|
|
if (isdigit(*pend)) {
|
|
do {
|
|
pend++;
|
|
} while (isdigit(*pend));
|
|
if (*pend == '\n' || *pend == '\0')
|
|
return(TRUE);
|
|
if (*pend++ == ' ' && *pend == '"')
|
|
return(TRUE);
|
|
}
|
|
while (*pend)
|
|
pend++;
|
|
} else {
|
|
for (pend = line; *pend; pend++) {
|
|
if (*pend == 'X' && pend[1] == 'C' && pend[2] == 'O' &&
|
|
pend[3] == 'M' && pend[4] == 'M' &&
|
|
(pend == line || pend[-1] == ' ' || pend[-1] == '\t' || pend[-1] == '\r') &&
|
|
(pend[5] == ' ' || pend[5] == '\t' || pend[5] == '\r' || pend[5] == '\0'))
|
|
{
|
|
*pend = '#';
|
|
memmove(pend+1, pend+5, strlen(pend+5)+1);
|
|
}
|
|
#ifdef CROSSCOMPILE
|
|
if (magic_make_vars)
|
|
#endif
|
|
{
|
|
#if defined CROSSCOMPILE || defined MAGIC_MAKE_VARS
|
|
if (*pend == 'X' && pend[1] == 'V' && pend[2] == 'A' &&
|
|
pend[3] == 'R')
|
|
{
|
|
char varbuf[5];
|
|
int i;
|
|
|
|
if (pend[4] == 'd' && pend[5] == 'e' && pend[6] == 'f' &&
|
|
pend[7] >= '0' && pend[7] <= '9')
|
|
{
|
|
i = pend[7] - '0';
|
|
sprintf(varbuf, "%0.4d", xvariable);
|
|
strncpy(pend+4, varbuf, 4);
|
|
xvariables[i] = xvariable;
|
|
xvariable = (xvariable + 1) % 10000;
|
|
}
|
|
else if (pend[4] == 'u' && pend[5] == 's' &&
|
|
pend[6] == 'e' && pend[7] >= '0' &&
|
|
pend[7] <= '9')
|
|
{
|
|
i = pend[7] - '0';
|
|
sprintf(varbuf, "%0.4d", xvariables[i]);
|
|
strncpy(pend+4, varbuf, 4);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
while (--pend >= line && (*pend == ' ' || *pend == '\t' || *pend == '\r')) ;
|
|
pend[1] = '\0';
|
|
return (*line == '\0');
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
char *
|
|
ReadLine(FILE *tmpfd, char *tmpfname)
|
|
{
|
|
static boolean initialized = FALSE;
|
|
static char *buf, *pline, *end;
|
|
register char *p1, *p2;
|
|
|
|
if (! initialized) {
|
|
#ifdef WIN32
|
|
FILE *fp = tmpfd;
|
|
#endif
|
|
int total_red;
|
|
struct stat st;
|
|
|
|
/*
|
|
* Slurp it all up.
|
|
*/
|
|
fseek(tmpfd, 0, 0);
|
|
if (fstat(fileno(tmpfd), &st) < 0)
|
|
LogFatal("cannot stat %s for size", tmpMakefile);
|
|
pline = buf = Emalloc((int)st.st_size+1);
|
|
total_red = fread(buf, 1, st.st_size, tmpfd);
|
|
if (total_red == 0 && st.st_size != 0)
|
|
LogFatal("cannot read %s", tmpMakefile);
|
|
end = buf + total_red;
|
|
*end = '\0';
|
|
fseek(tmpfd, 0, 0);
|
|
#if defined(SYSV) || defined(WIN32) || defined(USE_FREOPEN)
|
|
tmpfd = freopen(tmpfname, "w+", tmpfd);
|
|
#ifdef WIN32
|
|
if (! tmpfd) /* if failed try again */
|
|
tmpfd = freopen(tmpfname, "w+", fp);
|
|
#endif
|
|
if (! tmpfd)
|
|
LogFatal("cannot reopen %s\n", tmpfname);
|
|
#else /* !SYSV */
|
|
ftruncate(fileno(tmpfd), (off_t) 0);
|
|
#endif /* !SYSV */
|
|
initialized = TRUE;
|
|
fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
|
|
fprintf (tmpfd, "# %s\n",
|
|
"$Xorg: imake.c,v 1.6 2001/02/09 02:03:15 xorgcvs Exp $");
|
|
}
|
|
|
|
for (p1 = pline; p1 < end; p1++) {
|
|
if (*p1 == '@' && *(p1+1) == '@'
|
|
/* ignore ClearCase version-extended pathnames */
|
|
&& !(p1 != pline && !isspace(*(p1-1)) && *(p1+2) == '/'))
|
|
{ /* soft EOL */
|
|
*p1++ = '\0';
|
|
p1++; /* skip over second @ */
|
|
break;
|
|
}
|
|
else if (*p1 == '\n') { /* real EOL */
|
|
#if defined CROSSCOMPILE || defined WIN32
|
|
# if defined CROSSCOMPILE
|
|
if (sys == win32)
|
|
# endif
|
|
{
|
|
if (p1 > pline && p1[-1] == '\r')
|
|
p1[-1] = '\0';
|
|
}
|
|
#endif
|
|
*p1++ = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* return NULL at the end of the file.
|
|
*/
|
|
p2 = (pline == p1 ? NULL : pline);
|
|
pline = p1;
|
|
return(p2);
|
|
}
|
|
|
|
void
|
|
writetmpfile(FILE *fd, char *buf, int cnt, char *fname)
|
|
{
|
|
if (fwrite(buf, sizeof(char), cnt, fd) == -1)
|
|
LogFatal("Cannot write to %s.", fname);
|
|
}
|
|
|
|
char *
|
|
Emalloc(int size)
|
|
{
|
|
char *p;
|
|
|
|
if ((p = malloc(size)) == NULL)
|
|
LogFatalI("Cannot allocate %d bytes", size);
|
|
return(p);
|
|
}
|
|
|
|
#if defined CROSSCOMPILE || defined FIXUP_CPP_WHITESPACE
|
|
void
|
|
KludgeOutputLine(char **pline)
|
|
{
|
|
char *p = *pline;
|
|
char quotechar = '\0';
|
|
|
|
switch (*p) {
|
|
case '#': /*Comment - ignore*/
|
|
break;
|
|
case '\t': /*Already tabbed - ignore it*/
|
|
break;
|
|
case ' ': /*May need a tab*/
|
|
default:
|
|
#ifdef CROSSCOMPILE
|
|
if (inline_syntax)
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined INLINE_SYNTAX
|
|
{
|
|
if (*p == '<' && p[1] == '<') { /* inline file close */
|
|
InInline--;
|
|
InRule = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
* The following cases should not be treated as beginning of
|
|
* rules:
|
|
* variable := name (GNU make)
|
|
* variable = .*:.* (':' should be allowed as value)
|
|
* sed 's:/a:/b:' (: used in quoted values)
|
|
*/
|
|
for (; *p; p++) {
|
|
if (quotechar) {
|
|
if (quotechar == '\\' ||
|
|
(*p == quotechar &&
|
|
# if defined CROSSCOMPILE || defined WIN32
|
|
(
|
|
# if defined CROSSCOMPILE
|
|
(sys == win32) &&
|
|
# endif
|
|
quotechar != ')') &&
|
|
# endif
|
|
p[-1] != '\\'))
|
|
quotechar = '\0';
|
|
continue;
|
|
}
|
|
switch (*p) {
|
|
case '\\':
|
|
case '"':
|
|
case '\'':
|
|
quotechar = *p;
|
|
break;
|
|
case '(':
|
|
quotechar = ')';
|
|
break;
|
|
case '{':
|
|
quotechar = '}';
|
|
break;
|
|
case '[':
|
|
quotechar = ']';
|
|
break;
|
|
case '=':
|
|
#ifdef CROSSCOMPILE
|
|
if (remove_cpp_leadspace)
|
|
#endif
|
|
#if defined CROSSCOMPILE || defined REMOVE_CPP_LEADSPACE
|
|
{
|
|
if (!InRule && **pline == ' ') {
|
|
while (**pline == ' ')
|
|
(*pline)++;
|
|
}
|
|
}
|
|
#endif
|
|
goto breakfor;
|
|
#if defined CROSSCOMPILE || defined INLINE_SYNTAX
|
|
case '<':
|
|
if (inline_syntax) {
|
|
if (p[1] == '<') /* inline file start */
|
|
InInline++;
|
|
}
|
|
break;
|
|
#endif
|
|
case ':':
|
|
if (p[1] == '=')
|
|
goto breakfor;
|
|
while (**pline == ' ')
|
|
(*pline)++;
|
|
InRule = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
breakfor:
|
|
if (InRule && **pline == ' ')
|
|
**pline = '\t';
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
KludgeResetRule(void)
|
|
{
|
|
InRule = FALSE;
|
|
}
|
|
#endif
|
|
char *
|
|
Strdup(char *cp)
|
|
{
|
|
char *new = Emalloc(strlen(cp) + 1);
|
|
|
|
strcpy(new, cp);
|
|
return new;
|
|
}
|
|
|
|
#ifdef CROSSCOMPILE
|
|
char*
|
|
CrossCompileCPP(void)
|
|
{
|
|
char *cpp, *c;
|
|
int len ;
|
|
if (crosscompile_use_cc_e)
|
|
AddCppArg("-E");
|
|
|
|
cpp = strrchr(crosscompile_cpp,'/');
|
|
if (!cpp)
|
|
cpp = crosscompile_cpp;
|
|
else
|
|
cpp++;
|
|
|
|
len = strlen(cpp) + strlen(CrossCompileDir) + 2;
|
|
c = Emalloc(len);
|
|
|
|
(void)snprintf(c, len,"%s/%s",CrossCompileDir,cpp);
|
|
|
|
return c;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CROSSCOMPILE
|
|
static void
|
|
get_cross_compile_dir(FILE *inFile)
|
|
{
|
|
fprintf(inFile, "#define CrossCompileDir %s\n",
|
|
CrossCompileDir);
|
|
fprintf(inFile, "#define CrossCompiling YES\n");
|
|
}
|
|
#endif
|