summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS7
-rw-r--r--doc/make.texi41
-rw-r--r--src/remake.c18
-rw-r--r--tests/scripts/features/archives36
4 files changed, 86 insertions, 16 deletions
diff --git a/NEWS b/NEWS
index 6e9482b8..e8fce031 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,13 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=110&se
makefiles.
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
+* New feature: Parallel builds of archives
+ Previously it was not possible to use parallel builds with archives. It is
+ still not possible using the built-in rules, however you can now override
+ the built-in rules with a slightly different set of rules and use parallel
+ builds with archive creation. See the "Dangers When Using Archives" section
+ of the GNU Make manual, and https://savannah.gnu.org/bugs/index.php?14927
+
* Previously target-specific variables would inherit their "export" capability
from parent target-specific variables even if they were marked private. Now
private parent target-specific variables have no affect. For more details
diff --git a/doc/make.texi b/doc/make.texi
index 29c852a9..b8cbb52c 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -11497,7 +11497,7 @@ and make all the members of the archive file prerequisites of that rule.
For example,
@example
-libfoo.a: libfoo.a(x.o) libfoo.a(y.o) @dots{}
+libfoo.a: libfoo.a(x.o y.o @dots{})
ranlib libfoo.a
@end example
@@ -11518,15 +11518,38 @@ updates the @file{__.SYMDEF} member automatically.
@cindex archive, and @code{-j}
@cindex @code{-j}, and archive update
-It is important to be careful when using parallel execution (the
-@code{-j} switch; @pxref{Parallel, ,Parallel Execution}) and archives.
-If multiple @code{ar} commands run at the same time on the same archive
-file, they will not know about each other and can corrupt the file.
+The built-in rules for updating archives are incompatible with parallel
+builds. These rules (required by the POSIX standard) add each object file
+into the archive as it's compiled. When parallel builds are enabled this
+allows multiple @code{ar} commands to be updating the same archive
+simultaneously, which is not supported.
-Possibly a future version of @code{make} will provide a mechanism to
-circumvent this problem by serializing all recipes that operate on the
-same archive file. But for the time being, you must either write your
-makefiles to avoid this problem in some other way, or not use @code{-j}.
+If you want to use parallel builds with archives you can override the default
+rules by adding these lines to your makefile:
+
+@example
+(%) : % ;
+%.a : ; $(AR) $(ARFLAGS) $@ $?
+@end example
+
+The first line changes the rule that updates an individual object in the
+archive to do nothing, and the second line changes the default rule for
+building an archive to update all the outdated objects (@code{$?}) in one
+command.
+
+Of course you will still need to declare the prerequisites of your library
+using the archive syntax:
+
+@example
+libfoo.a: libfoo.a(x.o y.o @dots{})
+@end example
+
+If you prefer to write an explicit rule you can use:
+
+@example
+libfoo.a: libfoo.a(x.o y.o @dots{})
+ $(AR) $(ARFLAGS) $@ $?
+@end example
@node Archive Suffix Rules, , Archive Pitfalls, Archives
@section Suffix Rules for Archive Files
diff --git a/src/remake.c b/src/remake.c
index a1f1d1d9..8e2547eb 100644
--- a/src/remake.c
+++ b/src/remake.c
@@ -1341,7 +1341,7 @@ f_mtime (struct file *file, int search)
if (ar_name (file->name))
{
/* This file is an archive-member reference. */
-
+ FILE_TIMESTAMP memmtime;
char *arname, *memname;
struct file *arfile;
time_t member_date;
@@ -1349,6 +1349,9 @@ f_mtime (struct file *file, int search)
/* Find the archive's name. */
ar_parse_name (file->name, &arname, &memname);
+ /* Find the mtime of the member file (it might not exist). */
+ memmtime = name_mtime (memname);
+
/* Find the modification time of the archive itself.
Also allow for its name to be changed via VPATH search. */
arfile = lookup_file (arname);
@@ -1392,9 +1395,16 @@ f_mtime (struct file *file, int search)
return NONEXISTENT_MTIME;
member_date = ar_member_date (file->hname);
- mtime = (member_date == (time_t) -1
- ? NONEXISTENT_MTIME
- : file_timestamp_cons (file->hname, member_date, 0));
+
+ if (member_date == (time_t) -1
+ || (memmtime != NONEXISTENT_MTIME
+ && (time_t) FILE_TIMESTAMP_S (memmtime) > member_date))
+ /* If the member file exists and is newer than the member in the
+ archive, pretend it's nonexistent. This means the member file was
+ updated but not added to the archive yet. */
+ mtime = NONEXISTENT_MTIME;
+ else
+ mtime = file_timestamp_cons (file->hname, member_date, 0);
}
else
#endif
diff --git a/tests/scripts/features/archives b/tests/scripts/features/archives
index b0d479b2..2ad34d92 100644
--- a/tests/scripts/features/archives
+++ b/tests/scripts/features/archives
@@ -20,9 +20,7 @@ if ($osname eq 'VMS') {
# objects when the test tampers with the timestamp.
1 while unlink "$afile.c1";
1 while unlink "$afile.o";
- open (MYFILE, ">$afile.c1");
- print MYFILE "int $afile(void) {return 1;}\n";
- close MYFILE;
+ create_file("$afile.c1", "int $afile(void) {return 1;}\n");
system("cc $afile.c1 /object=$afile.o");
}
} else {
@@ -238,5 +236,37 @@ $pre%: ; touch \$\@
unlink($lib);
}
+# SV 61436 : Allow redefining archive rules to propagate timestamps
+
+# Find the output when creating an archive from multiple files
+
+utouch(-10, 'a.o', 'b.o');
+my $create2 = `$ar $arflags mylib.a a.o b.o $redir`;
+touch('b.o');
+my $add2 = `$ar $arflags mylib.a b.o $redir`;
+unlink('a.o', 'b.o', 'mylib.a');
+
+utouch(-20, 'a.c', 'b.c');
+
+run_make_test(q!
+mylib.a: mylib.a(a.o b.o)
+(%): % ;
+%.a: ; $(AR) $(ARFLAGS) $@ $?
+%.o : %.c ; @echo Compile $<; $(COMPILE.c) -o $@ $<
+!, $arvar, "Compile a.c\nCompile b.c\n$ar $arflags mylib.a a.o b.o\n${create2}rm b.o a.o");
+
+run_make_test(undef, $arvar, "#MAKE#: 'mylib.a' is up to date.");
+
+# Now update one of the source files and it should be compiled and archived
+
+sleep(2);
+touch('b.c');
+
+run_make_test(undef, $arvar, "Compile b.c\n$ar $arflags mylib.a b.o\n${add2}rm b.o");
+
+run_make_test(undef, $arvar, "#MAKE#: 'mylib.a' is up to date.");
+
+unlink('a.c', 'b.c', 'a.o', 'b.o', 'mylib.a');
+
# This tells the test driver that the perl test script executed properly.
1;