Paul D. Smith wrote:
%% Sandy Currier <address@hidden> writes:
sc> Actually, though the primary point is to not have targets that
sc> depend on foo.exp rebuild when it is not physically changed, the
sc> secondary point IS to touch the foo.exp target. By touching it
sc> when it is rebuilt, then the next time that make is run, if none
sc> of the $(ALL_FOO_OFILES) have changed, then the neither foo.exp or
sc> foo.so is rebuilt.
Well, you can't have it both ways: either the target is updated, in
which case things that depend on the target are updated, or it's not
updated, in which case it will be re-assessed in relation to its
prerequisites the next time make is run.
As mentioned, scons supports this, allowing the user the ability
to intrinsically tell the build that something is up-to-date
irrespective of the date/MD5 check. (Note: this question stems
from a bake-off we are having between gmake and scons as to see
which tool can build 10Gbytes of code better under a single DAG.)
In fact, there are several (many?) other places in the build where the
same feature is required. So far, in those places we worked around
the problem in gmake by using the "include <fake-dep-file>" trick (which
is somewhat akin to http://make.paulandlesley.org/autodep.html). This
is where as a side effect of creating and including a generated makefile
we create the actual file of interest. Whenever the file of interest is
missing or needs to be re-created from 'non-derived' files, gmake builds
the
file then reloads the DAG since an included makefile has changed.
This is cool, but it only really works in these cases since
all the generated files are derived from non-derived files (and the
DAG can be 'thrown out' and re-created without much cost). This step
occurs
first in the build, and everything is ok. Our current gmake prototype
does this with perhaps a 100 or so files, and the real build will handle
many
more of this type of file.
This trick cannot be used here with the shared library example since the
need to specify-this-derived-object-is-old-because-it-has-not-changed
occurs after much building and is based itself on derived files, not from
non-derived files. Throwing out the DAG at this point in the build
would be similar to breaking the DAG into two pieces, a pass-1 piece and
a pass-2 piece. And I am not sure it will work in this case anyway.
Well, you could actually get both but you need an extra file; you can
use this "sentinel" file to manage controlling the expensive part and
then the only part that is run multiple times is the cheap part of
comparing the results.
For example:
foo.so: $(ALL_FOO_OFILES) foo.exp
create_sharedlib.pl ...
foo.exp: .foo.exp.new
if [ "x`stat.pl address@hidden" != "x`stat.pl $<`" ]; then \
cp $< $@; \
fi
.foo.exp.new: $(ALL_FOO_OFILES)
create_export_list.pl $@ $^
Now create_export_list.pl will only be invoked when some OFILE actually
changes, and foo.exp will only be updated when the export list has
changed, but you don't pay the cost of updating the export list every
time you only pay the cost of the comparison.
The above breaks the requirement that foo.so be fully up-to-date when the
foo.exp target completes. Additionally, for -jN, the above has the
property that foo.exp can complete while foo.so still does not exist or
worse, is still actively being built. Then, targets that only explicitly
depends on foo.exp:
bar.so: foo.exp
link $@ foo.so
unittest_foo.exe : foo.exp
link $@ foo.so
will fail without some type of explicit or implicit dependency on foo.so,
which is what we are trying to avoid on purpose since we only want to
relink the bar.so shared library if the foo.exp file has changed, NOT if
the foo.so file has changed. Other targets to execute tests and things do
need to depend directly on foo.so:
run_unittest_foo.ts: unittest_foo.exe foo.so
unittest_foo.exe ...
touch $@
...and should re-execute whenever foo.so changes. [The above example
shows that the unittest for foo only needs to relink when foo.exp changes,
but that the test needs to run whenever foo.so changes. The former is
less frequent then the latter, and time saving estimates, on average,
total a couple hours per day per developer since we are doing continuous
building of the codeline.]
I don't know, I have tried to solve it several different ways, but keep
coming back to the fundemental requirement that the target needs to have
the mod time set (touched) AND have gmake to ignore it (-o it). That is
why I asked about a $(old ...) function - which doesn't change the DAG, it
just tells the look-up of '...' that it is up-to-date.
thanks!
-sandy