http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / doc / user / nodes.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   Internally, &SCons; represents all of the files
29   and directories it knows about as &Nodes;.
30   These internal objects
31   (not object <emphasis>files</emphasis>)
32   can be used in a variety of ways
33   to make your &SConscript;
34   files portable and easy to read.
35
36   </para>
37
38   <section>
39   <title>Builder Methods Return Lists of Target Nodes</title>
40
41     <para>
42
43     All builder methods return a list of
44     &Node; objects that identify the
45     target file or files that will be built.
46     These returned &Nodes; can be passed
47     as arguments to other builder methods.
48
49     </para>
50
51     <para>
52
53     For example, suppose that we want to build
54     the two object files that make up a program with different options.
55     This would mean calling the &b-link-Object;
56     builder once for each object file,
57     specifying the desired options:
58
59     </para>
60
61     <sconstruct>
62     Object('hello.c', CCFLAGS='-DHELLO')
63     Object('goodbye.c', CCFLAGS='-DGOODBYE')
64     </sconstruct>
65
66     <para>
67
68     One way to combine these object files
69     into the resulting program
70     would be to call the &b-link-Program;
71     builder with the names of the object files
72     listed as sources:
73
74     </para>
75
76     <sconstruct>
77     Object('hello.c', CCFLAGS='-DHELLO')
78     Object('goodbye.c', CCFLAGS='-DGOODBYE')
79     Program(['hello.o', 'goodbye.o'])
80     </sconstruct>
81
82     <para>
83
84     The problem with specifying the names as strings
85     is that our &SConstruct; file is no longer portable
86     across operating systems.
87     It won't, for example, work on Windows
88     because the object files there would be
89     named &hello_obj; and &goodbye_obj;,
90     not &hello_o; and &goodbye_o;.
91
92     </para>
93
94     <para>
95
96     A better solution is to assign the lists of targets
97     returned by the calls to the &b-Object; builder to variables,
98     which we can then concatenate in our
99     call to the &b-Program; builder:
100
101     </para>
102
103     <scons_example name="ex1">
104       <file name="SConstruct" printme="1">
105       hello_list = Object('hello.c', CCFLAGS='-DHELLO')
106       goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE')
107       Program(hello_list + goodbye_list)
108       </file>
109       <file name="hello.c">
110       int main() { printf("Hello, world!\n"); }
111       </file>
112       <file name="goodbye.c">
113       int main() { printf("Goodbye, world!\n"); }
114       </file>
115     </scons_example>
116
117     <para>
118
119     This makes our &SConstruct; file portable again,
120     the build output on Linux looking like:
121
122     </para>
123
124     <scons_output example="ex1" os="posix">
125        <scons_output_command>scons -Q</scons_output_command>
126     </scons_output>
127
128     <para>
129
130     And on Windows:
131
132     </para>
133
134     <scons_output example="ex1" os="win32">
135        <scons_output_command>scons -Q</scons_output_command>
136     </scons_output>
137
138     <para>
139
140     We'll see examples of using the list of nodes
141     returned by builder methods throughout
142     the rest of this guide.
143
144     </para>
145
146   </section>
147
148   <section>
149   <title>Explicitly Creating File and Directory Nodes</title>
150
151     <para>
152
153     It's worth mentioning here that
154     &SCons; maintains a clear distinction
155     between Nodes that represent files
156     and Nodes that represent directories.
157     &SCons; supports &File; and &Dir;
158     functions that, respectively,
159     return a file or directory Node:
160
161     </para>
162
163     <scons_example name="print">
164       <file name="SConstruct" printme="1">
165       hello_c = File('hello.c')
166       Program(hello_c)
167
168       classes = Dir('classes')
169       Java(classes, 'src')
170       </file>
171     </scons_example>
172
173     <para>
174
175     Normally, you don't need to call
176     &File; or &Dir; directly,
177     because calling a builder method automatically
178     treats strings as the names of files or directories,
179     and translates them into
180     the Node objects for you.
181     The &File; and &Dir; functions can come in handy
182     in situations where you need to explicitly
183     instruct &SCons; about the type of Node being
184     passed to a builder or other function,
185     or unambiguously refer to a specific
186     file in a directory tree.
187     <!--
188     (For an example of when you might
189     need to use &File; or &Dir; to
190     prevent ambiguous interpretation of a string
191     naming a file or directory, see
192     <xref linkend="chap-hierarchy">.)
193     -->
194
195     </para>
196
197     <para>
198
199     There are also times when you may need to
200     refer to an entry in a file system
201     without knowing in advance
202     whether it's a file or a directory.
203     For those situations,
204     &SCons; also supports an &Entry; function,
205     which returns a Node
206     that can represent either a file or a directory.
207
208     </para>
209
210     <sconstruct>
211     xyzzy = Entry('xyzzy')
212     </sconstruct>
213
214     <para>
215
216     The returned <literal>xyzzy</literal> Node
217     will be turned into a file or directory Node
218     the first time it is used by a builder method
219     or other function that
220     requires one vs. the other.
221
222     </para>
223
224   </section>
225
226   <section>
227   <title>Printing &Node; File Names</title>
228
229     <para>
230
231     One of the most common things you can do
232     with a Node is use it to print the
233     file name that the node represents.
234     Keep in mind, though, that because the object
235     returned by a builder call
236     is a <emphasis>list</emphasis> of Nodes,
237     you must use Python subscripts
238     to fetch individual Nodes from the list.
239     For example, the following &SConstruct; file:
240
241     </para>
242
243     <scons_example name="print">
244       <file name="SConstruct" printme="1">
245       object_list = Object('hello.c')
246       program_list = Program(object_list)
247       print "The object file is:", object_list[0]
248       print "The program file is:", program_list[0]
249       </file>
250       <file name="hello.c">
251       int main() { printf("Hello, world!\n"); }
252       </file>
253     </scons_example>
254
255     <para>
256
257     Would print the following file names on a POSIX system:
258
259     </para>
260
261     <scons_output example="print" os="posix">
262       <scons_output_command>scons -Q</scons_output_command>
263     </scons_output>
264
265     <para>
266
267     And the following file names on a Windows system:
268
269     </para>
270
271     <scons_output example="print" os="win32">
272       <scons_output_command>scons -Q</scons_output_command>
273     </scons_output>
274
275     <para>
276
277     Note that in the above example,
278     the <literal>object_list[0]</literal>
279     extracts an actual Node <emphasis>object</emphasis>
280     from the list,
281     and the Python <literal>print</literal> statement
282     converts the object to a string for printing.
283
284     </para>
285
286   </section>
287
288   <section>
289   <title>Using a &Node;'s File Name as a String</title>
290
291     <para>
292
293     Printing a &Node;'s name
294     as described in the previous section
295     works because the string representation of a &Node; object
296     is the name of the file.
297     If you want to do something other than
298     print the name of the file,
299     you can fetch it by using the builtin Python
300     &str; function.
301     For example, if you want to use the Python
302     <function>os.path.exists</function>
303     to figure out whether a file
304     exists while the &SConstruct; file
305     is being read and executed,
306     you can fetch the string as follows:
307
308     </para>
309
310     <scons_example name="exists">
311       <file name="SConstruct" printme="1">
312       import os.path
313       program_list = Program('hello.c')
314       program_name = str(program_list[0])
315       if not os.path.exists(program_name):
316           print program_name, "does not exist!"
317       </file>
318       <file name="hello.c">
319       int main() { printf("Hello, world!\n"); }
320       </file>
321     </scons_example>
322
323     <para>
324
325     Which executes as follows on a POSIX system:
326
327     </para>
328
329     <scons_output example="exists" os="posix">
330       <scons_output_command>scons -Q</scons_output_command>
331     </scons_output>
332
333   </section>
334
335   <!--
336
337   <section>
338   <title>Fetching the Contents of a &Node;</title>
339
340     <para>
341
342     XXX Describe using read() and readlines()
343     when we add that as a public interface.
344
345     </para>
346
347     <scons_example name="read">
348       <file name="SConstruct" printme="1">
349       hello_c = File('hello.c')
350       contents = hello_c.read()
351       print "contents are:"
352       print contents
353       </file>
354       <file name="hello.c">
355       int main() { printf("Hello, world!\n"); }
356       </file>
357     </scons_example>
358
359     <para>
360
361     Which executes as follows on a POSIX system:
362
363     </para>
364
365     <scons_output example="read" os="posix">
366       <scons_output_command>scons -Q</scons_output_command>
367     </scons_output>
368
369   </section>
370
371   -->
372
373   <!--
374
375   <section>
376   <title>Python Value &Node;</title>
377
378     <para>
379
380     XXX Value()
381
382     </para>
383
384   </section>
385
386   -->