Issue 1982: document GetLaunchDir() in the User's Guide.
[scons.git] / doc / user / misc.in
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   <para>
27
28   &SCons; supports a lot of additional functionality
29   that doesn't readily fit into the other chapters.
30
31   </para>
32
33   <section>
34   <title>Verifying the Python Version:  the &EnsurePythonVersion; Function</title>
35
36     <para>
37
38     Although the &SCons; code itself will run 
39     on any Python version 1.5.2 or later,
40     you are perfectly free to make use of
41     Python syntax and modules from more modern versions
42     (for example, Python 2.4 or 2.5)
43     when writing your &SConscript; files
44     or your own local modules.
45     If you do this, it's usually helpful to
46     configure &SCons; to exit gracefully with an error message
47     if it's being run with a version of Python
48     that simply won't work with your code.
49     This is especially true if you're going to use &SCons;
50     to build source code that you plan to distribute publicly,
51     where you can't be sure of the Python version
52     that an anonymous remote user might use
53     to try to build your software.
54
55     </para>
56
57     <para>
58
59     &SCons; provides an &EnsurePythonVersion; function for this.
60     You simply pass it the major and minor versions
61     numbers of the version of Python you require:
62
63     </para>
64
65     <!--
66
67     TODO:  Figure out how to generate the error message
68     regardless of executing Python version by faking out
69     the infrastructure in some way.
70
71     <scons_example name="EnsurePythonVersion">
72       <file name="SConstruct" printme="1">
73       EnsurePythonVersion(2, 5)
74       </file>
75     </scons_example>
76
77     -->
78
79     <sconstruct>
80       EnsurePythonVersion(2, 5)
81     </sconstruct>
82
83     <para>
84
85     And then &SCons will exit with the following error
86     message when a user runs it with an unsupported
87     earlier version of Python:
88
89     </para>
90
91     <!--
92
93     TODO:  Figure out how to generate the error message
94     regardless of executing Python version by faking out
95     the infrastructure in some way.
96
97     <scons_output example="EnsurePythonVersion">
98       <scons_output_command>scons -Q</scons_output_command>
99     </scons_output>
100
101     -->
102
103     <screen>
104       % <userinput>scons -Q</userinput>
105       Python 2.5 or greater required, but you have Python 2.3.6
106     </screen>
107
108   </section>
109
110   <section>
111   <title>Verifying the SCons Version:  the &EnsureSConsVersion; Function</title>
112
113     <para>
114
115     You may, of course, write your &SConscript; files
116     to use features that were only added in
117     recent versions of &SCons;.
118     When you publicly distribute software that is built using &SCons;,
119     it's helpful to have &SCons;
120     verify the version being used and
121     exit gracefully with an error message
122     if the user's version of &SCons; won't work
123     with your &SConscript; files.
124     &SCons; provides an &EnsureSConsVersion; function
125     that verifies the version of &SCons;
126     in the same
127     the &EnsurePythonVersion; function
128     verifies the version of Python,
129     by passing in the major and minor versions
130     numbers of the version of SCons you require:
131
132     </para>
133
134     <!--
135
136     TODO:  Figure out how to generate the error message
137     regardless of executing SCons version by faking out
138     the infrastructure in some way.
139
140     <scons_example name="EnsureSConsVersion">
141       <file name="SConstruct" printme="1">
142       EnsureSConsVersion(1, 0)
143       </file>
144     </scons_example>
145
146     -->
147
148     <sconstruct>
149       EnsureSConsVersion(1, 0)
150     </sconstruct>
151
152     <para>
153
154     And then &SCons will exit with the following error
155     message when a user runs it with an unsupported
156     earlier version of &SCons;:
157
158     </para>
159
160     <!--
161
162     TODO:  Figure out how to generate the error message
163     regardless of executing SCons version by faking out
164     the infrastructure in some way.
165
166     <scons_output example="EnsureSConsVersion">
167       <scons_output_command>scons -Q</scons_output_command>
168     </scons_output>
169
170     -->
171
172     <screen>
173       % <userinput>scons -Q</userinput>
174       SCons 1.0 or greater required, but you have SCons 0.98.5
175     </screen>
176
177   </section>
178
179   <section>
180   <title>Explicitly Terminating &SCons; While Reading &SConscript; Files:  the &Exit; Function</title>
181
182     <para>
183
184     &SCons; supports an &Exit; function
185     which can be used to terminate &SCons;
186     while reading the &SConscript; files,
187     usually because you've detected a condition
188     under which it doesn't make sense to proceed:
189
190     </para>
191
192     <scons_example name="Exit">
193       <file name="SConstruct" printme="1">
194       if ARGUMENTS.get('FUTURE'):
195           print "The FUTURE option is not supported yet!"
196           Exit(2)
197       env = Environment()
198       env.Program('hello.c')
199       </file>
200       <file name="hello.c">
201       hello.c
202       </file>
203     </scons_example>
204
205     <scons_output example="Exit">
206       <scons_output_command>scons -Q FUTURE=1</scons_output_command>
207       <scons_output_command>scons -Q</scons_output_command>
208     </scons_output>
209
210     <para>
211
212     The &Exit; function takes as an argument
213     the (numeric) exit status that you want &SCons; to exit with.
214     If you don't specify a value,
215     the default is to exit with <literal>0</literal>,
216     which indicates successful execution.
217
218     </para>
219
220     <para>
221
222     Note that the &Exit; function
223     is equivalent to calling the Python
224     <function>sys.exit</function> function
225     (which the it actually calls),
226     but because &Exit; is a &SCons; function,
227     you don't have to import the Python
228     <literal>sys</literal> module to use it.
229
230     </para>
231
232   </section>
233
234   <section>
235   <title>Handling Nested Lists:  the &Flatten; Function</title>
236
237     <para>
238
239     &SCons; supports a &Flatten; function
240     which takes an input Python sequence
241     (list or tuple)
242     and returns a flattened list
243     containing just the individual elements of
244     the sequence.
245     This can be handy when trying to examine
246     a list composed of the lists
247     returned by calls to various Builders.
248     For example, you might collect
249     object files built in different ways
250     into one call to the &Program; Builder
251     by just enclosing them in a list, as follows:
252
253     </para>
254
255     <scons_example name="Flatten1">
256       <file name="SConstruct" printme="1">
257       objects = [
258           Object('prog1.c'),
259           Object('prog2.c', CCFLAGS='-DFOO'),
260       ]
261       Program(objects)
262       </file>
263       <file name="prog1.c">
264       prog1.c
265       </file>
266       <file name="prog2.c">
267       prog2.c
268       </file>
269     </scons_example>
270
271     <para>
272
273     Because the Builder calls in &SCons;
274     flatten their input lists,
275     this works just fine to build the program:
276
277     </para>
278
279     <scons_output example="Flatten1">
280       <scons_output_command>scons -Q</scons_output_command>
281     </scons_output>
282
283     <para>
284
285     But if you were debugging your build
286     and wanted to print the absolute path
287     of each object file in the
288     <varname>objects</varname> list,
289     you might try the following simple approach,
290     trying to print each Node's
291     <literal>abspath</literal>
292     attribute:
293
294     </para>
295
296     <scons_example name="Flatten2">
297       <file name="SConstruct" printme="1">
298       objects = [
299           Object('prog1.c'),
300           Object('prog2.c', CCFLAGS='-DFOO'),
301       ]
302       Program(objects)
303
304       for object_file in objects:
305           print object_file.abspath
306       </file>
307       <file name="prog1.c">
308       prog1.c
309       </file>
310       <file name="prog2.c">
311       prog2.c
312       </file>
313     </scons_example>
314
315     <para>
316
317     This does not work as expected
318     because each call to <function>str</function>
319     is operating an embedded list returned by
320     each &Object; call,
321     not on the underlying Nodes within those lists:
322
323     </para>
324
325     <scons_output example="Flatten2">
326       <scons_output_command>scons -Q</scons_output_command>
327     </scons_output>
328
329     <para>
330
331     The solution is to use the &Flatten; function
332     so that you can pass each Node to
333     the <function>str</function> separately:
334
335     </para>
336
337     <scons_example name="Flatten3">
338       <file name="SConstruct" printme="1">
339       objects = [
340           Object('prog1.c'),
341           Object('prog2.c', CCFLAGS='-DFOO'),
342       ]
343       Program(objects)
344
345       for object_file in Flatten(objects):
346           print object_file.abspath
347       </file>
348       <file name="prog1.c">
349       prog1.c
350       </file>
351       <file name="prog2.c">
352       prog2.c
353       </file>
354     </scons_example>
355
356     <!--
357
358     TODO:  can't use this now because it displays the temporary path name
359
360     <scons_output example="Flatten3">
361       <scons_output_command>scons -Q</scons_output_command>
362     </scons_output>
363
364     -->
365
366     <screen>
367       % <userinput>scons -Q</userinput>
368       /home/me/project/prog1.o
369       /home/me/project/prog2.o
370       cc -o prog1.o -c prog1.c
371       cc -o prog2.o -c -DFOO prog2.c
372       cc -o prog1 prog1.o prog2.o
373     </screen>
374
375   </section>
376
377   <section>
378   <title>Finding the Invocation Directory:  the &GetLaunchDir; Function</title>
379
380     <para>
381
382     If you need to find the directory from
383     which the user invoked the &scons; command,
384     you can use the &GetLaunchDir; function:
385
386     </para>
387
388     <sconstruct>
389       env = Environment(
390           LAUNCHDIR = GetLaunchDir(),
391       )
392       env.Command('directory_build_info',
393                   '$LAUNCHDIR/build_info'
394                   Copy('$TARGET', '$SOURCE'))
395     </sconstruct>
396
397     <para>
398
399     Because &SCons; is usually invoked from the top-level
400     directory in which the &SConstruct; file lives,
401     the Python <function>os.getcwd()</function>
402     is often equivalent.
403     However, the &SCons;
404     <literal>-u</literal>,
405     <literal>-U</literal>
406     and
407     <literal>-D</literal>
408     command-line options,
409     when invoked from a subdirectory,
410     will cause &SCons; to change to the directory
411     in which the &SConstruct; file is found.
412     When those options are used,
413     &GetLaunchDir; will still return the path to the
414     user's invoking subdirectory,
415     allowing the &SConscript; configuration
416     to still get at configuration (or other) files
417     from the originating directory.
418
419     </para>
420
421   </section>