Eliminate / replace remaining cPickle references in test scripts.
[scons.git] / doc / user / nodes.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   <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     <programlisting>
62     Object('hello.c', CCFLAGS='-DHELLO')
63     Object('goodbye.c', CCFLAGS='-DGOODBYE')
64     </programlisting>
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     <programlisting>
77     Object('hello.c', CCFLAGS='-DHELLO')
78     Object('goodbye.c', CCFLAGS='-DGOODBYE')
79     Program(['hello.o', 'goodbye.o'])
80     </programlisting>
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     <programlisting>
104       hello_list = Object('hello.c', CCFLAGS='-DHELLO')
105       goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE')
106       Program(hello_list + goodbye_list)
107     </programlisting>
108
109     <para>
110
111     This makes our &SConstruct; file portable again,
112     the build output on Linux looking like:
113
114     </para>
115
116     <screen>
117        % <userinput>scons -Q</userinput>
118        cc -o goodbye.o -c -DGOODBYE goodbye.c
119        cc -o hello.o -c -DHELLO hello.c
120        cc -o hello hello.o goodbye.o
121     </screen>
122
123     <para>
124
125     And on Windows:
126
127     </para>
128
129     <screen>
130        C:\><userinput>scons -Q</userinput>
131        cl /Fogoodbye.obj /c goodbye.c -DGOODBYE
132        cl /Fohello.obj /c hello.c -DHELLO
133        link /nologo /OUT:hello.exe hello.obj goodbye.obj
134     </screen>
135
136     <para>
137
138     We'll see examples of using the list of nodes
139     returned by builder methods throughout
140     the rest of this guide.
141
142     </para>
143
144   </section>
145
146   <section>
147   <title>Explicitly Creating File and Directory Nodes</title>
148
149     <para>
150
151     It's worth mentioning here that
152     &SCons; maintains a clear distinction
153     between Nodes that represent files
154     and Nodes that represent directories.
155     &SCons; supports &File; and &Dir;
156     functions that, respectively,
157     return a file or directory Node:
158
159     </para>
160
161     <programlisting>
162       hello_c = File('hello.c')
163       Program(hello_c)
164
165       classes = Dir('classes')
166       Java(classes, 'src')
167     </programlisting>
168
169     <para>
170
171     Normally, you don't need to call
172     &File; or &Dir; directly,
173     because calling a builder method automatically
174     treats strings as the names of files or directories,
175     and translates them into
176     the Node objects for you.
177     The &File; and &Dir; functions can come in handy
178     in situations where you need to explicitly
179     instruct &SCons; about the type of Node being
180     passed to a builder or other function,
181     or unambiguously refer to a specific
182     file in a directory tree.
183     <!--
184     (For an example of when you might
185     need to use &File; or &Dir; to
186     prevent ambiguous interpretation of a string
187     naming a file or directory, see
188     <xref linkend="chap-hierarchy">.)
189     -->
190
191     </para>
192
193     <para>
194
195     There are also times when you may need to
196     refer to an entry in a file system
197     without knowing in advance
198     whether it's a file or a directory.
199     For those situations,
200     &SCons; also supports an &Entry; function,
201     which returns a Node
202     that can represent either a file or a directory.
203
204     </para>
205
206     <programlisting>
207     xyzzy = Entry('xyzzy')
208     </programlisting>
209
210     <para>
211
212     The returned <literal>xyzzy</literal> Node
213     will be turned into a file or directory Node
214     the first time it is used by a builder method
215     or other function that
216     requires one vs. the other.
217
218     </para>
219
220   </section>
221
222   <section>
223   <title>Printing &Node; File Names</title>
224
225     <para>
226
227     One of the most common things you can do
228     with a Node is use it to print the
229     file name that the node represents.
230     Keep in mind, though, that because the object
231     returned by a builder call
232     is a <emphasis>list</emphasis> of Nodes,
233     you must use Python subscripts
234     to fetch individual Nodes from the list.
235     For example, the following &SConstruct; file:
236
237     </para>
238
239     <programlisting>
240       hello_c = File('hello.c')
241       Program(hello_c)
242
243       classes = Dir('classes')
244       Java(classes, 'src')
245
246       object_list = Object('hello.c')
247       program_list = Program(object_list)
248       print "The object file is:", object_list[0]
249       print "The program file is:", program_list[0]
250     </programlisting>
251
252     <para>
253
254     Would print the following file names on a POSIX system:
255
256     </para>
257
258     <screen>
259       % <userinput>scons -Q</userinput>
260       The object file is: hello.o
261       The program file is: hello
262       cc -o hello.o -c hello.c
263       cc -o hello hello.o
264     </screen>
265
266     <para>
267
268     And the following file names on a Windows system:
269
270     </para>
271
272     <screen>
273       C:\><userinput>scons -Q</userinput>
274       The object file is: hello.obj
275       The program file is: hello.exe
276       cl /Fohello.obj /c hello.c /nologo
277       link /nologo /OUT:hello.exe hello.obj
278     </screen>
279
280     <para>
281
282     Note that in the above example,
283     the <literal>object_list[0]</literal>
284     extracts an actual Node <emphasis>object</emphasis>
285     from the list,
286     and the Python <literal>print</literal> statement
287     converts the object to a string for printing.
288
289     </para>
290
291   </section>
292
293   <section>
294   <title>Using a &Node;'s File Name as a String</title>
295
296     <para>
297
298     Printing a &Node;'s name
299     as described in the previous section
300     works because the string representation of a &Node; object
301     is the name of the file.
302     If you want to do something other than
303     print the name of the file,
304     you can fetch it by using the builtin Python
305     &str; function.
306     For example, if you want to use the Python
307     <function>os.path.exists</function>
308     to figure out whether a file
309     exists while the &SConstruct; file
310     is being read and executed,
311     you can fetch the string as follows:
312
313     </para>
314
315     <programlisting>
316       import os.path
317       program_list = Program('hello.c')
318       program_name = str(program_list[0])
319       if not os.path.exists(program_name):
320           print program_name, "does not exist!"
321     </programlisting>
322
323     <para>
324
325     Which executes as follows on a POSIX system:
326
327     </para>
328
329     <screen>
330       % <userinput>scons -Q</userinput>
331       hello does not exist!
332       cc -o hello.o -c hello.c
333       cc -o hello hello.o
334     </screen>
335
336   </section>
337
338   <!--
339
340   <section>
341   <title>Fetching the Contents of a &Node;</title>
342
343     <para>
344
345     XXX Describe using read() and readlines()
346     when we add that as a public interface.
347
348     </para>
349
350     <scons_example name="read">
351       <file name="SConstruct" printme="1">
352       hello_c = File('hello.c')
353       contents = hello_c.read()
354       print "contents are:"
355       print contents
356       </file>
357       <file name="hello.c">
358       int main() { printf("Hello, world!\n"); }
359       </file>
360     </scons_example>
361
362     <para>
363
364     Which executes as follows on a POSIX system:
365
366     </para>
367
368     <scons_output example="read" os="posix">
369       <scons_output_command>scons -Q</scons_output_command>
370     </scons_output>
371
372   </section>
373
374   -->
375
376   <!--
377
378   <section>
379   <title>Python Value &Node;</title>
380
381     <para>
382
383     XXX Value()
384
385     </para>
386
387   </section>
388
389   -->