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
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
@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
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;
/* 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);
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
# 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 {
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;