Sometimes a program the you need to call
to build a target file
will also update another file,
such as a log file describing what the program
does while building the target.
For example, we the folowing configuration
would have &SCons; invoke a hypothetical
script named build
(in the local directory)
with command-line arguments that write
log information to a common
logfile.txt file:
env = Environment()
env.Command('file1.out', 'file.in',
'./build --log logfile.txt $SOURCE $TARGET')
env.Command('file2.out', 'file.in',
'./build --log logfile.txt $SOURCE $TARGET')
This can cause problems when running
the build in parallel if
&SCons; decides to update both targets
by running both program invocations at the same time.
The multiple program invocations
may interfere with each other
writing to the common log file,
leading at best to intermixed output in the log file,
and at worst to an actual failed build
(on a system like Windows, for example,
where only one process at a time can open the log file for writing).
We can make sure that &SCons; does not
run these build
commands at the same time
by using the &SideEffect; function
to specify that updating
the logfile.txt file
is a side effect of building the specified
file1
and
file2
target files:
env = Environment()
f1 = env.Command('file1.out', 'file1.in',
'./build --log logfile.txt $SOURCE $TARGET')
f2 = env.Command('file2.out', 'file2.in',
'./build --log logfile.txt $SOURCE $TARGET')
env.SideEffect('logfile.txt', f1 + f2)
file1.in
file2.in
cat
This makes sure the the two
./build steps are run sequentially,
even withthe --jobs=2 in the command line:
scons -Q --jobs=2
The &SideEffect; function can be called multiple
times for the same side-effect file.
Additionally, the name used as a &SideEffect; does not
even need to actually exist as a file on disk.
&SCons; will still make sure
that the relevant targets
will be executed sequentially, not in parallel:
env = Environment()
f1 = env.Command('file1.out', [], 'echo >$TARGET data1')
env.SideEffect('not_really_updated', f1)
f2 = env.Command('file2.out', [], 'echo >$TARGET data2')
env.SideEffect('not_really_updated', f2)
scons -Q --jobs=2
Note that it might be tempting to
use &SideEffect; for additional target files
that a command produces.
For example, versions the Microsoft Visual C/C++ compiler
produce a foo.ilk
alongside compiling foo.obj file.
Specifying foo.ilk as a
side-effect of foo.obj
is not a recommended use of &SideEffect;,
because &SCons; handle side-effect files
slightly differently in its analysis of the dependency graph.
When a command produces multiple output files,
they should be specified as multiple targets of
the call to the relevant builder function,
and the &SideEffect; function itself should really only be used
when it's important to ensure that commands are not executed in parallel,
such as when a "peripheral" file (such as a log file)
may actually updated by more than one command invocation.