bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[3.81] Possible parallelizing bug in combination with multiple-target pa


From: Christoph Schulz
Subject: [3.81] Possible parallelizing bug in combination with multiple-target pattern rules
Date: Sun, 18 Feb 2007 11:01:23 +0100
User-agent: Thunderbird 1.5.0.9 (Windows/20061207)

[Tested on Windows with native (non-MSYS) MinGW build of GNU make 3.81,
found in
http://prdownloads.sourceforge.net/mingw/mingw32-make-3.81-1.tar.gz, and
on Gentoo Linux with portage-compiled make 3.81.]

Hello,

I think I've found a bug in GNU make. When a pattern rule with multiple
targets exists, and make determines that it needs that rule to built one
matching target, it uses this rule even if the other targets implicitly
built by this rule don't have their dependencies built yet.

As this is quite complicated to explain, I created a little example:

final: x
        @echo "making final"
        touch $@
x: x.tgt1 x.tgt2
        @echo "making x"
        touch $@
x.tgt2: dep
dep:
        @echo "making dep"
        sleep 5
        touch $@
%.tgt1 %.tgt2: %.src
        cp $< $(patsubst %.src,%.tgt1,$<)
        cp $< $(patsubst %.src,%.tgt2,$<)
clean:
        -rm -f final x dep x.tgt1 x.tgt2


(Note: To run this makefile successfully you have to create a file named
"x.src" at first, to cause the pattern rule to be applied.)

This Makefile has some unwanted properties. At first, building "final"
does not result in building "dep", although the dependency chain
"final-->x-->x.tgt2-->dep" exists. Make traverses the dependency tree
from left to right. It finds that x depends on x.tgt1 and that x.tgt1
can only be built by the pattern rule. However, at build time, this rule
also builds x.tgt2. So x.tgt2's non-existent dependencies are ignored as
it already exists.

If you reverse the order of x's prerequisites, you encounter an even
stranger effect. Running make (after a proper "make clean", of course)
seems to work. However, if you use "make -j" you will see that the "dep"
target will be finished long after the "final" target. This is due to
the fact that the dependency x.tgt2-->dep is not properly tracked across
the pattern rule.

Additionally, in both cases (Makefile with original order of x's
prerequisites and Makefile with reversed order and using "make -j"), one
has to run make a second time until everything is built.

I don't know whether this behaviour is by design. But I think that
pattern rules with multiple (pattern) targets must only be run if make
determines that all dependencies for *all* the targets the pattern rule
would create are already in place. Currently, make seems to perform the
dependency check only for that target that triggers the rule. This is
not enough IMHO. In the example above, make should be running the
pattern rule only after the dependencies of both x.tgt1 *and* x.tgt2
have been built successfully. This would also help to get rid of the
"reordering changes semantics" effect described above.

(For the curious: The real case was a system where the compiler (MSVC++)
also creates a precompiled header file for a special dummy source file.
To account for the fact that compiling all "normal" source files needs
this precompiled headers I built a pattern rule like the following one
(the pattern rule was necessary in order to tell "make" that the command
build both files simultaneously):

OBJS := library-pchgen.obj <further library objects>
$(OBJS): library-pchgen.obj

%.pch %-pchgen.obj: %-pchgen.src
  <compiler call to compile the pchgen and pch files>

$(TARGET): $(OBJS) library.pch
  <linker call>

Because there were dependencies on other libraries, all the object files
had additional prerequisites:

$(OBJS): other_lib/other_lib.dll another_lib/another_lib.dll

However, this did not work when using "make -j", as library-pchgen.obj
was built before the other libraries were built. Stating explicitly that
the pch file (library.pch) also depends on the other libraries via:

$(OBJS) library.pch: other_lib/other_lib.dll another_lib/another_lib.dll

solved the problem, but - as I already said - I don't think this should
be necessary.)

I'm looking forward to your opinions on that topic!

Regards,
  Christoph Schulz





reply via email to

[Prev in Thread] Current Thread [Next in Thread]