mirror of
https://github.com/mirror/make.git
synced 2025-02-10 20:00:21 +08:00
[SV 14927] Allow parallel builds for archives
Compare the timestamp of the object file (if it exists) with the archived object and if the object file is newer, ensure it's updated in the archive. * NEWS: Announce the new capability. * doc/make.texi (Dangers When Using Archives): Explain how to enable parallel builds with archives. * src/remake.c (f_mtime): For archive element files check the mod time of the object file (if it exists) against the archive object (if it exists). * tests/scripts/features/archives: Add tests for this capability.
This commit is contained in:
parent
8791d2b38e
commit
1ceeb8c64b
7
NEWS
7
NEWS
@ -24,6 +24,13 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=110&se
|
|||||||
makefiles.
|
makefiles.
|
||||||
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
|
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
|
* Previously target-specific variables would inherit their "export" capability
|
||||||
from parent target-specific variables even if they were marked private. Now
|
from parent target-specific variables even if they were marked private. Now
|
||||||
private parent target-specific variables have no affect. For more details
|
private parent target-specific variables have no affect. For more details
|
||||||
|
@ -11497,7 +11497,7 @@ and make all the members of the archive file prerequisites of that rule.
|
|||||||
For example,
|
For example,
|
||||||
|
|
||||||
@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
|
ranlib libfoo.a
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@ -11518,15 +11518,38 @@ updates the @file{__.SYMDEF} member automatically.
|
|||||||
@cindex archive, and @code{-j}
|
@cindex archive, and @code{-j}
|
||||||
@cindex @code{-j}, and archive update
|
@cindex @code{-j}, and archive update
|
||||||
|
|
||||||
It is important to be careful when using parallel execution (the
|
The built-in rules for updating archives are incompatible with parallel
|
||||||
@code{-j} switch; @pxref{Parallel, ,Parallel Execution}) and archives.
|
builds. These rules (required by the POSIX standard) add each object file
|
||||||
If multiple @code{ar} commands run at the same time on the same archive
|
into the archive as it's compiled. When parallel builds are enabled this
|
||||||
file, they will not know about each other and can corrupt the file.
|
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
|
If you want to use parallel builds with archives you can override the default
|
||||||
circumvent this problem by serializing all recipes that operate on the
|
rules by adding these lines to your makefile:
|
||||||
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}.
|
@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
|
@node Archive Suffix Rules, , Archive Pitfalls, Archives
|
||||||
@section Suffix Rules for Archive Files
|
@section Suffix Rules for Archive Files
|
||||||
|
18
src/remake.c
18
src/remake.c
@ -1341,7 +1341,7 @@ f_mtime (struct file *file, int search)
|
|||||||
if (ar_name (file->name))
|
if (ar_name (file->name))
|
||||||
{
|
{
|
||||||
/* This file is an archive-member reference. */
|
/* This file is an archive-member reference. */
|
||||||
|
FILE_TIMESTAMP memmtime;
|
||||||
char *arname, *memname;
|
char *arname, *memname;
|
||||||
struct file *arfile;
|
struct file *arfile;
|
||||||
time_t member_date;
|
time_t member_date;
|
||||||
@ -1349,6 +1349,9 @@ f_mtime (struct file *file, int search)
|
|||||||
/* Find the archive's name. */
|
/* Find the archive's name. */
|
||||||
ar_parse_name (file->name, &arname, &memname);
|
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.
|
/* Find the modification time of the archive itself.
|
||||||
Also allow for its name to be changed via VPATH search. */
|
Also allow for its name to be changed via VPATH search. */
|
||||||
arfile = lookup_file (arname);
|
arfile = lookup_file (arname);
|
||||||
@ -1392,9 +1395,16 @@ f_mtime (struct file *file, int search)
|
|||||||
return NONEXISTENT_MTIME;
|
return NONEXISTENT_MTIME;
|
||||||
|
|
||||||
member_date = ar_member_date (file->hname);
|
member_date = ar_member_date (file->hname);
|
||||||
mtime = (member_date == (time_t) -1
|
|
||||||
? NONEXISTENT_MTIME
|
if (member_date == (time_t) -1
|
||||||
: file_timestamp_cons (file->hname, member_date, 0));
|
|| (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
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,9 +20,7 @@ if ($osname eq 'VMS') {
|
|||||||
# objects when the test tampers with the timestamp.
|
# objects when the test tampers with the timestamp.
|
||||||
1 while unlink "$afile.c1";
|
1 while unlink "$afile.c1";
|
||||||
1 while unlink "$afile.o";
|
1 while unlink "$afile.o";
|
||||||
open (MYFILE, ">$afile.c1");
|
create_file("$afile.c1", "int $afile(void) {return 1;}\n");
|
||||||
print MYFILE "int $afile(void) {return 1;}\n";
|
|
||||||
close MYFILE;
|
|
||||||
system("cc $afile.c1 /object=$afile.o");
|
system("cc $afile.c1 /object=$afile.o");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -238,5 +236,37 @@ $pre%: ; touch \$\@
|
|||||||
unlink($lib);
|
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.
|
# This tells the test driver that the perl test script executed properly.
|
||||||
1;
|
1;
|
||||||
|
Loading…
Reference in New Issue
Block a user