>>> What would you expect? The same sequence in both cases? >> >> Yes. By the way, BSD make will behave in the same way in both cases. >> It would be confusing to specify that "x1 and x2 cannot run in >> parallel" and have them parallelized. >> >OK, I will try to fix this.
Here is a new version of the patch, which takes care of this. Christophe.
diff -r -u make-3.81/default.c make-3.81.patch-wait/default.c --- make-3.81/default.c 2006-02-11 23:16:04.000000000 +0100 +++ make-3.81.patch-wait/default.c 2006-12-03 21:30:25.000000000 +0100 @@ -531,7 +531,7 @@ char *p = default_suffixes; suffix_file->deps = (struct dep *) multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), - sizeof (struct dep)); + sizeof (struct dep), NULL); (void) define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0); } } diff -r -u make-3.81/dep.h make-3.81.patch-wait/dep.h --- make-3.81/dep.h 2006-03-17 15:24:20.000000000 +0100 +++ make-3.81.patch-wait/dep.h 2006-12-03 21:30:56.000000000 +0100 @@ -43,6 +43,7 @@ unsigned int ignore_mtime : 1; unsigned int staticpattern : 1; unsigned int need_2nd_expansion : 1; + unsigned int wait : 1 ; }; @@ -55,7 +56,7 @@ }; -extern struct nameseq *multi_glob PARAMS ((struct nameseq *chain, unsigned int size)); +extern struct nameseq *multi_glob PARAMS ((struct nameseq *chain, unsigned int size, int *seen_special)); #ifdef VMS extern struct nameseq *parse_file_seq (); #else diff -r -u make-3.81/file.c make-3.81.patch-wait/file.c --- make-3.81/file.c 2006-03-17 15:24:20.000000000 +0100 +++ make-3.81.patch-wait/file.c 2006-12-03 21:36:58.000000000 +0100 @@ -409,12 +409,40 @@ } } +/* Notice special dependencies. */ +void +notice_special_deps(struct dep **d_ptr) +{ + struct dep *d; + + restart_loop: + for (; *d_ptr; d_ptr = &(*d_ptr)->next) + { + d = *d_ptr; + if (!strcmp(d->name, ".WAIT")) + { + /* Found a .WAIT dependency: record this on the next dep, + and remove this dep from the chain */ + free(d->name); + if (d->next) + d->next->wait = 1; + *d_ptr = d->next; + free(d); + goto restart_loop; + } + } +} + struct dep * parse_prereqs (char *p) { + /* Nonzero if we saw possibly special dependencies (e.g. .WAIT) while + parsing the dependencies for that rule. */ + int seen_special = 0; + struct dep *new = (struct dep *) multi_glob (parse_file_seq (&p, '|', sizeof (struct dep), 1), - sizeof (struct dep)); + sizeof (struct dep), &seen_special); if (*p) { @@ -425,7 +453,7 @@ ++p; ood = (struct dep *) multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), - sizeof (struct dep)); + sizeof (struct dep), &seen_special); if (! new) new = ood; @@ -441,6 +469,12 @@ ood->ignore_mtime = 1; } + /* Before dependencies are entered as files, treat special + dependencies. Need to do this before entering them as files + as treatment might involve deletion of a dependency. */ + if (seen_special) + notice_special_deps(&new); + return new; } @@ -463,6 +497,7 @@ char *file_stem = f->stem; unsigned int last_dep_has_cmds = f->updating; int initialized = 0; + int seen_special = 0; f->updating = 0; f->deps = 0; @@ -574,6 +609,7 @@ } /* Enter them as files. */ + struct dep* prev = NULL; for (d1 = new; d1 != 0; d1 = d1->next) { d1->file = lookup_file (d1->name); @@ -584,6 +620,8 @@ d1->name = 0; d1->staticpattern = 0; d1->need_2nd_expansion = 0; + + prev = d1; } /* Add newly parsed deps to f->deps. If this is the last dependency @@ -630,7 +668,7 @@ { struct file *f; struct file *f2; - struct dep *d; + struct dep *d, *d2; struct file **file_slot_0; struct file **file_slot; struct file **file_end; @@ -734,9 +772,23 @@ f2->command_flags |= COMMANDS_SILENT; } + + /* .NOTPARALLEL with deps makes these targets non-parallel (i.e. all + their dependencies are serialized). Without deps, it forbids + parallel execution at all. */ f = lookup_file (".NOTPARALLEL"); if (f != 0 && f->is_target) - not_parallel = 1; + { + if (f->deps == 0) + not_parallel = 1; + else + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + for (d2 = f2->deps; d2 != 0; d2 = d2->next) { + d2->wait = 1; + } + } + #ifndef NO_MINUS_C_MINUS_O /* If .POSIX was defined, remove OUTPUT_OPTION to comply. */ diff -r -u make-3.81/filedef.h make-3.81.patch-wait/filedef.h --- make-3.81/filedef.h 2006-02-11 23:16:04.000000000 +0100 +++ make-3.81.patch-wait/filedef.h 2006-12-03 21:35:39.000000000 +0100 @@ -61,6 +61,11 @@ the same file. Otherwise this is null. */ struct file *double_colon; + /* Target that file is waiting for before starting, or nil if + there isn't one. */ + struct file *wait; + unsigned int waiting:1; + short int update_status; /* Status of the last attempt to update, or -1 if none has been made. */ diff -r -u make-3.81/function.c make-3.81.patch-wait/function.c --- make-3.81/function.c 2006-04-01 08:36:40.000000000 +0200 +++ make-3.81.patch-wait/function.c 2006-12-03 21:35:50.000000000 +0100 @@ -352,7 +352,7 @@ That would break examples like: $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */ 0), - sizeof (struct nameseq)); + sizeof (struct nameseq), NULL); if (result == 0) { diff -r -u make-3.81/implicit.c make-3.81.patch-wait/implicit.c --- make-3.81/implicit.c 2006-04-01 08:36:40.000000000 +0200 +++ make-3.81.patch-wait/implicit.c 2006-12-03 21:40:53.000000000 +0100 @@ -74,6 +74,7 @@ char *intermediate_pattern; /* pattern for intermediate file */ unsigned char had_stem; /* had % substituted with stem */ unsigned char ignore_mtime; /* ignore_mtime flag */ + unsigned char wait; }; static void @@ -182,6 +183,31 @@ return beg; } +/* Handle special dependencies in implicit rules. */ +static void +notice_special_ideps(struct idep **id_ptr) +{ + struct idep *id; + + restart_loop: + for (; *id_ptr; id_ptr = &(*id_ptr)->next) + { + id = *id_ptr; + if (!strcmp(id->name, ".WAIT")) + { + /* Found a .WAIT dependency: record this on the next dep, + and remove this dep from the chain */ + free(id->name); + if (id->next) + id->next->wait = 1; + *id_ptr = id->next; + free(id); + goto restart_loop; + } + } +} + + /* Search the pattern rules for a rule with an existing dependency to make FILE. If a rule is found, the appropriate commands and deps are put in FILE and 1 is returned. If not, 0 is returned. @@ -258,6 +284,10 @@ that is not just `%'. */ int specific_rule_matched = 0; + /* Nonzero if we saw possibly special dependencies (e.g. .WAIT) while + parsing the dependencies for that rule. */ + int seen_special = 0; + unsigned int i = 0; /* uninit checks OK */ struct rule *rule; struct dep *dep, *expl_d; @@ -336,6 +366,9 @@ /* It can't possibly match. */ continue; + /* This rule hasn't encountered special dependencies (so far). */ + seen_special = 0; + /* From the lengths of the filename and the pattern parts, find the stem: the part of the filename that matches the %. */ stem = filename + (suffix - target - 1); @@ -599,7 +632,8 @@ parse_file_seq (&p2, order_only ? '\0' : '|', sizeof (struct idep), - 1), sizeof (struct idep)); + 1), sizeof (struct idep), + &seen_special); /* @@ It would be nice to teach parse_file_seq or multi_glob to add prefix. This would save us some @@ -650,6 +684,10 @@ file->stem = 0; + /* If there were special dependencies, handle them. */ + if (seen_special) + notice_special_ideps(&deps); + /* @@ This loop can be combined with the previous one. I do it separately for now for transparency.*/ @@ -820,6 +858,7 @@ expl_d = file->deps; /* We will add them at the end. */ d_ptr = &file->deps; + char* prev_name = NULL; for (d = deps; d != 0; d = d->next) { register char *s; @@ -872,6 +911,7 @@ dep = alloc_dep (); dep->ignore_mtime = d->ignore_mtime; + dep->wait = d->wait; s = d->name; /* Hijacking the name. */ d->name = 0; if (recursions == 0) @@ -905,6 +945,24 @@ *d_ptr = dep; d_ptr = &dep->next; + + /* Record the actual file we are waiting for, if any */ + if (prev_name && d->wait) { + if (recursions != 0) { + dep->file = lookup_file(s); + } + dep->file->wait = lookup_file(prev_name); + } + + if (d->intermediate_file) { + prev_name = d->intermediate_file->name; + } else { + if (recursions == 0) { + prev_name = dep->file->name; + } else { + prev_name = dep->name; + } + } } *d_ptr = expl_d; diff -r -u make-3.81/main.c make-3.81.patch-wait/main.c --- make-3.81/main.c 2006-03-20 03:36:37.000000000 +0100 +++ make-3.81.patch-wait/main.c 2006-12-03 21:41:08.000000000 +0100 @@ -2162,7 +2162,7 @@ ns = multi_glob ( parse_file_seq (&p, '\0', sizeof (struct nameseq), 1), - sizeof (struct nameseq)); + sizeof (struct nameseq), NULL); /* .DEFAULT_GOAL should contain one target. */ if (ns->next != 0) diff -r -u make-3.81/read.c make-3.81.patch-wait/read.c --- make-3.81/read.c 2006-03-17 15:24:20.000000000 +0100 +++ make-3.81.patch-wait/read.c 2006-12-03 21:41:40.000000000 +0100 @@ -809,7 +809,7 @@ files = multi_glob (parse_file_seq (&p2, '\0', sizeof (struct nameseq), 1), - sizeof (struct nameseq)); + sizeof (struct nameseq), NULL); free (p); /* Save the state of conditionals and start @@ -1001,7 +1001,7 @@ filenames = multi_glob (parse_file_seq (&p2, '\0', sizeof (struct nameseq), 1), - sizeof (struct nameseq)); + sizeof (struct nameseq), NULL); *p2 = ':'; if (!filenames) @@ -3013,7 +3013,7 @@ that have room for additional info. */ struct nameseq * -multi_glob (struct nameseq *chain, unsigned int size) +multi_glob (struct nameseq *chain, unsigned int size, int *seen_special) { extern void dir_setup_glob (); register struct nameseq *new = 0; @@ -3041,6 +3041,11 @@ } } + if (seen_special && old->name[0] == '.' + && isalpha (old->name[1]) && isupper (old->name[1])) { + *seen_special = 1; + } + #ifndef NO_ARCHIVES if (ar_name (old->name)) { diff -r -u make-3.81/remake.c make-3.81.patch-wait/remake.c --- make-3.81/remake.c 2006-03-20 03:36:37.000000000 +0100 +++ make-3.81.patch-wait/remake.c 2006-12-12 00:20:57.000000000 +0100 @@ -68,6 +68,43 @@ static FILE_TIMESTAMP name_mtime PARAMS ((char *name)); static int library_search PARAMS ((char **lib, FILE_TIMESTAMP *mtime_ptr)); +/* Check for loops in wait dependencies */ +static int check_circular_wait(struct file* chain, struct file *file) +{ + int circular = 0; + + for (; chain && chain->wait; chain = chain->wait) { + if (chain->wait == file) { + error (NILF, _("Circular %s <- %s wait chain dropped."), + file->name, chain->wait->name); + circular = 1; + break; + } + } + + return circular; +} + +/* Record waits in the dependencies of 'f' */ +static void record_wait(struct file* f) +{ + struct dep* d; + struct dep* prev = NULL; + for (d=f->deps; d; d = d->next) { + if (prev && d->wait && (d->file->wait == NULL)) { + d->file->wait = prev->file; + if (check_circular_wait(prev->file, d->file)) { + d->file->wait = NULL; + } + } + + /* Recursively record wait of dependencies */ + record_wait(d->file); + + prev = d; + } +} + /* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing was done, 0 if all goals were updated successfully, or 1 if a goal failed. @@ -102,6 +139,15 @@ g->changed = 0; } + { + /* Record .WAIT dependencies when they are actually needed. */ + struct dep *g; + for (g = goals; g != 0; g = g->next) { + struct file* f=g->file; + record_wait(f); + } + } + /* All files start with the considered bit 0, so the global value is 1. */ considered = 1; @@ -134,6 +180,7 @@ unsigned int ocommands_started; int x; check_renamed (file); + if (rebuilding_makefiles) { if (file->cmd_target) @@ -364,6 +411,23 @@ error (NILF, msg_parent, "*** ", file->name, file->parent->name, "."); } +/* Mark the dependencies as considered in this pass (to avoid skipping them + on the next pass). */ +static void +consider_deps (struct dep *d) +{ + for (; d; d = d->next) + d->file->considered = considered; +} + +/* Mark all the next dependencies as waiting in this pass. */ +static void +wait_deps (struct dep *d) +{ + for (; d; d = d->next) + d->file->waiting = 1; +} + /* Consider a single `struct file' and update it as appropriate. */ static int @@ -468,12 +532,47 @@ lastd = 0; d = file->deps; + struct dep* prev = NULL; while (d != 0) { FILE_TIMESTAMP mtime; int maybe_make; int dontcare = 0; + if (d->file->wait) { + if (running && (d->file->wait == prev->file)) { + /* Waiting for the prev dependency, which is currently + running, so wait */ + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } else if (d->file->waiting) { + if (d->file->wait->command_state == cs_finished) { + /* Already waiting, but the file we were waiting for has + been rebuilt: stop waiting */ + d->file->waiting = 0; + } else { + /* Already waiting, for a dep other than the previous one + (from another dep chain). Keep waiting */ + consider_deps (d); + wait_deps (d); + break; + } + } else { + /* Not yet waiting, and the dep we should wait for has not + started yet: start waiting */ + if (d->file->wait->command_state == cs_not_started) { + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } + } + } + + prev = d; + check_renamed (d->file); mtime = file_mtime (d->file); @@ -547,24 +646,62 @@ /* Now we know whether this target needs updating. If it does, update all the intermediate files we depend on. */ + prev = NULL; if (must_make || always_make_flag) { for (d = file->deps; d != 0; d = d->next) - if (d->file->intermediate) - { - int dontcare = 0; + { + if (d->file->wait) { - FILE_TIMESTAMP mtime = file_mtime (d->file); - check_renamed (d->file); - d->file->parent = file; + if (prev && (d->file->wait == prev->file) + && (d->file->wait->command_state == cs_deps_running)) { + /* Waiting for the previous file, whose deps are + currently running: start waiting */ + running |= 1; + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } else if (d->file->waiting) { + if (d->file->wait->command_state == cs_finished) { + /* Stop waiting if the deps we were waiting for has + been built */ + d->file->waiting = 0; + } else { + /* Keep waiting if needed, as well as the next deps */ + running |= 1; + consider_deps (d); + wait_deps (d); + break; + } + } else { + if (d->file->wait->command_state == cs_not_started) { + /* Start waiting if deps have not started yet */ + running |= 1; + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } + } + } - /* Inherit dontcare flag from our parent. */ - if (rebuilding_makefiles) - { - dontcare = d->file->dontcare; - d->file->dontcare = file->dontcare; - } + prev = d; + + if (d->file->intermediate) + { + int dontcare = 0; + + FILE_TIMESTAMP mtime = file_mtime (d->file); + check_renamed (d->file); + d->file->parent = file; + /* Inherit dontcare flag from our parent. */ + if (rebuilding_makefiles) + { + dontcare = d->file->dontcare; + d->file->dontcare = file->dontcare; + } dep_status |= update_file (d->file, depth); @@ -594,6 +731,7 @@ d->changed = ((file->phony && file->cmds != 0) || file_mtime (d->file) != mtime); } + } } finish_updating (file); @@ -987,10 +1125,40 @@ lastd = 0; d = file->deps; + struct dep* prev = NULL; while (d != 0) { int maybe_make; + + if (d->file->wait) { + if (prev && (d->file->wait == prev->file) + && prev->file->command_state == cs_running) { + /* Waiting for previous */ + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } else if (d->file->waiting) { + if (d->file->wait->command_state == cs_finished) { + /* Stop waiting if dep finished */ + d->file->waiting = 0; + } else { + consider_deps (d); + wait_deps (d); + break; + } + } else { + if (d->file->wait->command_state == cs_not_started) { + consider_deps (d); + wait_deps (d); + d->file->waiting = 1; + break; + } + } + } + prev = d; + if (is_updating (d->file)) { error (NILF, _("Circular %s <- %s dependency dropped."), diff -r -u make-3.81/rule.c make-3.81.patch-wait/rule.c --- make-3.81/rule.c 2006-03-17 15:24:20.000000000 +0100 +++ make-3.81.patch-wait/rule.c 2006-12-03 22:03:12.000000000 +0100 @@ -361,7 +361,7 @@ { register struct rule *r; char *ptr; - + int seen_special = 0; r = (struct rule *) xmalloc (sizeof (struct rule)); r->targets = (char **) xmalloc (2 * sizeof (char *)); @@ -386,7 +386,10 @@ ptr = p->dep; r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0', sizeof (struct dep), 1), - sizeof (struct dep)); + sizeof (struct dep), &seen_special); + + if (seen_special) + notice_special_deps(&r->deps); if (new_pattern_rule (r, 0)) { diff -r -u make-3.81/w32/Makefile make-3.81.patch-wait/w32/Makefile --- make-3.81/w32/Makefile 2006-04-01 08:40:26.000000000 +0200 +++ make-3.81.patch-wait/w32/Makefile 2006-12-03 21:17:09.000000000 +0100 @@ -51,8 +51,8 @@ NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : -build_triplet = i686-pc-linux-gnu -host_triplet = i686-pc-linux-gnu +build_triplet = i586-pc-linux-gnu +host_triplet = i586-pc-linux-gnu subdir = w32 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -88,15 +88,15 @@ ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = ${SHELL} /opt/src/make/make-release/config/missing --run aclocal-1.9 +ACLOCAL = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run aclocal-1.9 ALLOCA = AMDEP_FALSE = # AMDEP_TRUE = -AMTAR = ${SHELL} /opt/src/make/make-release/config/missing --run tar +AMTAR = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run tar AR = ar -AUTOCONF = ${SHELL} /opt/src/make/make-release/config/missing --run autoconf -AUTOHEADER = ${SHELL} /opt/src/make/make-release/config/missing --run autoheader -AUTOMAKE = ${SHELL} /opt/src/make/make-release/config/missing --run automake-1.9 +AUTOCONF = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run autoconf +AUTOHEADER = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run autoheader +AUTOMAKE = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run automake-1.9 AWK = gawk CC = gcc CCDEPMODE = depmode=gcc3 @@ -129,8 +129,8 @@ LTLIBICONV = -liconv LTLIBINTL = LTLIBOBJS = -MAKEINFO = ${SHELL} /opt/src/make/make-release/config/missing --run makeinfo -MAKE_HOST = i686-pc-linux-gnu +MAKEINFO = ${SHELL} /home/lyon/Boulot/make-wait/config/missing --run makeinfo +MAKE_HOST = i586-pc-linux-gnu MKINSTALLDIRS = $(top_builddir)/config/mkinstalldirs MSGFMT = /usr/bin/msgfmt MSGMERGE = /usr/bin/msgmerge @@ -171,30 +171,30 @@ am__tar = ${AMTAR} chof - "$$tardir" am__untar = ${AMTAR} xf - bindir = ${exec_prefix}/bin -build = i686-pc-linux-gnu +build = i586-pc-linux-gnu build_alias = -build_cpu = i686 +build_cpu = i586 build_os = linux-gnu build_vendor = pc datadir = ${prefix}/share exec_prefix = ${prefix} -host = i686-pc-linux-gnu +host = i586-pc-linux-gnu host_alias = -host_cpu = i686 +host_cpu = i586 host_os = linux-gnu host_vendor = pc includedir = ${prefix}/include infodir = ${prefix}/info -install_sh = /opt/src/make/make-release/config/install-sh +install_sh = /home/lyon/Boulot/make-wait/config/install-sh libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec +libexecdir = /usr/local/lib localstatedir = ${prefix}/var -mandir = ${prefix}/man +mandir = /usr/local/man mkdir_p = mkdir -p -- oldincludedir = /usr/include prefix = /usr/local program_transform_name = s,x,x, -sbindir = ${exec_prefix}/sbin +sbindir = /usr/local/bin sharedstatedir = ${prefix}/com sysconfdir = ${prefix}/etc target_alias =
_______________________________________________ Help-make mailing list Help-make@gnu.org http://lists.gnu.org/mailman/listinfo/help-make