diff options
-rw-r--r-- | usr.bin/make/globals.h | 1 | ||||
-rw-r--r-- | usr.bin/make/job.c | 49 | ||||
-rw-r--r-- | usr.bin/make/job.h | 2 | ||||
-rw-r--r-- | usr.bin/make/main.c | 202 | ||||
-rw-r--r-- | usr.bin/make/make.1 | 45 | ||||
-rw-r--r-- | usr.bin/make/make.h | 1 | ||||
-rw-r--r-- | usr.bin/make/parse.c | 6 |
7 files changed, 279 insertions, 27 deletions
diff --git a/usr.bin/make/globals.h b/usr.bin/make/globals.h index 4982a9f..465c4f3 100644 --- a/usr.bin/make/globals.h +++ b/usr.bin/make/globals.h @@ -77,6 +77,7 @@ extern Boolean beSilent; /* True if should print no commands */ extern Boolean beVerbose; /* True if should print extra cruft */ extern Boolean noExecute; /* True if should execute nothing */ extern Boolean allPrecious; /* True if every target is precious */ +extern Boolean is_posix; /* .POSIX target seen */ /* True if should continue on unaffected portions of the graph * when have an error in one portion */ diff --git a/usr.bin/make/job.c b/usr.bin/make/job.c index 7bb31cd..6136c6f 100644 --- a/usr.bin/make/job.c +++ b/usr.bin/make/job.c @@ -3070,7 +3070,7 @@ Compat_RunCommand(char *cmd, GNode *gn) /*- *----------------------------------------------------------------------- - * CompatMake -- + * Compat_Make -- * Make a target, given the parent, to abort if necessary. * * Side Effects: @@ -3078,8 +3078,8 @@ Compat_RunCommand(char *cmd, GNode *gn) * *----------------------------------------------------------------------- */ -static int -CompatMake(GNode *gn, GNode *pgn) +int +Compat_Make(GNode *gn, GNode *pgn) { LstNode *ln; @@ -3099,7 +3099,7 @@ CompatMake(GNode *gn, GNode *pgn) gn->made = BEINGMADE; Suff_FindDeps(gn); LST_FOREACH(ln, &gn->children) - CompatMake(Lst_Datum(ln), gn); + Compat_Make(Lst_Datum(ln), gn); if (!gn->make) { gn->made = ABORTED; pgn->make = FALSE; @@ -3289,6 +3289,27 @@ CompatMake(GNode *gn, GNode *pgn) } /*- + * Install signal handlers for Compat_Run + */ +void +Compat_InstallSignalHandlers(void) +{ + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + signal(SIGINT, CompatCatchSig); + } + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + signal(SIGTERM, CompatCatchSig); + } + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + signal(SIGHUP, CompatCatchSig); + } + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { + signal(SIGQUIT, CompatCatchSig); + } +} + +/*- *----------------------------------------------------------------------- * Compat_Run -- * Start making again, given a list of target nodes. @@ -3308,19 +3329,7 @@ Compat_Run(Lst *targs) int error_cnt; /* Number of targets not remade due to errors */ LstNode *ln; - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - signal(SIGINT, CompatCatchSig); - } - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - signal(SIGTERM, CompatCatchSig); - } - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - signal(SIGHUP, CompatCatchSig); - } - if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - signal(SIGQUIT, CompatCatchSig); - } - + Compat_InstallSignalHandlers(); ENDNode = Targ_FindNode(".END", TARG_CREATE); /* * If the user has defined a .BEGIN target, execute the commands @@ -3341,8 +3350,8 @@ Compat_Run(Lst *targs) } /* - * For each entry in the list of targets to create, call CompatMake on - * it to create the thing. CompatMake will leave the 'made' field of gn + * For each entry in the list of targets to create, call Compat_Make on + * it to create the thing. Compat_Make will leave the 'made' field of gn * in one of several states: * UPTODATE gn was already up-to-date * MADE gn was recreated successfully @@ -3353,7 +3362,7 @@ Compat_Run(Lst *targs) error_cnt = 0; while (!Lst_IsEmpty(targs)) { gn = Lst_DeQueue(targs); - CompatMake(gn, gn); + Compat_Make(gn, gn); if (gn->made == UPTODATE) { printf("`%s' is up to date.\n", gn->name); diff --git a/usr.bin/make/job.h b/usr.bin/make/job.h index 1ef4b66..a4c6620 100644 --- a/usr.bin/make/job.h +++ b/usr.bin/make/job.h @@ -72,6 +72,8 @@ void Proc_Init(void); struct Buffer *Cmd_Exec(const char *, const char **); +int Compat_Make(struct GNode *gn, struct GNode *pgn); +void Compat_InstallSignalHandlers(void); void Compat_Run(struct Lst *); #endif /* job_h_4678dfd1 */ diff --git a/usr.bin/make/main.c b/usr.bin/make/main.c index 1c8acdc..8eceedf 100644 --- a/usr.bin/make/main.c +++ b/usr.bin/make/main.c @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); #include "config.h" #include "dir.h" #include "globals.h" +#include "GNode.h" #include "job.h" #include "make.h" #include "parse.h" @@ -100,6 +101,9 @@ extern char **environ; /* XXX what header declares this variable? */ /* ordered list of makefiles to read */ static Lst makefiles = Lst_Initializer(makefiles); +/* ordered list of source makefiles */ +static Lst source_makefiles = Lst_Initializer(source_makefiles); + /* list of variables to print */ static Lst variables = Lst_Initializer(variables); @@ -108,6 +112,8 @@ static Boolean noBuiltins; /* -r flag */ static Boolean forceJobs; /* -j argument given */ static char *curdir; /* startup directory */ static char *objdir; /* where we chdir'ed to */ +static char **save_argv; /* saved argv */ +static char *save_makeflags;/* saved MAKEFLAGS */ /* (-E) vars to override from env */ Lst envFirstVars = Lst_Initializer(envFirstVars); @@ -116,6 +122,7 @@ Lst envFirstVars = Lst_Initializer(envFirstVars); Lst create = Lst_Initializer(create); Boolean allPrecious; /* .PRECIOUS given on line by itself */ +Boolean is_posix; /* .POSIX target seen */ Boolean beSilent; /* -s flag */ Boolean beVerbose; /* -v flag */ Boolean compatMake; /* -B argument */ @@ -316,6 +323,31 @@ found: } /** + * Open and parse the given makefile. + * If open is successful add it to the list of makefiles. + * + * Results: + * TRUE if ok. FALSE if couldn't open file. + */ +static Boolean +TryReadMakefile(const char p[]) +{ + char *data; + LstNode *last = Lst_Last(&source_makefiles); + + if (!ReadMakefile(p)) + return (FALSE); + + data = estrdup(p); + if (last == NULL) { + LstNode *first = Lst_First(&source_makefiles); + Lst_Insert(&source_makefiles, first, data); + } else + Lst_Append(&source_makefiles, last, estrdup(p)); + return (TRUE); +} + +/** * MainParseArgs * Parse a given argument vector. Called from main() and from * Main_ParseArgLine() when the .MAKEFLAGS target is used. @@ -502,7 +534,7 @@ rearg: if (Main_ParseWarn(optarg, 1) != -1) MFLAGS_append("-x", optarg); break; - + default: case '?': usage(); @@ -523,10 +555,12 @@ rearg: for (; *argv != NULL; ++argv, --argc) { if (Parse_IsVar(*argv)) { char *ptr = MAKEFLAGS_quote(*argv); + char *v = estrdup(*argv); Var_Append(".MAKEFLAGS", ptr, VAR_GLOBAL); - Parse_DoVar(*argv, VAR_CMD); + Parse_DoVar(v, VAR_CMD); free(ptr); + free(v); } else if ((*argv)[0] == '-') { if ((*argv)[1] == '\0') { @@ -640,6 +674,149 @@ check_make_level(void) } /** + * Main_AddSourceMakefile + * Add a file to the list of source makefiles + */ +void +Main_AddSourceMakefile(const char *name) +{ + + Lst_AtEnd(&source_makefiles, estrdup(name)); +} + +/** + * Remake_Makefiles + * Remake all the makefiles + */ +static void +Remake_Makefiles(void) +{ + LstNode *ln; + int error_cnt = 0; + int remade_cnt = 0; + + Compat_InstallSignalHandlers(); + + LST_FOREACH(ln, &source_makefiles) { + LstNode *ln2; + struct GNode *gn; + const char *name = Lst_Datum(ln); + Boolean saveTouchFlag = touchFlag; + Boolean saveQueryFlag = queryFlag; + Boolean saveNoExecute = noExecute; + + /* + * Create node + */ + gn = Targ_FindNode(name, TARG_CREATE); + DEBUGF(MAKE, ("Checking %s...", gn->name)); + Suff_FindDeps(gn); + + /* + * ! dependencies as well as + * dependencies with .FORCE, .EXEC and .PHONY attributes + * are skipped to prevent infinite loops + */ + if (gn->type & (OP_FORCE | OP_EXEC | OP_PHONY)) { + DEBUGF(MAKE, ("skipping (force, exec or phony).\n", + gn->name)); + continue; + } + + /* + * Skip :: targets that have commands and no children + * because such targets are always out-of-date + */ + if ((gn->type & OP_DOUBLEDEP) && + !Lst_IsEmpty(&gn->commands) && + Lst_IsEmpty(&gn->children)) { + DEBUGF(MAKE, ("skipping (doubledep, no sources " + "and has commands).\n")); + continue; + } + + /* + * Skip targets without sources and without commands + */ + if (Lst_IsEmpty(&gn->commands) && + Lst_IsEmpty(&gn->children)) { + DEBUGF(MAKE, + ("skipping (no sources and no commands).\n")); + continue; + } + + DEBUGF(MAKE, ("\n")); + + /* + * -t, -q and -n has no effect unless the makefile is + * specified as one of the targets explicitly in the + * command line + */ + LST_FOREACH(ln2, &create) { + if (!strcmp(gn->name, Lst_Datum(ln2))) { + /* found as a target */ + break; + } + } + if (ln2 == NULL) { + touchFlag = FALSE; + queryFlag = FALSE; + noExecute = FALSE; + } + + /* + * Check and remake the makefile + */ + Compat_Make(gn, gn); + + /* + * Restore -t, -q and -n behaviour + */ + touchFlag = saveTouchFlag; + queryFlag = saveQueryFlag; + noExecute = saveNoExecute; + + /* + * Compat_Make will leave the 'made' field of gn + * in one of the following states: + * UPTODATE gn was already up-to-date + * MADE gn was recreated successfully + * ERROR An error occurred while gn was being created + * ABORTED gn was not remade because one of its inferiors + * could not be made due to errors. + */ + if (gn->made == MADE) + remade_cnt++; + else if (gn->made == ERROR) + error_cnt++; + else if (gn->made == ABORTED) { + printf("`%s' not remade because of errors.\n", + gn->name); + error_cnt++; + } + } + + if (error_cnt > 0) + Fatal("Failed to remake Makefiles."); + if (remade_cnt > 0) { + DEBUGF(MAKE, ("Restarting `%s'.\n", save_argv[0])); + + /* + * Some of makefiles were remade -- restart from clean state + */ + if (save_makeflags != NULL) + setenv("MAKEFLAGS", save_makeflags, 1); + else + unsetenv("MAKEFLAGS"); + chdir(curdir); + if (execvp(save_argv[0], save_argv) < 0) { + Fatal("Can't restart `%s': %s.", + save_argv[0], strerror(errno)); + } + } +} + +/** * main * The main function, for obvious reasons. Initializes variables * and a few modules, then parses the arguments give it in the @@ -671,6 +848,11 @@ main(int argc, char **argv) char cdpath[MAXPATHLEN]; char *cp = NULL, *start; + save_argv = argv; + save_makeflags = getenv("MAKEFLAGS"); + if (save_makeflags != NULL) + save_makeflags = estrdup(save_makeflags); + /* * Initialize file global variables. */ @@ -958,14 +1140,14 @@ main(int argc, char **argv) LstNode *ln; LST_FOREACH(ln, &makefiles) { - if (!ReadMakefile(Lst_Datum(ln))) + if (!TryReadMakefile(Lst_Datum(ln))) break; } if (ln != NULL) Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); - } else if (!ReadMakefile("BSDmakefile")) - if (!ReadMakefile("makefile")) - ReadMakefile("Makefile"); + } else if (!TryReadMakefile("BSDmakefile")) + if (!TryReadMakefile("makefile")) + TryReadMakefile("Makefile"); ReadMakefile(".depend"); @@ -1034,6 +1216,13 @@ main(int argc, char **argv) */ Lst targs = Lst_Initializer(targs); + if (!is_posix) { + /* + * Check if any of the makefiles are out-of-date. + */ + Remake_Makefiles(); + } + if (Lst_IsEmpty(&create)) Parse_MainName(&targs); else @@ -1072,6 +1261,7 @@ main(int argc, char **argv) Lst_Destroy(&variables, free); Lst_Destroy(&makefiles, free); + Lst_Destroy(&source_makefiles, free); Lst_Destroy(&create, free); /* print the graph now it's been processed if the user requested it */ diff --git a/usr.bin/make/make.1 b/usr.bin/make/make.1 index e77ec19..393e4f5 100644 --- a/usr.bin/make/make.1 +++ b/usr.bin/make/make.1 @@ -1465,6 +1465,51 @@ Several flags can be specified on a single .Ic .WARN target by seperating them with blanks. .El +.Sh REMAKING MAKEFILES +After reading Makefile and all the files that are included using +.Ic .include +or +.Ic .sinclude +directives (source Makefiles) +.Nm +considers each source Makefile as a target and tries to rebuild it. +Both explicit and implicit rules are checked and all source Makefiles +are updated if necessary. If any of the source Makefiles were rebuilt, +.Nm +restarts from clean state. +.Pp +To prevent infinite loops the following source Makefile targets are ignored: +.Bl -bullet +.It +.Ic :: +targets that have no prerequisites but have commands +.It +.Ic ! +targets +.It +targets that have +.Ic .PHONY +or +.Ic .EXEC +attributes +.It +targets without prerequisites and without commands +.El +.Pp +When remaking a source Makefile options +.Ic -t +(touch target), +.Ic -q +(query mode), and +.Ic -n +(no exec) do not take effect, unless source Makefile is specified +explicitly as a target in +.Nm +command line. +.Pp +Additionally, system makefiles and +.Ic .depend +are not considered as a Makefiles that can be rebuilt. .Sh ENVIRONMENT The .Nm diff --git a/usr.bin/make/make.h b/usr.bin/make/make.h index e8d5660..2386cd7 100644 --- a/usr.bin/make/make.h +++ b/usr.bin/make/make.h @@ -68,5 +68,6 @@ void Make_DoAllVar(struct GNode *); Boolean Make_Run(struct Lst *); void Main_ParseArgLine(char *, int); int Main_ParseWarn(const char *, int); +void Main_AddSourceMakefile(const char *); #endif /* make_h_a91074b9 */ diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index c9c1dbf..f125b50 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1070,6 +1070,7 @@ ParseDoDependency(char *line) Path_Clear(Lst_Datum(ln)); break; case Posix: + is_posix = TRUE; Var_Set("%POSIX", "1003.2", VAR_GLOBAL); break; default: @@ -2059,7 +2060,7 @@ ParseFinishLine(void) } /** - * parse_include + * xparse_include * Parse an .include directive and push the file onto the input stack. * The input is the line minus the .include. A file spec is a string * enclosed in <> or "". The former is looked for only in sysIncPath. @@ -2184,9 +2185,12 @@ xparse_include(char *file, int sinclude) *cp = endc; if (!sinclude) Parse_Error(PARSE_FATAL, "Could not find %s", file); + else + Main_AddSourceMakefile(file); free(file); return; } + Main_AddSourceMakefile(fullname); free(file); /* |