Occasionally, it may be useful to specify that a certain file or directory must, if necessary, be built or created before some other target is built, but that changes to that file or directory do not require that the target itself be rebuilt. Such a relationship is called an order-only dependency because it only affects the order in which things must be built--the dependency before the target--but it is not a strict dependency relationship because the target should not change in response to changes in the dependent file.
For example, suppose that you want to create a file
every time you run a build
that identifies the time the build was performed,
the version number, etc.,
and which is included in every program that you build.
The version file's contents will change every build.
If you specify a normal dependency relationship,
then every program that depends on
that file would be rebuilt every time you ran SCons.
For example, we could use some Python code in
a SConstruct
file to create a new version.c
file
with a string containing the current date every time
we run SCons,
and then link a program with the resulting object file
by listing version.c
in the sources:
import time version_c_text = """ char *date = "%s"; """ % time.ctime(time.time()) open('version.c', 'w').write(version_c_text) hello = Program(['hello.c', 'version.c'])
If we list version.c
as an actual source file,
though, then the version.o
file
will get rebuilt every time we run SCons
(because the SConstruct
file itself changes
the contents of version.c
)
and the hello
executable
will get re-linked every time
(because the version.o
file changes):
%scons -Q hello
cc -o hello.o -c hello.c cc -o version.o -c version.c cc -o hello hello.o version.o %sleep 1
%scons -Q hello
cc -o version.o -c version.c cc -o hello hello.o version.o %sleep 1
%scons -Q hello
cc -o version.o -c version.c cc -o hello hello.o version.o
(Note that for the above example to work,
we sleep for one second in between each run,
so that the SConstruct
file will create a
version.c
file with a time string
that's one second later than the previous run.)
One solution is to use the Requires
function
to specify that the version.o
must be rebuilt before it is used by the link step,
but that changes to version.o
should not actually cause the hello
executable to be re-linked:
import time version_c_text = """ char *date = "%s"; """ % time.ctime(time.time()) open('version.c', 'w').write(version_c_text) version_obj = Object('version.c') hello = Program('hello.c', LINKFLAGS = str(version_obj[0])) Requires(hello, version_obj)
Notice that because we can no longer list version.c
as one of the sources for the hello
program,
we have to find some other way to get it into the link command line.
For this example, we're cheating a bit and stuffing the
object file name (extracted from version_obj
list returned by the Object
builder call)
into the $LINKFLAGS
variable,
because $LINKFLAGS
is already included
in the $LINKCOM
command line.
With these changes,
we get the desired behavior of only
re-linking the hello
executable
when the hello.c
has changed,
even though the version.o
is rebuilt
(because the SConstruct
file still changes the
version.c
contents directly each run):
%scons -Q hello
cc -o version.o -c version.c cc -o hello.o -c hello.c cc -o hello version.o hello.o %sleep 1
%scons -Q hello
cc -o version.o -c version.c scons: `hello' is up to date. %sleep 1
% [CHANGE THE CONTENTS OF hello.c] %scons -Q hello
cc -o version.o -c version.c cc -o hello.o -c hello.c cc -o hello version.o hello.o %sleep 1
%scons -Q hello
cc -o version.o -c version.c scons: `hello' is up to date.