1674 lines
40 KiB
C
1674 lines
40 KiB
C
/*
|
|
* COMPONENT_NAME: BLDPROCESS
|
|
*
|
|
* FUNCTIONS: DieHorribly
|
|
* Error
|
|
* Fatal
|
|
* Finish
|
|
* MainParseArgs
|
|
* Main_ParseArgLine
|
|
* MakeSetWorkingDir
|
|
* Punt
|
|
* ReadMakefile
|
|
* ReadMakefileP
|
|
* confmove
|
|
* didchdir
|
|
* emalloc
|
|
* enomem
|
|
* fixvar
|
|
* ltop
|
|
* main
|
|
* makechdir
|
|
* makepath
|
|
* movedmake
|
|
* plainmake
|
|
* ptol
|
|
* rdircat
|
|
* reldir
|
|
* setpathvars
|
|
* strdup2
|
|
* ui_print_revision1595
|
|
* usage
|
|
*
|
|
* ORIGINS: 27,71
|
|
*
|
|
* This module contains IBM CONFIDENTIAL code. -- (IBM
|
|
* Confidential Restricted when combined with the aggregated
|
|
* modules for this product)
|
|
* SOURCE MATERIALS
|
|
*
|
|
* (C) COPYRIGHT International Business Machines Corp. 1994
|
|
* All Rights Reserved
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
/*
|
|
* @OSF_FREE_COPYRIGHT@
|
|
* COPYRIGHT NOTICE
|
|
* Copyright (c) 1992, 1991, 1990
|
|
* Open Software Foundation, Inc.
|
|
*
|
|
* Permission is hereby granted to use, copy, modify and freely distribute
|
|
* the software in this file and its documentation for any purpose without
|
|
* fee, provided that the above copyright notice appears in all copies and
|
|
* that both the copyright notice and this permission notice appear in
|
|
* supporting documentation. Further, provided that the name of Open
|
|
* Software Foundation, Inc. ("OSF") not be used in advertising or
|
|
* publicity pertaining to distribution of the software without prior
|
|
* written permission from OSF. OSF makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*/
|
|
/*
|
|
* HISTORY
|
|
* $Log: main.c,v $
|
|
* Revision 1.2.13.1 1993/09/21 19:17:52 damon
|
|
* CR 635. Bumped version to 2.3.2
|
|
* [1993/09/21 19:17:42 damon]
|
|
*
|
|
* Revision 1.2.11.1 1993/08/11 16:05:01 damon
|
|
* CR 620. Updated version to 2.3.1
|
|
* [1993/08/11 16:04:51 damon]
|
|
*
|
|
* Revision 1.2.9.3 1993/05/04 19:13:01 damon
|
|
* CR 393. Update version string to 2.3
|
|
* [1993/05/04 19:12:53 damon]
|
|
*
|
|
* Revision 1.2.9.2 1993/04/26 20:27:19 damon
|
|
* CR 424. make now handles error returns better
|
|
* [1993/04/26 20:26:56 damon]
|
|
*
|
|
* Revision 1.2.4.8 1992/12/03 19:06:54 damon
|
|
* ODE 2.2 CR 346. Expanded copyright
|
|
* [1992/12/03 18:36:14 damon]
|
|
*
|
|
* Revision 1.2.4.7 1992/11/23 14:53:31 damon
|
|
* Changed version string
|
|
* [1992/11/23 14:53:12 damon]
|
|
*
|
|
* Revision 1.2.4.6 1992/11/13 15:19:50 root
|
|
* Added bogus strdup2 function for systems which have
|
|
* a bad strdup declaration. See make.h for details.
|
|
* [1992/11/13 14:56:04 root]
|
|
*
|
|
* Revision 1.2.4.5 1992/11/09 21:50:27 damon
|
|
* CR 296. Cleaned up to remove warnings
|
|
* [1992/11/09 21:49:14 damon]
|
|
*
|
|
* Revision 1.2.4.4 1992/09/24 19:26:22 gm
|
|
* CR286: Major improvements to make internals.
|
|
* [1992/09/24 17:54:49 gm]
|
|
*
|
|
* Revision 1.2.4.3 1992/06/16 22:42:31 damon
|
|
* more 2.1.1 touch-up
|
|
* [1992/06/16 22:40:20 damon]
|
|
*
|
|
* Revision 1.2.2.3 1992/04/02 17:04:59 damon
|
|
* Fixed BUILD_DATE for bootstrap
|
|
* [1992/04/02 17:04:44 damon]
|
|
*
|
|
* Revision 1.2.2.2 1992/04/02 15:02:22 damon
|
|
* Added ui_print_revision and BUILD_DATE
|
|
* [1992/04/02 15:00:44 damon]
|
|
*
|
|
* Revision 1.2 1991/12/05 20:44:24 devrcs
|
|
* Changes for parallel make.
|
|
* [91/04/21 16:38:13 gm]
|
|
*
|
|
* Changes for Reno make
|
|
* [91/03/22 16:06:16 mckeen]
|
|
*
|
|
* $EndLog$
|
|
*/
|
|
/*
|
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
|
* Copyright (c) 1988, 1989 by Adam de Boor
|
|
* Copyright (c) 1989 by Berkeley Softworks
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Adam de Boor.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted provided
|
|
* that: (1) source distributions retain this entire copyright notice and
|
|
* comment, and (2) distributions including binaries display the following
|
|
* acknowledgement: ``This product includes software developed by the
|
|
* University of California, Berkeley and its contributors'' in the
|
|
* documentation or other materials provided with the distribution and in
|
|
* all advertising materials mentioning features or use of this software.
|
|
* Neither the name of the University nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)44 1.9 src/bldenv/make/main.c, bldprocess, bos412, 9443A412a 10/27/94 16:30:54";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
char copyright[] =
|
|
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
|
|
All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
static char rcsid[] = "@(#)main.c 5.24 (Berkeley) 2/2/91";
|
|
#endif /* not lint */
|
|
|
|
/*-
|
|
* main.c --
|
|
* The main file for this entire program. Exit routines etc
|
|
* reside here.
|
|
*
|
|
* Utility functions defined in this file:
|
|
* Main_ParseArgLine Takes a line of arguments, breaks them and
|
|
* treats them as if they were given when first
|
|
* invoked. Used by the parse module to implement
|
|
* the .MFLAGS target.
|
|
*
|
|
* Error Print a tagged error message. The global
|
|
* MAKE variable must have been defined. This
|
|
* takes a format string and two optional
|
|
* arguments for it.
|
|
*
|
|
* Fatal Print an error message and exit. Also takes
|
|
* a format string and two arguments.
|
|
*
|
|
* Punt Aborts all jobs and exits with a message. Also
|
|
* takes a format string and two arguments.
|
|
*
|
|
* Finish Finish things up by printing the number of
|
|
* errors which occured, as passed to it, and
|
|
* exiting.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "make.h"
|
|
#include "buf.h"
|
|
#include "pathnames.h"
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX MAXPATHLEN
|
|
#endif
|
|
|
|
string_t sALL_DEPEND;
|
|
string_t sPTF_UPDATE;
|
|
string_t sPTF_UPDATE_ALL;
|
|
string_t sTDPATH;
|
|
string_t sTDPATH_ALL;
|
|
string_t sNULL;
|
|
string_t sDOT;
|
|
string_t sTARGET;
|
|
string_t sOODATE;
|
|
string_t sALLSRC;
|
|
string_t sIMPSRC;
|
|
string_t sPREFIX;
|
|
string_t sARCHIVE;
|
|
string_t sMEMBER;
|
|
string_t s_TARGET;
|
|
string_t s_OODATE;
|
|
string_t s_ALLSRC;
|
|
string_t s_IMPSRC;
|
|
string_t s_PREFIX;
|
|
string_t s_ARCHIVE;
|
|
string_t s_MEMBER;
|
|
string_t s_TARGETS;
|
|
string_t s_INCLUDES;
|
|
string_t s_LIBS;
|
|
string_t sMAKE;
|
|
string_t sMAKEFLAGS;
|
|
string_t sMFLAGS;
|
|
string_t sMACHINE;
|
|
string_t sNPROC;
|
|
string_t sVPATH;
|
|
string_t sMAKEFILE;
|
|
string_t sLIBSUFF;
|
|
string_t sMAKEOBJDIR;
|
|
string_t sMAKESRCDIRPATH;
|
|
string_t sMAKEDIR;
|
|
string_t sMAKETOP;
|
|
string_t sMAKESUB;
|
|
string_t s_DEFAULT;
|
|
string_t s_INTERRUPT;
|
|
string_t s_BEGIN;
|
|
string_t s_END;
|
|
string_t s_ERROR;
|
|
string_t s_EXIT;
|
|
|
|
const char *progname = "make";
|
|
|
|
Lst create; /* Targets to be made */
|
|
time_t now; /* Time at start of make */
|
|
GNode *DEFAULT; /* .DEFAULT node */
|
|
Boolean allPrecious; /* .PRECIOUS given on line by itself */
|
|
|
|
static Boolean noBuiltins; /* -r flag */
|
|
static Lst makefiles; /* ordered list of makefiles to read */
|
|
int maxJobs; /* -J argument */
|
|
static int maxLocal; /* -L argument */
|
|
Boolean debug; /* -d flag */
|
|
Boolean noExecute; /* -n flag */
|
|
Boolean keepgoing; /* -k flag */
|
|
Boolean queryFlag; /* -q flag */
|
|
Boolean touchFlag; /* -t flag */
|
|
Boolean ignoreErrors; /* -i flag */
|
|
Boolean beSilent; /* -s flag */
|
|
Boolean oldVars; /* variable substitution style */
|
|
Boolean checkEnvFirst; /* -e flag */
|
|
Boolean noisy; /* -N flag */
|
|
static Boolean jobsRunning; /* TRUE if the jobs might be running */
|
|
|
|
static char _MAKECONF[] = "_MAKECONF";
|
|
static char _MAKECWD[] = "_MAKECWD";
|
|
static char _MAKEPSD[] = "_MAKEPSD";
|
|
static char _MAKEIOD[] = "_MAKEIOD";
|
|
|
|
static Boolean ReadMakefile(const char *, Boolean);
|
|
static int ReadMakefileP(ClientData, ClientData);
|
|
static void usage(void);
|
|
|
|
static void MakeSetWorkingDir(const char *);
|
|
static void plainmake(char *, const char *);
|
|
static void movedmake(char *, char *, char *);
|
|
static void setpathvars(const char *);
|
|
static void confmove(char *, char *, char *);
|
|
static void fixvar(Lst, char *, char *);
|
|
static void reldir(char *, string_t, Lst);
|
|
static void makechdir(string_t, char *, Lst);
|
|
static int didchdir(void);
|
|
static void makepath(const char *, const char *);
|
|
static void rdircat(char *, char *, Buffer);
|
|
static void ptol(const char *, Lst *);
|
|
static void ltop(Lst, Buffer);
|
|
static void ui_print_revision(void);
|
|
|
|
#ifdef BAD_STRDUP_DECL
|
|
char *strdup2 ( char * str)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/*-
|
|
* MainParseArgs --
|
|
* Parse a given argument vector. Called from main() and from
|
|
* Main_ParseArgLine() when the MAKEFLAGS target is used.
|
|
*
|
|
* XXX: Deal with command line overriding MAKEFLAGS in makefile
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* Various global and local flags will be set depending on the flags
|
|
* given
|
|
*/
|
|
static void
|
|
MainParseArgs(int argc, char **argv)
|
|
{
|
|
int c;
|
|
string_t argstr;
|
|
|
|
optind = 1; /* since we're called more than once */
|
|
rearg: while((c = getopt(argc, argv, "D:I:L:NPSd:ef:ij:knqrstv")) != EOF) {
|
|
switch(c) {
|
|
case 'D':
|
|
argstr = string_create(optarg);
|
|
Var_Set(argstr, string_create("1"), VAR_GLOBAL);
|
|
Var_Append(sMAKEFLAGS, string_create("-D"),
|
|
VAR_GLOBAL);
|
|
Var_Append(sMAKEFLAGS, argstr, VAR_GLOBAL);
|
|
string_deref(argstr);
|
|
break;
|
|
case 'I':
|
|
argstr = string_create(optarg);
|
|
Parse_AddIncludeDir(argstr);
|
|
Var_Append(sMAKEFLAGS, string_create("-I"),
|
|
VAR_GLOBAL);
|
|
Var_Append(sMAKEFLAGS, argstr, VAR_GLOBAL);
|
|
string_deref(argstr);
|
|
break;
|
|
case 'L':
|
|
maxLocal = atoi(optarg);
|
|
Var_Append(sMAKEFLAGS, string_create("-L"),
|
|
VAR_GLOBAL);
|
|
argstr = string_create(optarg);
|
|
Var_Append(sMAKEFLAGS, argstr, VAR_GLOBAL);
|
|
string_deref(argstr);
|
|
break;
|
|
case 'N':
|
|
noisy = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-N"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'S':
|
|
keepgoing = FALSE;
|
|
Var_Append(sMAKEFLAGS, string_create("-S"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'd': {
|
|
char *modules = optarg;
|
|
|
|
for (; *modules; ++modules)
|
|
switch (*modules) {
|
|
case 'A':
|
|
debug = ~0;
|
|
break;
|
|
case 'a':
|
|
debug |= DEBUG_ARCH;
|
|
break;
|
|
case 'c':
|
|
debug |= DEBUG_COND;
|
|
break;
|
|
case 'd':
|
|
debug |= DEBUG_DIR;
|
|
break;
|
|
case 'g':
|
|
if (modules[1] == '1') {
|
|
debug |= DEBUG_GRAPH1;
|
|
++modules;
|
|
}
|
|
else if (modules[1] == '2') {
|
|
debug |= DEBUG_GRAPH2;
|
|
++modules;
|
|
}
|
|
break;
|
|
case 'j':
|
|
debug |= DEBUG_JOB;
|
|
break;
|
|
case 'm':
|
|
debug |= DEBUG_MAKE;
|
|
break;
|
|
case 's':
|
|
debug |= DEBUG_SUFF;
|
|
break;
|
|
case 't':
|
|
debug |= DEBUG_TARG;
|
|
break;
|
|
case 'v':
|
|
debug |= DEBUG_VAR;
|
|
break;
|
|
}
|
|
Var_Append(sMAKEFLAGS, string_create("-d"),
|
|
VAR_GLOBAL);
|
|
argstr = string_create(optarg);
|
|
Var_Append(sMAKEFLAGS, argstr, VAR_GLOBAL);
|
|
string_deref(argstr);
|
|
break;
|
|
}
|
|
case 'e':
|
|
checkEnvFirst = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-e"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'f':
|
|
(void)Lst_AtEnd(makefiles, (ClientData)optarg);
|
|
break;
|
|
case 'i':
|
|
ignoreErrors = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-i"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'j':
|
|
maxJobs = atoi(optarg);
|
|
Var_Append(sMAKEFLAGS, string_create("-j"),
|
|
VAR_GLOBAL);
|
|
argstr = string_create(optarg);
|
|
Var_Append(sMAKEFLAGS, argstr, VAR_GLOBAL);
|
|
string_deref(argstr);
|
|
break;
|
|
case 'k':
|
|
keepgoing = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-k"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'n':
|
|
noExecute = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-n"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'q':
|
|
queryFlag = TRUE;
|
|
/* Kind of nonsensical, wot? */
|
|
Var_Append(sMAKEFLAGS, string_create("-q"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'r':
|
|
noBuiltins = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-r"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 's':
|
|
beSilent = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-s"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 't':
|
|
touchFlag = TRUE;
|
|
Var_Append(sMAKEFLAGS, string_create("-t"),
|
|
VAR_GLOBAL);
|
|
break;
|
|
case 'v':
|
|
ui_print_revision();
|
|
exit(2);
|
|
default:
|
|
case '?':
|
|
usage();
|
|
}
|
|
}
|
|
|
|
oldVars = TRUE;
|
|
|
|
/*
|
|
* See if the rest of the arguments are variable assignments and
|
|
* perform them if so. Else take them to be targets and stuff them
|
|
* on the end of the "create" list.
|
|
*/
|
|
for (argv += optind, argc -= optind; *argv; ++argv, --argc)
|
|
if (Parse_DoVar(*argv, VAR_CMD) != 0) {
|
|
if (!**argv)
|
|
Punt("illegal (null) argument.");
|
|
if (**argv == '-') {
|
|
optind = 0;
|
|
goto rearg;
|
|
}
|
|
(void)Lst_AtEnd(create,
|
|
(ClientData)string_create(*argv));
|
|
}
|
|
}
|
|
|
|
/*-
|
|
* Main_ParseArgLine --
|
|
* Used by the parse module when a .MFLAGS or MAKEFLAGS target
|
|
* is encountered and by main() when reading the MAKEFLAGS envariable.
|
|
* Takes a line of arguments and breaks it into its
|
|
* component words and passes those words and the number of them to the
|
|
* MainParseArgs function.
|
|
* The line should have all its leading whitespace removed.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* Only those that come from the various arguments.
|
|
*/
|
|
void
|
|
Main_ParseArgLine(char *line) /* Line to fracture */
|
|
{
|
|
char **argv; /* Manufactured argument vector */
|
|
int argc; /* Number of arguments in argv */
|
|
|
|
if (line == NULL)
|
|
return;
|
|
for (; *line == ' '; ++line);
|
|
if (!*line)
|
|
return;
|
|
|
|
argv = brk_string(line, &argc);
|
|
MainParseArgs(argc, argv);
|
|
}
|
|
|
|
/*-
|
|
* main --
|
|
* The main function, for obvious reasons. Initializes variables
|
|
* and a few modules, then parses the arguments give it in the
|
|
* environment and on the command line. Reads the system makefile
|
|
* followed by either Makefile, makefile or the file given by the
|
|
* -f argument. Sets the MAKEFLAGS PMake variable based on all the
|
|
* flags it has received by then uses either the Make or the Compat
|
|
* module to create the initial list of targets.
|
|
*
|
|
* Results:
|
|
* If -q was given, exits -1 if anything was out-of-date. Else it exits
|
|
* 0.
|
|
*
|
|
* Side Effects:
|
|
* The program exits when done. Targets are created. etc. etc. etc.
|
|
*/
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
Lst targs; /* target nodes to create -- passed to Make_Init */
|
|
Boolean outOfDate; /* FALSE if all targets up to date */
|
|
Boolean hadErrors; /* TRUE if we had errors */
|
|
const char *p;
|
|
|
|
create = Lst_Init();
|
|
makefiles = Lst_Init();
|
|
beSilent = FALSE; /* Print commands as executed */
|
|
ignoreErrors = FALSE; /* Pay attention to non-zero returns */
|
|
noExecute = FALSE; /* Execute all commands */
|
|
keepgoing = FALSE; /* Stop on error */
|
|
allPrecious = FALSE; /* Remove targets when interrupted */
|
|
queryFlag = FALSE; /* This is not just a check-run */
|
|
noBuiltins = FALSE; /* Read the built-in rules */
|
|
touchFlag = FALSE; /* Actually update targets */
|
|
debug = 0; /* No debug verbosity, please. */
|
|
jobsRunning = FALSE;
|
|
noisy = FALSE;
|
|
|
|
maxJobs = 0; /* Set default max concurrency */
|
|
maxLocal = -1; /* Set default local max concurrency */
|
|
|
|
/*
|
|
* create internal commonly used strings
|
|
*/
|
|
string_init();
|
|
|
|
sNULL = string_create("");
|
|
sDOT = string_create(".");
|
|
|
|
sTARGET = string_create("@");
|
|
sOODATE = string_create("?");
|
|
sALLSRC = string_create(">");
|
|
sIMPSRC = string_create("<");
|
|
sPREFIX = string_create("*");
|
|
sARCHIVE = string_create("!");
|
|
sMEMBER = string_create("%");
|
|
|
|
s_TARGET = string_create(".TARGET");
|
|
s_OODATE = string_create(".OODATE");
|
|
s_ALLSRC = string_create(".ALLSRC");
|
|
s_IMPSRC = string_create(".IMPSRC");
|
|
s_PREFIX = string_create(".PREFIX");
|
|
s_ARCHIVE = string_create(".ARCHIVE");
|
|
s_MEMBER = string_create(".MEMBER");
|
|
|
|
s_TARGETS = string_create(".TARGETS");
|
|
s_INCLUDES = string_create(".INCLUDES");
|
|
s_LIBS = string_create(".LIBS");
|
|
|
|
sMAKE = string_create("MAKE");
|
|
sMAKEFLAGS = string_create("MAKEFLAGS");
|
|
sMFLAGS = string_create("MFLAGS");
|
|
sMACHINE = string_create("MACHINE");
|
|
sNPROC = string_create("NPROC");
|
|
sVPATH = string_create("VPATH");
|
|
sMAKEFILE = string_create("MAKEFILE");
|
|
sLIBSUFF = string_create(LIBSUFF);
|
|
|
|
sMAKEOBJDIR = string_create("MAKEOBJDIR");
|
|
sMAKESRCDIRPATH = string_create("MAKESRCDIRPATH");
|
|
sMAKEDIR = string_create("MAKEDIR");
|
|
sMAKETOP = string_create("MAKETOP");
|
|
sMAKESUB = string_create("MAKESUB");
|
|
|
|
s_DEFAULT = string_create(".DEFAULT");
|
|
s_INTERRUPT = string_create(".INTERRUPT");
|
|
s_BEGIN = string_create(".BEGIN");
|
|
s_END = string_create(".END");
|
|
s_ERROR = string_create(".ERROR");
|
|
s_EXIT = string_create(".EXIT");
|
|
|
|
sALL_DEPEND = string_create("ALL_DEPEND");
|
|
sPTF_UPDATE = string_create("PTF_UPDATE");
|
|
sPTF_UPDATE_ALL = string_create("PTF_UPDATE_ALL");
|
|
sTDPATH = string_create("TDPATH");
|
|
sTDPATH_ALL = string_create("TDPATH_ALL");
|
|
|
|
/*
|
|
* Initialize the parsing, directory and variable modules to prepare
|
|
* for the reading of inclusion paths and variable settings on the
|
|
* command line
|
|
*/
|
|
Dir_Init(); /* Initialize directory structures so -I flags
|
|
* can be processed correctly */
|
|
Parse_Init(); /* Need to initialize the paths of #include
|
|
* directories */
|
|
Var_Init(); /* As well as the lists of variables for
|
|
* parsing arguments */
|
|
|
|
/*
|
|
* Initialize various variables.
|
|
* MAKE also gets this name, for compatibility
|
|
* MAKEFLAGS gets set to the empty string just in case.
|
|
* MFLAGS also gets initialized empty, for compatibility.
|
|
*/
|
|
Var_Set(sMAKE, string_create(argv[0]), VAR_GLOBAL);
|
|
Var_Set(sMAKEFLAGS, sNULL, VAR_GLOBAL);
|
|
Var_Set(sMFLAGS, sNULL, VAR_GLOBAL);
|
|
Var_Set(sMACHINE, string_create(MACHINE), VAR_GLOBAL);
|
|
Var_Set(sNPROC, string_create((p = getenv("NPROC")) ? p : "1"),
|
|
VAR_GLOBAL);
|
|
|
|
/*
|
|
* First snag any flags out of the MAKE environment variable.
|
|
* (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
|
|
* in a different format).
|
|
*/
|
|
Main_ParseArgLine(getenv("MAKEFLAGS"));
|
|
|
|
MainParseArgs(argc, argv);
|
|
|
|
Cond_Setup();
|
|
|
|
/*
|
|
* Now make sure that maxJobs and maxLocal are positive. If
|
|
* not, use the value of NPROC (or 1 if NPROC is not positive)
|
|
*/
|
|
{
|
|
int nproc = atoi(Var_Value(sNPROC, VAR_GLOBAL));
|
|
|
|
if (nproc < 1)
|
|
nproc = 1;
|
|
if (maxJobs < 1)
|
|
maxJobs = nproc;
|
|
}
|
|
|
|
/*
|
|
* Initialize archive, target and suffix modules in preparation for
|
|
* parsing the makefile(s)
|
|
*/
|
|
Arch_Init();
|
|
Targ_Init();
|
|
Suff_Init();
|
|
|
|
DEFAULT = NILGNODE;
|
|
(void)time(&now);
|
|
|
|
/*
|
|
* Set up the .TARGETS variable to contain the list of targets to be
|
|
* created. If none specified, make the variable empty -- the parser
|
|
* will fill the thing in with the default or .MAIN target.
|
|
*/
|
|
if (!Lst_IsEmpty(create)) {
|
|
LstNode ln;
|
|
|
|
for (ln = Lst_First(create); ln != NILLNODE;
|
|
ln = Lst_Succ(ln)) {
|
|
string_t name = (string_t)Lst_Datum(ln);
|
|
|
|
Var_Append(s_TARGETS, name, VAR_GLOBAL);
|
|
}
|
|
} else
|
|
Var_Set(s_TARGETS, sNULL, VAR_GLOBAL);
|
|
|
|
/*
|
|
* Locate the correct working directory for make. Adjust for any
|
|
* movement taken from the directory of our parent if we are a
|
|
* sub-make.
|
|
*/
|
|
MakeSetWorkingDir("Makeconf");
|
|
|
|
/*
|
|
* Read in the built-in rules first, followed by the specified
|
|
* makefile, if it was (makefile != (char *) NULL), or the default
|
|
* Makefile and makefile, in that order, if it wasn't.
|
|
*/
|
|
if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK, TRUE))
|
|
Fatal("make: no system rules (%s).", _PATH_DEFSYSMK);
|
|
|
|
if (!Lst_IsEmpty(makefiles)) {
|
|
LstNode ln;
|
|
|
|
ln = Lst_Find(makefiles, (ClientData)FALSE, ReadMakefileP);
|
|
if (ln != NILLNODE)
|
|
Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
|
|
} else if (!ReadMakefile("makefile", FALSE))
|
|
(void)ReadMakefile("Makefile", FALSE);
|
|
|
|
Var_Append(sMFLAGS, Var_StrValue(sMAKEFLAGS, VAR_GLOBAL), VAR_GLOBAL);
|
|
|
|
/* Install all the flags into the MAKEFLAGS envariable. */
|
|
if ((p = Var_Value(sMAKEFLAGS, VAR_GLOBAL)) && *p)
|
|
setenv("MAKEFLAGS", p, 1);
|
|
|
|
/*
|
|
* For compatibility, look at the directories in the VPATH variable
|
|
* and add them to the search path, if the variable is defined. The
|
|
* variable's value is in the same format as the PATH envariable, i.e.
|
|
* <directory>:<directory>:<directory>...
|
|
*/
|
|
if (Var_Exists(sVPATH, VAR_CMD)) {
|
|
char *vpath, *path, *cp, savec;
|
|
/*
|
|
* GCC stores string constants in read-only memory, but
|
|
* Var_Subst will want to write this thing, so store it
|
|
* in an array
|
|
*/
|
|
static char VPATH[] = "${VPATH}";
|
|
|
|
vpath = Var_Subst(VPATH, VAR_CMD, FALSE);
|
|
path = vpath;
|
|
do {
|
|
/* skip to end of directory */
|
|
for (cp = path; *cp != ':' && *cp != '\0'; cp++);
|
|
/* Save terminator character so know when to stop */
|
|
savec = *cp;
|
|
*cp = '\0';
|
|
/* Add directory to search path */
|
|
Dir_AddDir(dirSearchPath, string_create(path));
|
|
*cp = savec;
|
|
path = cp + 1;
|
|
} while (savec == ':');
|
|
(void)free((Address)vpath);
|
|
}
|
|
|
|
/*
|
|
* Now that all search paths have been read for suffixes et al, it's
|
|
* time to add the default search path to their lists...
|
|
*/
|
|
Suff_DoPaths();
|
|
|
|
/* print the initial graph, if the user requested it */
|
|
if (DEBUG(GRAPH1))
|
|
Targ_PrintGraph(1);
|
|
|
|
/*
|
|
* Have now read the entire graph and need to make a list of targets
|
|
* to create. If none was given on the command line, we consult the
|
|
* parsing module to find the main target(s) to create.
|
|
*/
|
|
if (Lst_IsEmpty(create))
|
|
targs = Parse_MainName();
|
|
else
|
|
targs = Targ_FindList(create, TARG_CREATE);
|
|
|
|
/*
|
|
* Initialize job module before traversing the graph, now that
|
|
* any .BEGIN and .END targets have been read. This is done
|
|
* only if the -q flag wasn't given (to prevent the .BEGIN from
|
|
* being executed should it exist).
|
|
*/
|
|
if (!queryFlag) {
|
|
if (maxLocal < 0 || maxLocal > maxJobs)
|
|
maxLocal = maxJobs;
|
|
Job_Init(maxJobs, maxLocal);
|
|
jobsRunning = TRUE;
|
|
}
|
|
|
|
/* Traverse the graph, checking on all the targets */
|
|
outOfDate = Make_Run(targs, &hadErrors);
|
|
|
|
/* print the graph now it's been processed if the user requested it */
|
|
if (DEBUG(GRAPH2))
|
|
Targ_PrintGraph(2);
|
|
|
|
/* print the target dependency file if PTF_UPDATE is set to yes */
|
|
/* prints only the dependencies that were out of date */
|
|
if (strcmp(Var_Value(sPTF_UPDATE, VAR_GLOBAL), "yes") == 0)
|
|
Targ_PrintTargDep(2);
|
|
|
|
/* print all dependencies for every target if PTF_UPDATE_ALL=yes */
|
|
if (strcmp(Var_Value(sPTF_UPDATE_ALL, VAR_GLOBAL), "yes") == 0)
|
|
Targ_PrintAllTargDep(2);
|
|
|
|
return (hadErrors || (queryFlag && outOfDate));
|
|
}
|
|
|
|
/*-
|
|
* ReadMakefile --
|
|
* Open and parse the given makefile.
|
|
*
|
|
* Results:
|
|
* TRUE if ok. FALSE if couldn't open file.
|
|
*
|
|
* Side Effects:
|
|
* lots
|
|
*/
|
|
static int
|
|
ReadMakefileP(
|
|
ClientData fname, /* makefile to read */
|
|
ClientData isSystem) /* system makefile */
|
|
{
|
|
return(ReadMakefile((char *)fname, (Boolean)isSystem));
|
|
}
|
|
|
|
static Boolean
|
|
ReadMakefile(
|
|
const char *fname, /* makefile to read */
|
|
Boolean isSystem) /* system makefile */
|
|
{
|
|
FILE *stream;
|
|
string_t name;
|
|
|
|
if (!strcmp(fname, "-")) {
|
|
Var_Set(sMAKEFILE, sNULL, VAR_GLOBAL);
|
|
Parse_File(string_create("(stdin)"), stdin);
|
|
} else {
|
|
string_t sfname = string_create(fname);
|
|
if (!isSystem) {
|
|
name = Dir_FindFile(sfname, dirSearchPath);
|
|
} else {
|
|
name = Dir_FindFile(sfname, parseIncPath);
|
|
if (name == (string_t) NULL)
|
|
name = Dir_FindFile(sfname, sysIncPath);
|
|
}
|
|
string_deref(sfname);
|
|
if (name == (string_t) NULL ||
|
|
(stream = fopen(name->data, "r")) == NULL)
|
|
return(FALSE);
|
|
/*
|
|
* set the MAKEFILE variable desired by System V fans -- the
|
|
* placement of the setting here means it gets set to the last
|
|
* makefile specified, as it is set by SysV make.
|
|
*/
|
|
Var_Set(sMAKEFILE, name, VAR_GLOBAL);
|
|
Parse_File(name, stream);
|
|
(void)fclose(stream);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/*-
|
|
* Error --
|
|
* Print an error message given its format.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* The message is printed.
|
|
*/
|
|
void
|
|
Error(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
(void)vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
(void)fprintf(stderr, "\n");
|
|
(void)fflush(stderr);
|
|
}
|
|
|
|
/*-
|
|
* Fatal --
|
|
* Produce a Fatal error message. If jobs are running, waits for them
|
|
* to finish.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* The program exits
|
|
*/
|
|
void
|
|
Fatal(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (jobsRunning)
|
|
Job_Wait();
|
|
|
|
va_start(ap, fmt);
|
|
(void)vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
(void)fprintf(stderr, "\n");
|
|
(void)fflush(stderr);
|
|
|
|
if (DEBUG(GRAPH2))
|
|
Targ_PrintGraph(2);
|
|
exit(2); /* Not 1 so -q can distinguish error */
|
|
}
|
|
|
|
/*
|
|
* Punt --
|
|
* Major exception once jobs are being created. Kills all jobs, prints
|
|
* a message and exits.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* All children are killed indiscriminately and the program Lib_Exits
|
|
*/
|
|
void
|
|
Punt(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
(void)fprintf(stderr, "make: ");
|
|
va_start(ap, fmt);
|
|
(void)vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
(void)fprintf(stderr, "\n");
|
|
(void)fflush(stderr);
|
|
|
|
DieHorribly();
|
|
}
|
|
|
|
/*-
|
|
* DieHorribly --
|
|
* Exit without giving a message.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* A big one...
|
|
*/
|
|
void
|
|
DieHorribly(void)
|
|
{
|
|
if (jobsRunning)
|
|
Job_AbortAll();
|
|
if (DEBUG(GRAPH2))
|
|
Targ_PrintGraph(2);
|
|
exit(2); /* Not 1, so -q can distinguish error */
|
|
}
|
|
|
|
/*
|
|
* Finish --
|
|
* Called when aborting due to errors in child shell to signal
|
|
* abnormal exit.
|
|
*
|
|
* Results:
|
|
* None
|
|
*
|
|
* Side Effects:
|
|
* The program exits
|
|
*/
|
|
void
|
|
Finish(int errors) /* number of errors encountered in Make_Make */
|
|
{
|
|
Fatal("%d error%s", errors, errors == 1 ? "" : "s");
|
|
}
|
|
|
|
/*
|
|
* emalloc --
|
|
* malloc, but die on error.
|
|
*/
|
|
char *
|
|
emalloc(u_int len)
|
|
{
|
|
char *p;
|
|
|
|
if (!(p = (char *)malloc(len)))
|
|
enomem();
|
|
return(p);
|
|
}
|
|
|
|
/*
|
|
* enomem --
|
|
* die when out of memory.
|
|
*/
|
|
void
|
|
enomem(void)
|
|
{
|
|
(void)fprintf(stderr, "make: %s.\n", strerror(errno));
|
|
exit(2);
|
|
}
|
|
|
|
/*
|
|
* usage --
|
|
* exit with usage message
|
|
*/
|
|
void
|
|
usage(void)
|
|
{
|
|
(void)fprintf(stderr,
|
|
"usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile ]\n\t\
|
|
[-I directory] [-j max_jobs] [variable=value]\n");
|
|
exit(2);
|
|
}
|
|
|
|
static void
|
|
MakeSetWorkingDir(const char *cf)
|
|
{
|
|
char *owd, *psd, cwd[PATH_MAX+1];
|
|
|
|
if (getcwd(cwd, sizeof(cwd)) == 0 || *cwd != '/')
|
|
Fatal("getwd: %s", strerror(errno));
|
|
if ((owd = getenv(_MAKECWD)) && (psd = getenv(_MAKEPSD))) {
|
|
if (*owd != '/')
|
|
Fatal("make: bad %s environment variable", _MAKECWD);
|
|
if (*psd == '\0')
|
|
Fatal("make: bad %s environment variable", _MAKEPSD);
|
|
movedmake(cwd, owd, psd);
|
|
} else
|
|
plainmake(cwd, cf);
|
|
}
|
|
|
|
/*
|
|
* find and read the configuration file and move
|
|
* to the object tree
|
|
*/
|
|
static void
|
|
plainmake(char *cwd, const char *cf)
|
|
{
|
|
register char *d, *p, *q;
|
|
int n;
|
|
char *pname;
|
|
struct stat sb;
|
|
|
|
pname = q = NULL;
|
|
if (stat(cf, &sb) == 0) {
|
|
pname = strdup(cf);
|
|
} else if (cwd[1] != '\0') {
|
|
n = 0;
|
|
for (p = cwd; *p != '\0'; p++)
|
|
if (*p == '/')
|
|
n++;
|
|
p = d = emalloc((n * 3) + strlen(cf) + 1);
|
|
q = cwd;
|
|
while (*q != '\0')
|
|
if (*q++ == '/') {
|
|
*p++ = '.';
|
|
*p++ = '.';
|
|
*p++ = '/';
|
|
}
|
|
(void) strcpy(p, cf);
|
|
q = p;
|
|
for (;;) {
|
|
q -= 3;
|
|
if (stat(q, &sb) == 0) {
|
|
pname = strdup(q);
|
|
*p = '\0';
|
|
break;
|
|
}
|
|
if (q == d) {
|
|
q = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
confmove(cwd, pname, q);
|
|
}
|
|
|
|
/*
|
|
* we may have changed directories, so we calulate possible difference
|
|
*/
|
|
static void
|
|
movedmake(char *cwd, char *owd, char *psd)
|
|
{
|
|
register char *p, *q, *r, *s;
|
|
char *ep;
|
|
struct stat sb;
|
|
int cnt;
|
|
Lst newsd;
|
|
LstNode ln;
|
|
string_t str;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
/*
|
|
* Locate the difference between the current working directory
|
|
* and the previous working directory.
|
|
*/
|
|
for (p = r = owd, q = s = cwd; *r && *r == *s; r++, s++)
|
|
if (*r == '/') {
|
|
while (*(r+1) == '/')
|
|
r++;
|
|
while (*(s+1) == '/')
|
|
s++;
|
|
p = r + 1;
|
|
q = s + 1;
|
|
}
|
|
if (*r == 0 && *s == 0) {
|
|
p = r;
|
|
q = s;
|
|
} else if (*r == '/' && *s == 0) {
|
|
while (*++r && *r == '/')
|
|
;
|
|
p = r;
|
|
q = s;
|
|
} else if (*r == 0 && *s == '/') {
|
|
p = r;
|
|
while (*++s && *s == '/')
|
|
;
|
|
q = s;
|
|
}
|
|
|
|
ptol(psd, &newsd);
|
|
Lst_Open(newsd);
|
|
while ((ln = Lst_Next(newsd)) != NILLNODE) {
|
|
s = (char *) Lst_Datum(ln);
|
|
if (*s != '/') {
|
|
rdircat(q, p, buf);
|
|
cnt = Buf_Size(buf);
|
|
if (cnt != 0) {
|
|
r = (char *)Buf_GetBase(buf);
|
|
if (r[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
}
|
|
Buf_AddBytes(buf, strlen(s), (Byte *)s);
|
|
if ((*p || *q) && *s && (cnt = Buf_Size(buf)) != 0) {
|
|
r = (char *)Buf_GetBase(buf);
|
|
if (r[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
rdircat(p, q, buf);
|
|
str = string_create((char *)Buf_GetBase(buf));
|
|
str = string_flatten(str);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
Lst_Replace(ln, (ClientData)strdup(str->data));
|
|
}
|
|
Lst_Close(newsd);
|
|
if ((ep = getenv(sMAKEDIR->data))) {
|
|
while (*ep == '/')
|
|
ep++;
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
Buf_AddBytes(buf, strlen(ep), (Byte *)ep);
|
|
if (*p || *q) {
|
|
cnt = Buf_Size(buf);
|
|
r = (char *)Buf_GetBase(buf);
|
|
if (r[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
} else
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
rdircat(p, q, buf);
|
|
str = string_create((char *)Buf_GetBase(buf));
|
|
str = string_flatten(str);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
setenv(sMAKEDIR->data, str->data, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", sMAKEDIR->data, str->data);
|
|
}
|
|
setpathvars(str->data);
|
|
if ((ep = getenv(_MAKECONF))) {
|
|
if (stat(ep, &sb) == 0)
|
|
(void) ReadMakefile(ep, FALSE);
|
|
}
|
|
if (!didchdir())
|
|
Var_Delete(sMAKEOBJDIR, VAR_GLOBAL);
|
|
setenv(_MAKECWD, cwd, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", _MAKECWD, cwd);
|
|
}
|
|
ltop(newsd, buf);
|
|
r = (char *)Buf_GetBase(buf);
|
|
setenv(_MAKEPSD, r, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", _MAKEPSD, r);
|
|
}
|
|
Buf_Destroy(buf);
|
|
Dir_ReInit(newsd);
|
|
Lst_Destroy(newsd, free);
|
|
}
|
|
|
|
static void
|
|
setpathvars(const char *dir)
|
|
{
|
|
register const char *p, *q;
|
|
int cnt;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
Var_Set(sMAKEDIR, string_create(dir), VAR_GLOBAL);
|
|
while (*dir == '/')
|
|
dir++;
|
|
q = dir;
|
|
while (*q) {
|
|
if (*q == '.' && strncmp(q, "../", 3) == 0)
|
|
Fatal("%s: bad MAKEDIR", dir);
|
|
if (*q++ == '/') {
|
|
while (*q == '/')
|
|
q++;
|
|
} else {
|
|
Buf_AddBytes(buf, 3, (Byte *)"../");
|
|
while (*q && *q != '/')
|
|
q++;
|
|
}
|
|
}
|
|
p = (char *)Buf_GetBase(buf);
|
|
Var_Set(sMAKETOP, string_create(p), VAR_GLOBAL);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
Buf_AddBytes(buf, strlen(dir), (Byte *)dir);
|
|
if ((cnt = Buf_Size(buf)) != 0) {
|
|
p = (char *)Buf_GetBase(buf);
|
|
if (p[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
p = (char *)Buf_GetBase(buf);
|
|
Var_Set(sMAKESUB, string_create(p), VAR_GLOBAL);
|
|
Buf_Destroy(buf);
|
|
}
|
|
|
|
static void
|
|
confmove(char *cwd, char *cf, char *pre)
|
|
{
|
|
register char *src, *r;
|
|
register const char *vp;
|
|
char *suf;
|
|
int cnt;
|
|
struct stat sb;
|
|
Lst newsd;
|
|
string_t str, obj;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
if (pre && *pre) {
|
|
suf = cwd + strlen(cwd);
|
|
for (r = pre;
|
|
*r == '.' && *(r+1) == '.' && *(r+2) == '/';
|
|
r += 3) {
|
|
while (*(suf-1) == '/')
|
|
suf--;
|
|
if (suf == cwd || suf == cwd + 1) {
|
|
suf = 0;
|
|
break;
|
|
}
|
|
while (*(suf-1) != '/')
|
|
suf--;
|
|
}
|
|
if (suf && *suf) {
|
|
suf = strdup(suf);
|
|
Buf_AddBytes(buf, strlen(suf), (Byte *)suf);
|
|
} else
|
|
suf = 0;
|
|
} else {
|
|
pre = 0;
|
|
suf = 0;
|
|
}
|
|
src = (char *)Buf_GetBase(buf);
|
|
setenv(sMAKEDIR->data, src, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", sMAKEDIR->data, src);
|
|
}
|
|
setpathvars(src);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
if (cf) {
|
|
if (*cf != '/') {
|
|
Buf_AddBytes(buf, strlen(cwd), (Byte *)cwd);
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
Buf_AddBytes(buf, strlen(cf), (Byte *)cf);
|
|
str = string_create((char *)Buf_GetBase(buf));
|
|
str = string_flatten(str);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
setenv(_MAKECONF, str->data, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", _MAKECONF, str->data);
|
|
}
|
|
Var_Set(string_create(_MAKECONF), str, VAR_GLOBAL);
|
|
(void) ReadMakefile(str->data, FALSE);
|
|
}
|
|
obj = (string_t) NULL;
|
|
if ((vp = Var_Value(sMAKEOBJDIR, VAR_GLOBAL))) {
|
|
if (strchr (vp, '$') != (char *)NULL)
|
|
vp = Var_Subst(vp, VAR_GLOBAL, FALSE);
|
|
else
|
|
vp = strdup(vp);
|
|
if (DEBUG(VAR)) {
|
|
printf("< %s=%s\n", sMAKEOBJDIR->data, vp);
|
|
}
|
|
if (strchr(vp, ':'))
|
|
Fatal("%s: only one component allowed",
|
|
sMAKEOBJDIR->data);
|
|
if (*vp == '\0') {
|
|
Var_Delete(sMAKEOBJDIR, VAR_GLOBAL);
|
|
} else {
|
|
if (*vp != '/' && pre)
|
|
Buf_AddBytes(buf, strlen(pre), (Byte *)pre);
|
|
Buf_AddBytes(buf, strlen(vp), (Byte *)vp);
|
|
r = (char *)Buf_GetBase(buf);
|
|
if (stat(r, &sb) < 0)
|
|
Fatal("No such directory: %s", r);
|
|
if (suf) {
|
|
cnt = Buf_Size(buf);
|
|
if (cnt != 0 && r[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
Buf_AddBytes(buf, strlen(suf), (Byte *)suf);
|
|
}
|
|
obj = string_create((char *)Buf_GetBase(buf));
|
|
obj = string_flatten(obj);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
if (DEBUG(VAR)) {
|
|
printf("> %s=%s\n", sMAKEOBJDIR->data,
|
|
obj->data);
|
|
}
|
|
}
|
|
}
|
|
if ((vp = Var_Value(sMAKESRCDIRPATH, VAR_GLOBAL))) {
|
|
if (strchr (vp, '$') != (char *)NULL)
|
|
vp = Var_Subst(vp, VAR_GLOBAL, FALSE);
|
|
else
|
|
vp = strdup(vp);
|
|
if (DEBUG(VAR)) {
|
|
printf("< %s=%s\n", sMAKESRCDIRPATH->data, vp);
|
|
}
|
|
if (*vp == '\0')
|
|
newsd = Lst_Init();
|
|
else {
|
|
ptol(vp, &newsd);
|
|
(void) fixvar(newsd, pre, suf);
|
|
if (DEBUG(VAR)) {
|
|
ltop(newsd, buf);
|
|
r = (char *)Buf_GetBase(buf);
|
|
printf("> %s=%s\n", sMAKESRCDIRPATH->data, r);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
}
|
|
}
|
|
} else
|
|
newsd = Lst_Init();
|
|
Buf_Destroy(buf);
|
|
Lst_AtFront(newsd, (ClientData) strdup("."));
|
|
if (obj || Lst_First(newsd) != Lst_Last(newsd))
|
|
reldir(cwd, obj, newsd);
|
|
Dir_ReInit(newsd);
|
|
Lst_Destroy(newsd, free);
|
|
}
|
|
|
|
static void
|
|
fixvar(Lst l, char *pre, char *suf)
|
|
{
|
|
register char *p;
|
|
int cnt;
|
|
LstNode ln;
|
|
string_t str;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
Lst_Open(l);
|
|
while ((ln = Lst_Next(l)) != NILLNODE) {
|
|
p = (char *) Lst_Datum(ln);
|
|
if (*p != '/' && pre)
|
|
Buf_AddBytes(buf, strlen(pre), (Byte *)pre);
|
|
Buf_AddBytes(buf, strlen(p), (Byte *)p);
|
|
if (suf) {
|
|
if ((cnt = Buf_Size(buf)) != 0) {
|
|
p = (char *)Buf_GetBase(buf);
|
|
if (p[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
Buf_AddBytes(buf, strlen(suf), (Byte *)suf);
|
|
}
|
|
str = string_create((char *)Buf_GetBase(buf));
|
|
str = string_flatten(str);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
Lst_Replace(ln, (ClientData)strdup(str->data));
|
|
}
|
|
Buf_Destroy(buf);
|
|
Lst_Close(l);
|
|
}
|
|
|
|
/*
|
|
* find names for the source directories after a
|
|
* chdir(obj) and use them to adjust search path
|
|
*/
|
|
static void
|
|
reldir(char *cwd, string_t obj, Lst newsd)
|
|
{
|
|
register char *h;
|
|
register const char *t, *tt;
|
|
register char *p, *q, *r;
|
|
char lastc;
|
|
char *twd;
|
|
int cnt;
|
|
LstNode ln;
|
|
string_t str;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
Lst_Open(newsd);
|
|
while ((ln = Lst_Next(newsd)) != NILLNODE) {
|
|
p = (char *) Lst_Datum(ln);
|
|
if (*p == '/' || obj == (string_t) NULL)
|
|
continue;
|
|
Buf_AddBytes(buf, strlen(cwd), (Byte *)cwd);
|
|
if (*obj->data == '/') {
|
|
r = (char *)Buf_GetBase(buf);
|
|
cnt = Buf_Size(buf);
|
|
if (r[cnt-1] != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
Buf_AddBytes(buf, strlen(p), (Byte *)p);
|
|
str = string_create((char *)Buf_GetBase(buf));
|
|
str = string_flatten(str);
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
Lst_Replace(ln, (ClientData)strdup(str->data));
|
|
continue;
|
|
}
|
|
r = (char *)Buf_GetBase(buf);
|
|
cnt = Buf_Size(buf);
|
|
twd = emalloc(cnt + obj->len + 2);
|
|
memcpy(twd, r, cnt + 1);
|
|
Buf_Discard(buf, cnt);
|
|
r = twd + cnt - 1;
|
|
lastc = '\0';
|
|
for (tt = t = obj->data; *tt; tt = t) {
|
|
while (*t && *t != '/')
|
|
t++;
|
|
if (t == tt + 1 && *tt == '.') {
|
|
while (*t == '/')
|
|
t++;
|
|
}
|
|
if (lastc != '\0') {
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
lastc = '/';
|
|
}
|
|
if (t == tt + 2 && *tt == '.' && *(tt+1) == '.') {
|
|
if (r == twd) {
|
|
if (lastc != '/')
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
break;
|
|
}
|
|
while (*r != '/') {
|
|
Buf_AddByte(buf, (Byte)*r);
|
|
lastc = *r--;
|
|
}
|
|
while (r != twd && *r == '/')
|
|
--r;
|
|
} else {
|
|
*++r = '/';
|
|
while (tt != t)
|
|
*++r = *tt++;
|
|
Buf_AddByte(buf, (Byte)'.');
|
|
Buf_AddByte(buf, (Byte)'.');
|
|
lastc = '.';
|
|
}
|
|
while (*t == '/')
|
|
t++;
|
|
}
|
|
(void)free(twd);
|
|
q = (char *)Buf_GetBase(buf);
|
|
cnt = Buf_Size(buf);
|
|
t = q + cnt - 1;
|
|
r = emalloc(cnt + strlen(p) + 2);
|
|
h = r;
|
|
while (cnt--) {
|
|
*h++ = *t--;
|
|
}
|
|
Buf_Discard(buf, Buf_Size(buf));
|
|
if (h != r && *(h-1) != '/')
|
|
*h++ = '/';
|
|
(void) strcpy(h, p);
|
|
str = string_create(r);
|
|
str = string_flatten(str);
|
|
free(r);
|
|
Lst_Replace(ln, (ClientData)strdup(str->data));
|
|
}
|
|
Buf_Destroy(buf);
|
|
Lst_Close(newsd);
|
|
makechdir(obj, cwd, newsd);
|
|
}
|
|
|
|
static void
|
|
makechdir(string_t obj, char *cwd, Lst newsd)
|
|
{
|
|
char wd[PATH_MAX+1];
|
|
char *p;
|
|
Buffer buf = Buf_Init(0);
|
|
|
|
if (obj != (string_t) NULL) {
|
|
makepath(obj->data, (char *)Lst_Datum(Lst_First(newsd)));
|
|
if (!beSilent)
|
|
printf("cd %s\n", obj->data);
|
|
if (chdir(obj->data) == -1)
|
|
Fatal("%s: %s", obj->data, strerror(errno));
|
|
Var_Set(string_create(".CURDIR"), string_create(cwd),
|
|
VAR_GLOBAL);
|
|
cwd = wd;
|
|
if (getcwd(wd, sizeof(wd)) == 0 || *cwd != '/')
|
|
Fatal("getwd: %s", strerror(errno));
|
|
setenv(_MAKEIOD, _MAKEIOD, 1);
|
|
} else
|
|
Var_Set(string_create(".CURDIR"), sDOT, VAR_GLOBAL);
|
|
setenv(_MAKECWD, cwd, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", _MAKECWD, cwd);
|
|
}
|
|
ltop(newsd, buf);
|
|
p = (char *)Buf_GetBase(buf);
|
|
setenv(_MAKEPSD, p, 1);
|
|
if (DEBUG(VAR)) {
|
|
printf("%s=%s\n", _MAKEPSD, p);
|
|
}
|
|
Buf_Destroy(buf);
|
|
}
|
|
|
|
static int
|
|
didchdir(void)
|
|
{
|
|
register char *p;
|
|
|
|
return (p = getenv(_MAKEIOD)) != 0 && strcmp(p, _MAKEIOD) == 0;
|
|
}
|
|
|
|
static void
|
|
makepath(const char *dir, const char *src)
|
|
{
|
|
register char *p, *q, *s, *r;
|
|
char *nsrc, *ndir;
|
|
register char c, c1;
|
|
int len;
|
|
struct stat sb;
|
|
string_t str;
|
|
|
|
len = strlen(src) + 1;
|
|
if (*src != '/')
|
|
len += strlen(dir) + 1;
|
|
p = nsrc = emalloc(len);
|
|
ndir = strdup(dir);
|
|
if (*src != '/') {
|
|
for (q = ndir; *q; *p++ = *q++)
|
|
;
|
|
*p++ = '/';
|
|
}
|
|
strcpy(p, src);
|
|
str = string_create(nsrc);
|
|
str = string_flatten(str);
|
|
nsrc = strdup(str->data);
|
|
p = nsrc + strlen(nsrc) - 1;
|
|
q = ndir + strlen(ndir) - 1;
|
|
s = p;
|
|
r = q;
|
|
while (q > ndir && p > nsrc && *--q == *--p) {
|
|
if (*q != '/')
|
|
continue;
|
|
r = q + 1;
|
|
s = p + 1;
|
|
while (q > ndir && *(q - 1) == '/')
|
|
--q;
|
|
while (p > nsrc && *(p - 1) == '/')
|
|
--p;
|
|
}
|
|
for (p = ndir; *p == '/'; p++)
|
|
;
|
|
while (*p) {
|
|
while (*++p && *p != '/')
|
|
;
|
|
c = *p;
|
|
*p = 0;
|
|
if (p > r)
|
|
while (*s && *s != '/')
|
|
s++;
|
|
if (stat(ndir, &sb) == -1) {
|
|
sb.st_mode = 0777;
|
|
if (p > r) {
|
|
c1 = *s;
|
|
*s = 0;
|
|
if (stat(nsrc, &sb) != -1 && DEBUG(VAR))
|
|
printf("using mode of %s\n", nsrc);
|
|
*s = c1;
|
|
}
|
|
if (!beSilent)
|
|
printf("mkdir %s\n", ndir);
|
|
if (mkdir(ndir, (int) sb.st_mode & 0777) == -1)
|
|
Fatal("Couldn't make directory: %s", ndir);
|
|
} else if ((sb.st_mode & S_IFMT) != S_IFDIR)
|
|
Fatal("Not a directory: %s", ndir);
|
|
if (p > r)
|
|
while (*s == '/')
|
|
s++;
|
|
*p = c;
|
|
while (*p == '/')
|
|
p++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* "rev(a) | '/' | b" into buf
|
|
*/
|
|
static void
|
|
rdircat(char *a, char *b, Buffer buf)
|
|
{
|
|
register char *p;
|
|
|
|
for (p = a; *p; ) {
|
|
if (*p == '/' ||
|
|
(*p == '.' &&
|
|
(*(p+1) == 0 || *(p+1) == '/' ||
|
|
(*(p+1) == '.' && (*(p+2) == 0 || *(p+2) == '/')))))
|
|
Fatal("bad directory: %s", a);
|
|
while (*p && *p++ != '/')
|
|
;
|
|
Buf_AddByte(buf, (Byte)'.');
|
|
Buf_AddByte(buf, (Byte)'.');
|
|
if (*p || *b != 0)
|
|
Buf_AddByte(buf, (Byte)'/');
|
|
}
|
|
if (*b != 0)
|
|
Buf_AddBytes(buf, strlen(b), (Byte *)b);
|
|
}
|
|
|
|
static void
|
|
ptol(register const char *p, register Lst *lp)
|
|
{
|
|
const char *q;
|
|
Lst l = Lst_Init();
|
|
|
|
*lp = l;
|
|
for (;;) {
|
|
q = p;
|
|
while (*p && *p != ':')
|
|
p++;
|
|
if (*p == 0)
|
|
break;
|
|
(void) Lst_AtEnd(l, (ClientData) strndup(q, p - q));
|
|
p++;
|
|
}
|
|
(void) Lst_AtEnd(l, (ClientData) strndup(q, p - q));
|
|
}
|
|
|
|
static void
|
|
ltop(register Lst l, register Buffer buf)
|
|
{
|
|
register char *q;
|
|
LstNode ln;
|
|
|
|
Lst_Open(l);
|
|
if ((ln = Lst_Next(l)) != NILLNODE)
|
|
for (;;) {
|
|
q = (char *) Lst_Datum(ln);
|
|
Buf_AddBytes(buf, strlen(q), (Byte *)q);
|
|
if ((ln = Lst_Next(l)) == NILLNODE)
|
|
break;
|
|
Buf_AddByte(buf, (Byte)':');
|
|
}
|
|
Lst_Close(l);
|
|
}
|
|
|
|
/*
|
|
* FIXME
|
|
* A better way to get this procedure needs to be devised.
|
|
* It should come from libode.
|
|
*/
|
|
# define BUILD_VERSION "ODE 2.3.2"
|
|
void
|
|
ui_print_revision(void)
|
|
{
|
|
printf("program : %s\nrelease : %s\nbuilt : %s\n",
|
|
#ifdef BUILD_DATE
|
|
progname, BUILD_VERSION, BUILD_DATE);
|
|
#else
|
|
progname, BUILD_VERSION, "bootstrap version");
|
|
#endif
|
|
} /* ui_print_revision */
|