Merged revisions 3057-3059,3061-3264 via svnmerge from
[scons.git] / doc / user / sideeffect.xml
1 <!--
2
3   __COPYRIGHT__
4
5   Permission is hereby granted, free of charge, to any person obtaining
6   a copy of this software and associated documentation files (the
7   "Software"), to deal in the Software without restriction, including
8   without limitation the rights to use, copy, modify, merge, publish,
9   distribute, sublicense, and/or sell copies of the Software, and to
10   permit persons to whom the Software is furnished to do so, subject to
11   the following conditions:
12
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15
16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17   KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18   WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 -->
25
26  <!--
27
28  <para>
29
30  If &SCons; is unaware that a build step produces an extra file,
31  the &SideEffect; method can be used to identify it,
32  so that the file can be used as a dependency in subsequent build steps.
33  However, the primary use for the &SideEffect; method
34  is to prevent two build steps from simultaneously modifying the same file.
35
36  </para>
37
38  TODO: currently doesn't work due to issue #2154:
39  http://scons.tigris.org/issues/show_bug.cgi?id=2154
40
41  <para>
42
43  If more than one build step creates or manipulates the same file,
44  it can cause unpleasant results if both build steps are run at the same time.
45  The shared file is declared as a side-effect of building the primary targets
46  and &SCons; will prevent the two build steps from running in parallel.
47
48  </para>
49
50  <para>
51
52  In this example, the <filename>SConscript</filename> uses
53  &SideEffect; to inform &SCons; about the additional output file.
54
55  </para>
56
57  <scons_example name="SideEffectSimple">
58    <file name="SConstruct" printme="1">
59     env = Environment()
60     f2 = env.Command('file2', 'log', Copy('$TARGET', '$SOURCE'))
61     f1 = env.Command('file1', [],
62         'echo >$TARGET data1; echo >log updated file1'))
63     env.SideEffect('log', env.Command('file1', [],
64         'echo >$TARGET data1; echo >log updated file1'))
65    </file>
66  </scons_example>
67
68  <para>
69
70  Even when run in parallel mode, &SCons; will run the two steps in order:
71
72  </para>
73
74  <scons_output example="SideEffectSimple">
75     <scons_output_command>scons -Q --jobs=2</scons_output_command>
76  </scons_output>
77
78  -->
79
80  <para>
81
82  Sometimes a program the you need to call
83  to build a target file
84  will also update another file,
85  such as a log file describing what the program
86  does while building the target.
87  For example, we the folowing configuration
88  would have &SCons; invoke a hypothetical
89  script named <application>build</application>
90  (in the local directory)
91  with command-line arguments that write
92  log information to a common
93  <filename>logfile.txt</filename> file:
94
95  </para>
96
97  <screen>
98  env = Environment()
99  env.Command('file1.out', 'file.in',
100              './build --log logfile.txt $SOURCE $TARGET')
101  env.Command('file2.out', 'file.in',
102              './build --log logfile.txt $SOURCE $TARGET')
103  <screen>
104
105  <para>
106
107  This can cause problems when running
108  the build in parallel if
109  &SCons; decides to update both targets
110  by running both program invocations at the same time.
111  The multiple program invocations
112  may interfere with each other
113  writing to the common log file,
114  leading at best to intermixed output in the log file,
115  and at worst to an actual failed build
116  (on a system like Windows, for example,
117  where only one process at a time can open the log file for writing).
118
119  </para>
120
121  <para>
122
123  We can make sure that &SCons; does not
124  run these <application>build</application>
125  commands at the same time
126  by using the &SideEffect; function
127  to specify that updating
128  the <filename>logfile.txt</filename> file
129  is a side effect of building the specified
130  <filename>file1</filename>
131  and
132  <filename>file2</filename>
133  target files:
134
135  </para>
136
137  <programlisting>
138    env = Environment()
139    f1 = env.Command('file1.out', 'file1.in',
140                     './build --log logfile.txt $SOURCE $TARGET')
141    f2 = env.Command('file2.out', 'file2.in',
142                     './build --log logfile.txt $SOURCE $TARGET')
143    env.SideEffect('logfile.txt', f1 + f2)
144  </programlisting>
145
146  <para>
147
148  </para>
149
150  <para>
151
152  This makes sure the the two
153  <application>./build</application> steps are run sequentially,
154  even withthe <filename>--jobs=2</filename> in the command line:
155
156  </para>
157
158  <screen>
159     % <userinput>scons -Q --jobs=2</userinput>
160     ./build --log logfile.txt file1.in file1.out
161     ./build --log logfile.txt file2.in file2.out
162  </screen>
163
164  <para>
165
166  The &SideEffect; function can be called multiple
167  times for the same side-effect file.
168  Additionally, the name used as a &SideEffect; does not
169  even need to actually exist as a file on disk.
170  &SCons; will still make sure
171  that the relevant targets
172  will be executed sequentially, not in parallel:
173
174  </para>
175
176  <programlisting>
177     env = Environment()
178     f1 = env.Command('file1.out', [], 'echo &gt;$TARGET data1')
179     env.SideEffect('not_really_updated', f1)
180     f2 = env.Command('file2.out', [], 'echo &gt;$TARGET data2')
181     env.SideEffect('not_really_updated', f2)
182  </programlisting>
183
184  <screen>
185     % <userinput>scons -Q --jobs=2</userinput>
186     echo &gt; file1.out data1
187     echo &gt; file2.out data2
188  </screen>
189
190  <para>
191
192  Note that it might be tempting to
193  use &SideEffect; for additional target files
194  that a command produces.
195  For example, versions the Microsoft Visual C/C++ compiler
196  produce a <filename>foo.ilk</filename>
197  alongside compiling <filename>foo.obj</filename> file.
198  Specifying <filename>foo.ilk</filename> as a
199  side-effect of <filename>foo.obj</filename>
200  is <emphasis>not</emphasis> a recommended use of &SideEffect;,
201  because &SCons; handle side-effect files
202  slightly differently in its analysis of the dependency graph.
203  When a command produces multiple output files,
204  they should be specified as multiple targets of
205  the call to the relevant builder function,
206  and the &SideEffect; function itself should really only be used
207  when it's important to ensure that commands are not executed in parallel,
208  such as when a "peripheral" file (such as a log file)
209  may actually updated by more than one command invocation.
210
211  </para>