diff options
author | Steven Knight <knight@baldmt.com> | 2003-03-25 05:13:22 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2003-03-25 05:13:22 (GMT) |
commit | c24f1504b711f871c0c4310a460727ac1a859936 (patch) | |
tree | ba6a8eb0d60129fab1da2c249696500580d0c699 /doc/user | |
parent | 8d8e5b7a7edcfb7ac3795977c33c7f6e561abdda (diff) | |
download | SCons-c24f1504b711f871c0c4310a460727ac1a859936.zip SCons-c24f1504b711f871c0c4310a460727ac1a859936.tar.gz SCons-c24f1504b711f871c0c4310a460727ac1a859936.tar.bz2 |
Branch for in-progress User's Guide changes.
Diffstat (limited to 'doc/user')
-rw-r--r-- | doc/user/alias.sgml | 71 | ||||
-rw-r--r-- | doc/user/builders.sgml | 375 | ||||
-rw-r--r-- | doc/user/caching.sgml | 242 | ||||
-rw-r--r-- | doc/user/command.sgml | 79 | ||||
-rw-r--r-- | doc/user/default.sgml | 10 | ||||
-rw-r--r-- | doc/user/depends.sgml | 662 | ||||
-rw-r--r-- | doc/user/environments.sgml | 391 | ||||
-rw-r--r-- | doc/user/help.sgml | 2 | ||||
-rw-r--r-- | doc/user/hierarchy.sgml | 207 | ||||
-rw-r--r-- | doc/user/install.sgml | 246 | ||||
-rw-r--r-- | doc/user/library.sgml | 81 | ||||
-rw-r--r-- | doc/user/main.sgml | 76 | ||||
-rw-r--r-- | doc/user/more.sgml | 63 | ||||
-rw-r--r-- | doc/user/object.sgml | 71 | ||||
-rw-r--r-- | doc/user/precious.sgml | 46 | ||||
-rw-r--r-- | doc/user/program.sgml | 77 | ||||
-rw-r--r-- | doc/user/reference.sgml | 63 | ||||
-rw-r--r-- | doc/user/repositories.sgml | 530 | ||||
-rw-r--r-- | doc/user/separate.sgml | 211 | ||||
-rw-r--r-- | doc/user/simple.sgml | 6 | ||||
-rw-r--r-- | doc/user/sourcecode.sgml | 144 | ||||
-rw-r--r-- | doc/user/variants.sgml | 21 |
22 files changed, 2385 insertions, 1289 deletions
diff --git a/doc/user/alias.sgml b/doc/user/alias.sgml index 33c236a..3f48ee0 100644 --- a/doc/user/alias.sgml +++ b/doc/user/alias.sgml @@ -23,23 +23,72 @@ --> -<!-- + <para> ---> + We've already seen how you can use the &Alias; + function to create a target named <literal>install</literal>: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + You can then use this alias on the command line + to tell &SCons; more naturally that you want to install files: + + </para> + + <literallayout> + % <userinput>scons install</userinput> + Install file: "hello" as "/usr/bin/hello" + </literallayout> - <para> + <para> - X + Like other &Builder; methods, though, + the &Alias; method returns an object + representing the alias being built. + You can then use this object as input to anothother &Builder;. + This is especially useful if you use such an object + as input to another call to the &Alias; &Builder;, + allowing you to create a hierarchy + of nested aliases: - </para> + </para> - <section> - <title>Alias Targets</title> + <programlisting> + env = Environment() + p = env.Program('hello.c') + l = env.Library('hello.c') + env.Install('/usr/bin', p) + env.Install('/usr/lib', l) + ib = env.Alias('install-bin', '/usr/bin') + il = env.Alias('install-lib', '/usr/lib') + env.Alias('install', [ib, il]) + </programlisting> - <para> + <para> - X + This example defines separate <literal>install</literal>, + <literal>install-bin</literal>, + and <literal>install-lib</literal> aliases, + allowing you finer control over what gets installed: - </para> + </para> - </section> + <literallayout> + % <userinput>scons install-bin</userinput> + Install file: "hello" as "/usr/bin/hello" + % <userinput>scons install-lib</userinput> + Install file: "libhello.a" as "/usr/lib/libhello.a" + % <userinput>scons -c /</userinput> + % <userinput>scons install</userinput> + Install file: "hello" as "/usr/bin/hello" + Install file: "libhello.a" as "/usr/lib/libhello.a" + </literallayout> diff --git a/doc/user/builders.sgml b/doc/user/builders.sgml index ac5f193..c1b4269 100644 --- a/doc/user/builders.sgml +++ b/doc/user/builders.sgml @@ -95,30 +95,375 @@ This functionality could be invoked as in the following example: --> - <para> + <para> + + &SCons; provides many useful methods + for building common software products: + programs, libraries, documents. + Frequently, however, you want to be + able to build some other type of file + not supported directly by &SCons; + Fortunately, &SCons; makes it very easy + to define your own &Builder; objects + for any custom file types you want to build. + + </para> + + <section> + <title>Builders That Execute External Commands</title> + + <para> + + The simplest &Builder; to create is + one that executes an external command. + For example, if we want to build + an output file by running the contents + of the input file through a command named + <literal>foobuild</literal>, + creating that &Builder; might look like: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $TARGET > $SOURCE') + </programlisting> + + </section> + + <section> + <title>Attaching a Builder to a &ConsEnv;</title> + + <para> + + A &Builder; object by itself, though, + isn't useful until it's attached to a &consenv; + so that we can call it to arrange + for files to be built. + This is done through the &BUILDERS; + &consvar; in an environment. + The &BUILDERS; variable is a Python dictionary + that maps the names by which you want to call various &Builder; + to the &Builder; objects themselves. + For example, if we want to call the + &Builder; we defined by the name + <function>Foo</function>, + our &SConstruct; file might look like: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $TARGET > $SOURCE') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + </programlisting> + + <para> + + Then when we run &SCons; it looks like: + + </para> + + <literallayout> + % <userinput>scons</userinput> + foobuild < file.input > file.foo + </literallayout> + + <para> + + Note, however, that the default &BUILDERS; + variable in a &consenv; + comes with a default set of &Builder; objects + already defined: + &Program;, &Library;, etc. + And when we explicitly set the &BUILDERS; variable + when we create the &consenv;, + the default &Builder;s are no longer part of + the environment: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $TARGET > $SOURCE') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + other errors + Traceback (most recent call last): + File "/usr/lib/scons/SCons/Script/__init__.py", line 901, in main + _main() + File "/usr/lib/scons/SCons/Script/__init__.py", line 762, in _main + SCons.Script.SConscript.SConscript(script) + File "/usr/lib/scons/SCons/Script/SConscript.py", line 207, in SConscript + exec _file_ in stack[-1].globals + File "SConstruct", line 4, in ? + env.Program('hello.c') + scons: Environment instance has no attribute 'Program' + </literallayout> + + <para> + + To be able use both our own defined &Builder; objects + and the default &Builder; objects in the same &consenv;, + you can either add to the &BUILDERS; variable + using the &Append; function: + + </para> + + <programlisting> + env = Environment() + bld = Builder(action = 'foobuild < $TARGET > $SOURCE') + env.Append(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <para> + + Or you can explicitly set the appropriately-named + key in the &BUILDERS; dictionary: + + </para> + + <programlisting> + env = Environment() + bld = Builder(action = 'foobuild < $TARGET > $SOURCE') + env['BUILDERS']['Foo'] = bld + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + </programlisting> + + <para> + + Either way, the same &consenv; + can then use both the newly-defined + <function>Foo</function> &Builder; + and the default &Program; &Builder;: + + </para> + + <literallayout> + % <userinput>scons</userinput> + foobuild < file.input > file.foo + cc -c hello.c -o hello.o + cc -o hello hello.o + </literallayout> + + </section> + + <section> + <title>Letting &SCons; Handle The File Suffixes</title> + + <para> + + By supplying additional information + when you create a &Builder;, + you can let &SCons; add appropriate file + suffixes to the target and/or the source file. + For example, rather than having to specify + explicitly that you want the <literal>Foo</literal> + &Builder; to build the <literal>file.foo</literal> + target file from the <literal>file.input</literal> source file, + you can give the <literal>.foo</literal> + and <literal>.input</literal> suffixes to the &Builder;, + making for more compact and readable calls to + the <literal>Foo</literal> &Builder;: + + </para> + + <programlisting> + bld = Builder(action = 'foobuild < $TARGET > $SOURCE', + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file1') + env.Foo('file2') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + foobuild < file1.input > file1.foo + foobuild < file2.input > file2.foo + </literallayout> + + <para> + + You can also supply a <literal>prefix</literal> keyword argument + if it's appropriate to have &SCons; append a prefix + to the beginning of target file names. + + </para> + + </section> - X + <section> + <title>Builders That Execute Python Functions</title> - </para> + <para> - <section> - <title>Builders That Execute External Commands</title> + In &SCons;, you don't have to call an external command + to build a file. + You can, instead, define a Python function + that a &Builder; object can invoke + to build your target file (or files). - <para> + </para> - X + <programlisting> + def build_function(target, source, env): + # XXX + return None + </programlisting> - </para> + <para> - </section> + XXX explain the function + XXX define the arguments - <section> - <title>Builders That Execute Python Functions</title> + </para> - <para> + <para> - X + Once you've defined the Python function + that will build your target file, + defining a &Builder; object for it is as + simple as specifying the name of the function, + instead of an external command, + as the &Builder;'s + <literal>action</literal> + argument: + + </para> + + <programlisting> + def build_function(target, source, env): + # XXX + return None + bld = Builder(action = build_function, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <para> + + And notice that the output changes slightly, + reflecting the fact that a Python function, + not an external command, + is now called to build the target file: + + </para> + + <literallayout> + % <userinput>scons</userinput> + build_function("file.foo", "file.input") + </literallayout> + + </section> + + <section> + <title>Builders That Generate Actions</title> - </para> + <para> - </section> + X + + </para> + + <programlisting> + def generate_actions(XXX): + return XXX + bld = Builder(generator = generate_actions, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + <para> + + Note that it's illegal to specify both an + <literal>action</literal> + and a + <literal>generator</literal> + for a &Builder;. + + </para> + + </section> + + <section> + <title>Builders That Modify the Target List</title> + + <para> + + X + + </para> + + <programlisting> + def modify_targets(XXX): + return XXX + bld = Builder(action = 'XXX', + suffix = '.foo', + src_suffix = '.input', + emitter = modify_targets) + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + <programlisting> + bld = Builder(action = 'XXX', + suffix = '.foo', + src_suffix = '.input', + emitter = 'MY_EMITTER') + def modify1(XXX): + return XXX + def modify2(XXX): + return XXX + env1 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify1) + env2 = Environment(BUILDERS = {'Foo' : bld}, + MY_EMITTER = modify2) + env1.Foo('file1') + env2.Foo('file2') + </programlisting> + + </section> + + <section> + <title>Builders That Use Other Builders</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.BitKeeper('XXX') + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> diff --git a/doc/user/caching.sgml b/doc/user/caching.sgml index 5403c43..ed72c1e 100644 --- a/doc/user/caching.sgml +++ b/doc/user/caching.sgml @@ -23,30 +23,242 @@ --> -<!-- + <para> -=head2 The C<UseCache> method + On multi-developer software projects, + you can sometimes speed up every developer's builds a lot by + allowing them to share the derived files that they build. + &SCons; makes this easy, as well as reliable. -The C<UseCache> method instructs Cons to maintain a cache of derived -files, to be shared among separate build trees of the same project. + </para> - UseCache("cache/<buildname>") || warn("cache directory not found"); + <section> + <title>Specifying the Shared Cache Directory</title> ---> + <para> + + To enable sharing of derived files, + use the &CacheDir; function + in any &SConscript; file: + + </para> + + <programlisting> + CacheDir('/usr/local/build_cache') + </programlisting> + + <para> + + Note that the directory you specify must already exist + and be readable and writable by all developers + who will be sharing derived files. + It should also be in some central location + that all builds will be able to access. + In environments where developers are using separate systems + (like individual workstations) for builds, + this directory would typically be + on a shared or NFS-mounted file system. + + </para> + + <para> + + Here's what happens: + When a build has a &CacheDir; specified, + every time a file is built, + it is stored in the shared cache directory + along with its MD5 build signature. + On subsequent builds, + before an action is invoked to build a file, + &SCons; will check the shared cache directory + to see if a file with the exact same build + signature already exists. + If so, the derived file will not be built locally, + but will be copied into the local build directory + from the shared cache directory, + like so: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -c</userinput> + % <userinput>scons</userinput> + Retrieved `hello.o' from cache + Retrieved `hello' from cache + % + </literallayout> + + </section> + + <section> + <title>Keeping Build Output Consistent</title> + + <para> + + One potential drawback to using a shared cache + is that your build output can be inconsistent + from invocation to invocation, + because any given file may be rebuilt one time + and retrieved from the shared cache the next time. + This can make analyzing build output more difficult, + especially for automated scripts that + expect consistent output each time. + + </para> + + <para> + + If, however, you use the <literal>--cache-show</literal> option, + &SCons; will print the command line that it + <emphasis>would</emphasis> have executed + to build the file, + even when it is retrieving the file from the shared cache. + This makes the build output consistent + every time the build is run: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons --cache-show</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + <para> + + The trade-off, of course, is that you no longer + know whether or not &SCons; + has retrieved a derived file from cache + or has rebuilt it locally. + + </para> + + </section> + + <section> + <title>Not Retrieving Files From a Shared Cache</title> + + <para> + + Retrieving an already-built file + from the shared cache + is usually a significant time-savings + over rebuilding the file, + but how much of a savings + (or even whether it saves time at all) + can depend a great deal on your + system or network configuration. + For example, retrieving cached files + from a busy server over a busy network + might end up being slower than + rebuilding the files locally. + + </para> + + <para> + + In these cases, you can specify + the <literal>--cache-disable</literal> + command-line option to tell &SCons; + to not retrieve already-built files from the + shared cache directory: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons</userinput> + Retrieved `hello.o' from cache + Retrieved `hello' from cache + % <userinput>scons -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons --cache-disable</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + </section> + + <section> + <title>Populating a Shared Cache With Already-Built Files</title> + + <para> + + Sometimes, you may have one or more derived files + already built in your local build tree + that you wish to make available to other people doing builds. + For example, you may find it more effective to perform + integration builds with the cache disabled + (per the previous section) + and only populate the shared cache directory + with the built files after the integration build + has completed successfully. + This way, the cache will only get filled up + with derived files that are part of a complete, successful build + not with files that might be later overwritten + while you debug integration problems. + + </para> - <para> + <para> - X + In this case, you can use the + the <literal>--cache-force</literal> option + to tell &SCons; to put all derived files in the cache, + even if the files had already been built + by a previous invocation: - </para> + </para> - <section> - <title>The &Cache; Method</title> + <literallayout> + % <userinput>scons --cache-disable</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons --cache-disable</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons --cache-force</userinput> + % <userinput>scons -c</userinput> + Removed hello.o + Removed hello + % <userinput>scons</userinput> + Retrieved `hello.o' from cache + Retrieved `hello' from cache + % + </literallayout> - <para> + <para> - X + Notice how the above sample run + demonstrates that the <literal>--cache-disable</literal> + option avoids putting the built + <filename>hello.o</filename> + and + <filename>hello</filename> files in the cache, + but after using the <literal>--cache-force</literal> option, + the files have been put in the cache + for the next invocation to retrieve. - </para> + </para> - </section> + </section> diff --git a/doc/user/command.sgml b/doc/user/command.sgml index abb3a58..945c656 100644 --- a/doc/user/command.sgml +++ b/doc/user/command.sgml @@ -27,12 +27,6 @@ =head2 The C<Command> method -The C<Command> method is a catchall method which can be used to arrange for -any build action to be executed to update the target. For this command, a -target file and list of inputs is provided. In addition, a build action -is specified as the last argument. The build action is typically a -command line or lines, but may also contain Perl code to be executed; -see the section above on build actions for details. The C<Command> method is called as follows: @@ -55,19 +49,60 @@ F<foo.h> and F<foo.c>. --> - <para> - - X - - </para> - - <section> - <title>The &Command; Method</title> - - <para> - - X - - </para> - - </section> + <para> + + Creating a &Builder; and attaching it to a &consenv; + allows for a lot of flexibility when you + want to re-use the same actions + to build multiple files of the same type. + This can, however, be cumbersome + if you only need to execute one specific command + to build a single file (or single group of files). + For these situations, &SCons; supports a + &Command; &Builder; that arranges + for a specific action to be executed + to build a specific file or files. + This looks a lot like the other builders + (like &Program;, &Object;, etc.), + but takes as an additional argument + the command to be executed to build the file: + + </para> + + <programlisting> + env = Environment() + env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $TARGET > $SOURCE") + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + sed 's/x/y' < foo.in > foo.out + </literallayout> + + <para> + + This is often more convenient than + creating a &Builder; object + and adding it to the &BUILDERS; variable + of a &consenv; + + </para> + + <para> + + Note that the action you + + </para> + + <programlisting> + env = Environment() + def build(target, source, env) + XXX + return None + env.Command('foo.out', 'foo.in', build) + </programlisting> + + <literallayout> + % <userinput>scons .</userinput> + build("foo.out", "foo.in") + </literallayout> diff --git a/doc/user/default.sgml b/doc/user/default.sgml index eb2bdc1..981ac42 100644 --- a/doc/user/default.sgml +++ b/doc/user/default.sgml @@ -69,9 +69,9 @@ default list. explicitly specify one or more targets on the command line. Sometimes, however, you may want - to explicitly specify that only - certain programs should be built by default, - which you do using the &Default; function: + to specify explicitly that only + certain programs should be built by default. + You do this with the &Default; function: </para> @@ -84,7 +84,7 @@ default list. <para> - This &SConstruct; file builds two programs, + This &SConstruct; file knows how to build two programs, &hello; and &goodbye;, but only builds the &hello program by default: @@ -162,7 +162,7 @@ default list. <application>prog1</application> and <application>prog3</application> - programs: + programs by default: </para> diff --git a/doc/user/depends.sgml b/doc/user/depends.sgml index e8491e4..8669c72 100644 --- a/doc/user/depends.sgml +++ b/doc/user/depends.sgml @@ -46,369 +46,369 @@ operating system on which the build is performed (as reported by C<uname --> - <para> - - So far we've seen how &SCons; handles one-time builds. - But the real point of a build tool like &SCons; - is to rebuild the necessary things when source files change. - The other side of rebuilding all the necessary things - is that &SCons; should <emphasis>not</emphasis> - unnecessarily rebuild things that have already - been built. - You can see this at work simply be re-invoking &SCons; - after building our simple &hello; example: - - </para> - - <literallayout> - % <userinput>scons</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>scons</userinput> - % - </literallayout> - - <para> - - &SCons; has remembered that the &hello; program - is up-to-date with respect to the current &hello_c; source file, - and avoids rebuilding it. - You can see this more clearly by naming - the &hello; program explicitly on the command line: - - </para> - - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - % - </literallayout> - - <para> - - Note that &SCons; only reports "...is up to date" - for target files named explicitly on the command line, - to avoid cluttering the output. - - </para> - - <section> - <title>MD5 Signatures</title> - - <para> - - &SCons; keeps track of whether a file has changed - based on the file's contents, - not the modification time. - This means that you may be surprised by the - behavior of &SCons; if you are used to the - &Make; convention of forcing - a rebuild by updating the file's - modification time like so: - - </para> - - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>touch hello.c</userinput> - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - % - </literallayout> - - <para> - - This saves time by avoiding unnecessary rebuilds when, - for example, someone rewrites the - contents of a file without making a change. - But if the contents of the file change, - then &SCons; detects the change - and rebuilds the program as required: - - </para> - - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>edit hello.c</userinput> - [CHANGE THE CONTENTS OF hello.c] - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % - </literallayout> - - <para> - - X - - </para> - - </section> + <para> + + So far we've seen how &SCons; handles one-time builds. + But the real point of a build tool like &SCons; + is to rebuild the necessary things, + and only the necessary thing, when source files change. + Put another way, + &SCons; should <emphasis>not</emphasis> + waste time rebuilding things that have already been built. + You can see this at work simply be re-invoking &SCons; + after building our simple &hello; example: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons</userinput> + % + </literallayout> + + <para> + + The second time it is executed, + &SCons; realizes that the &hello; program + is up-to-date with respect to the current &hello_c; source file, + and avoids rebuilding it. + You can see this more clearly by naming + the &hello; program explicitly on the command line: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % + </literallayout> + + <para> + + Note that &SCons; only reports "...is up to date" + for target files named explicitly on the command line, + to avoid cluttering the output. + + </para> + + <section> + <title>MD5 Signatures</title> + + <para> + + &SCons; keeps track of whether a file has changed + based on the file's contents, + not the modification time. + This means that you may be surprised by the + behavior of &SCons; if you are used to the + &Make; convention of forcing + a rebuild by updating the file's + modification time like so: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>touch hello.c</userinput> + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % + </literallayout> + + <para> + + This saves time by avoiding unnecessary rebuilds when, + for example, someone rewrites the + contents of a file without making a change. + But if the contents of the file change, + then &SCons; detects the change + and rebuilds the program as required: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>edit hello.c</userinput> + [CHANGE THE CONTENTS OF hello.c] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + <para> + + X + + </para> + + </section> + + <!-- + + Now it turns out that F<hello.c> also includes the interface definition + file, F<world.h>: + + How does Cons know that F<hello.c> includes F<world.h>, and that F<hello.o> + must therefore be recompiled? For now, suffice it to say that when + considering whether or not F<hello.o> is up-to-date, Cons invokes a scanner + for its dependency, F<hello.c>. This scanner enumerates the files included + by F<hello.c> to come up with a list of further dependencies, beyond those + made explicit by the Cons script. This process is recursive: any files + included by included files will also be scanned. -<!-- - -Now it turns out that F<hello.c> also includes the interface definition -file, F<world.h>: - -How does Cons know that F<hello.c> includes F<world.h>, and that F<hello.o> -must therefore be recompiled? For now, suffice it to say that when -considering whether or not F<hello.o> is up-to-date, Cons invokes a scanner -for its dependency, F<hello.c>. This scanner enumerates the files included -by F<hello.c> to come up with a list of further dependencies, beyond those -made explicit by the Cons script. This process is recursive: any files -included by included files will also be scanned. - ---> - - <section> - <title>Implicit Dependencies</title> + --> - <para> + <section> + <title>Implicit Dependencies</title> + + <para> + + Now suppose that our "Hello, World!" program + actually has a <literal>#include</literal> line + to include &hello_h; file in the compilation: + + </para> + + <programlisting> + #include "hello.h" + int + main() + { + printf("Hello, %s!\n", string); + } + </programlisting> + + <para> + + And, for completeness, the &hello_h; file looks like this: + + </para> + + <programlisting> + #define string "world" + </programlisting> + + <para> + + In this case, we want &SCons; to recognize that, + if the contents of the &hello_h; file change, + the &hello; program must be recompiled. + To do this, we need to modify the + &SConstruct; file like so: + + </para> + + <programlisting> + env = Environment(CPPPATH = '.') XXX IS CPPPATH NECESSARY? + hello = env.Program('hello.c') + </programlisting> + + <para> + + The &CPPPATH; assignment in the &Environment; call + tells &SCons; to look in the current directory + (<literal>'.'</literal>) + for any files included by C source files + (<filename>.c</filename> or <filename>.h</filename> files). + With this assignment in the &SConstruct file: + + </para> + + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % + </literallayout> + + <para> + + &SCons; knows that the &hello; + program must be rebuilt + because it scans the contents of + the &hello_c; file + for the <literal>#include</literal> lines that indicate + another file is being included in the compilation. + &SCons; records these as + <emphasis>implicit dependencies</emphasis> + of the target file, + Consequently, + when the &hello_h; file changes, + &SCons; realizes that the &hello_c; file includes it, + and rebuilds the resulting &hello; program + that depends on both the &hello_c; and &hello_h; files. + + </para> + + <para> + + X + + <!-- + Isn't this expensive? The answer is, it depends. If you do a full build of a + large system, the scanning time is insignificant. If you do a rebuild of a + large system, then Cons will spend a fair amount of time thinking about it + before it decides that nothing has to be done (although not necessarily more + time than make!). The good news is that Cons makes it very easy to + intelligently subset your build, when you are working on localized changes. + --> - Now suppose that our "Hello, World!" program - actually looks like this: + </para> + + </section> + + <section> + <title>The &Ignore; Method</title> + + <para> + + Sometimes it makes sense + to not rebuild a program, + even if a dependency file changes. + In this case, + you would tell &SCons; specifically + to ignore a dependency as follows: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Ignore(hello, 'hello.h') + </programlisting> - </para> + <!-- XXX mention that you can use arrays for target and source? --> - <programlisting> - #include "hello.h" - int - main() - { - printf("Hello, %s!\n", string); - } - </programlisting> + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit hello.h</userinput> + [CHANGE THE CONTENTS OF hello.h] + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + </literallayout> - <para> + <para> - That is, the first line - includes a &hello_h; - that looks like this: + Now, the above example is a little contrived, + because it's hard to imagine a real-world situation + where you wouldn't to rebuild &hello; + if the &hello_h; file changed. + A more realistic example + might be if the &hello; + program is being built in a + directory that is shared between multiple systems + that have different copies of the + &stdio_h; include file. + In that case, + &SCons; would notice the differences between + the different systems' copies of &stdio_h; + and would rebuild &hello; + each time you change systems. + You could avoid these rebuilds as follows: - </para> + </para> - <programlisting> - #define string "world" - </programlisting> + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Ignore(hello, '/usr/include/stdio.h') + </programlisting> - <para> + </section> - In this case, we want &SCons; to recognize that, - if the contents of the &hello_h; file change, - the &hello; program must be recompiled. - To do this, we need to modify the - &SConstruct; file like so: + <section> + <title>The &Depends; Method</title> - </para> + <para> - <programlisting> - env = Environment(CPPPATH = '.') XXX IS CPPPATH NECESSARY? - hello = env.Program('hello.c') - </programlisting> + On the other hand, + sometimes a file depends on another + file that the scanner(s) in &SCons; will not detect. + For this situation, + &SCons; allows you to specific that one file explicitly + depends on another file, + and must be rebuilt whenever that file changes, + using the &Depends; method: - <para> + </para> - The &CPPPATH; assignment in the &Environment; call - tells &SCons; to look in the current directory - (<literal>'.'</literal>) - for any files included by C source files - (<filename>.c</filename> or <filename>.h</filename> files). - With this assignment in the &SConstruct file: + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Depends(hello, 'other_file') + </programlisting> - </para> + <!-- XXX mention that you can use arrays for target and source? --> - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - % <userinput>edit hello.h</userinput> - [CHANGE THE CONTENTS OF hello.h] - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % - </literallayout> + <literallayout> + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons hello</userinput> + scons: `hello' is up to date. + % <userinput>edit other_file</userinput> + [CHANGE THE CONTENTS OF other_file] + % <userinput>scons hello</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + </literallayout> - <para> + </section> - &SCons; knows that the &hello; - program must be rebuilt - because it scans the contents of - the &hello_c; file - for the <literal>#include</literal> lines that indicate - another file is being included in the compilation. - &SCons; records these as - <emphasis>implicit dependencies</emphasis> - of the target file, - Consequently, - when the &hello_h; file changes, - &SCons; realizes that the &hello_c; file includes it, - and rebuilds the resulting &hello; program - that depends on both the &hello_c; and &hello_h; files. + <!--> - </para> + <section> + <title>The &Salt; Method</title> - <para> + <para> - X + X -<!-- -Isn't this expensive? The answer is, it depends. If you do a full build of a -large system, the scanning time is insignificant. If you do a rebuild of a -large system, then Cons will spend a fair amount of time thinking about it -before it decides that nothing has to be done (although not necessarily more -time than make!). The good news is that Cons makes it very easy to -intelligently subset your build, when you are working on localized changes. ---> + </para> - </para> - - </section> - - <section> - <title>The &Ignore; Method</title> - - <para> - - Sometimes it makes sense - to not rebuild a program, - even if a dependency file changes. - In this case, - you would tell &SCons; specifically - to ignore a dependency as follows: - - </para> - - <programlisting> - env = Environment() - hello = env.Program('hello.c') - env.Ignore(hello, 'hello.h') - </programlisting> - - <!-- XXX mention that you can use arrays for target and source? --> - - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - % <userinput>edit hello.h</userinput> - [CHANGE THE CONTENTS OF hello.h] - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - </literallayout> - - <para> - - Now, the above example is a little contrived, - because it's hard to imagine a real-world situation - where you wouldn't to rebuild &hello; - if the &hello_h; file changed. - A more realistic example - might be if the &hello; - program is being built in a - directory that is shared between multiple systems - that have different copies of the - &stdio_h; include file. - In that case, - &SCons; would notice the differences between - the different systems' copies of &stdio_h; - and would rebuild &hello; - each time you change systems. - You could avoid these rebuilds as follows: - - </para> - - <programlisting> - env = Environment() - hello = env.Program('hello.c') - env.Ignore(hello, '/usr/include/stdio.h') - </programlisting> - - </section> - - <section> - <title>The &Depends; Method</title> - - <para> - - On the other hand, - sometimes a file depends on another - file that the scanner(s) in &SCons; will not detect. - For this situation, - &SCons; allows you to specific that one file explicitly - depends on another file, - and must be rebuilt whenever that file changes, - using the &Depends; method: - - </para> - - <programlisting> - env = Environment() - hello = env.Program('hello.c') - env.Depends(hello, 'other_file') - </programlisting> - - <!-- XXX mention that you can use arrays for target and source? --> - - <literallayout> - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - % <userinput>scons hello</userinput> - scons: `hello' is up to date. - % <userinput>edit other_file</userinput> - [CHANGE THE CONTENTS OF other_file] - % <userinput>scons hello</userinput> - cc -c hello.c -o hello.o - cc -o hello hello.o - </literallayout> - - </section> - - <!--> - - <section> - <title>The &Salt; Method</title> - - <para> - - X - - </para> - - </section> + </section> - --> + --> - <section> - <title>Time Stamps</title> + <section> + <title>Time Stamps</title> - <para> + <para> - X + X - </para> + </para> - </section> + </section> - <section> - <title>The &SourceSignature; Method</title> + <section> + <title>The &SourceSignature; Method</title> - <para> + <para> - X + X - </para> + </para> - </section> + </section> diff --git a/doc/user/environments.sgml b/doc/user/environments.sgml index b06ade1..8117cf0 100644 --- a/doc/user/environments.sgml +++ b/doc/user/environments.sgml @@ -25,47 +25,6 @@ <!-- -=head2 Construction environments - -A key simplification of Cons is the idea of a B<construction environment>. A -construction environment is an B<object> characterized by a set of key/value -pairs and a set of B<methods>. In order to tell Cons how to build something, -you invoke the appropriate method via an appropriate construction -environment. Consider the following example: - - - - $env = new cons( - CC => 'gcc', - LIBS => 'libworld.a' - ); - - Program $env 'hello', 'hello.c'; - -In this case, rather than using the default construction environment, as is, -we have overridden the value of C<CC> so that the GNU C Compiler equivalent -is used, instead. Since this version of B<Hello, World!> requires a library, -F<libworld.a>, we have specified that any program linked in this environment -should be linked with that library. If the library exists already, well and -good, but if not, then we'll also have to include the statement: - - - - Library $env 'libworld', 'world.c'; - -Now if you type C<cons hello>, the library will be built before the program -is linked, and, of course, C<gcc> will be used to compile both modules: - - - - % cons hello - gcc -c hello.c -o hello.o - gcc -c world.c -o world.o - ar r libworld.a world.o - ar: creating libworld.a - ranlib libworld.a - gcc -o hello hello.o libworld.a - =head1 More on construction environments As previously mentioned, a B<construction environment> is an object that @@ -346,6 +305,12 @@ by the MD5 signature calculation on the actual file contents. =back +XXX + +DESCRIBE THE Literal() FUNCTION, TOO + +XXX + =head2 Expanding construction variables in file names Cons expands construction variables in the source and target file names @@ -420,101 +385,261 @@ C<PATH> variable in the default environment, you could do the following: This will leave anything else that might be in the default execution environment undisturbed. +--> + + <para> + It is rare that all of the software in a large, + complicated system needs to be built the same way. + Different source files need different options + enabled on the command line; + different executable programs need to be linked + with different libraries (shared or static); + XXX + &SCons; accomodates these different build + requirements by allowing you to create and + configure multiple &consenvs; + that control how the software is built. + Technically, a &consenv; is an object + that has a number of associated + &consvars;, each with a name and a value. + (A &consenv; also has an attached + set of &Builder; methods, + about which we'll learn more later.) -=head2 Overriding construction variables + </para> -There are several ways of extending Cons, which vary in degree of -difficulty. The simplest method is to define your own construction -environment, based on the default environment, but modified to reflect your -particular needs. This will often suffice for C-based applications. You can -use the C<new> constructor, and the C<clone> and C<copy> methods to create -hybrid environments. These changes can be entirely transparent to the -underlying F<Conscript> files. + <para> ---> + A &consenv; is created by the &Environment; + method which you have already seen. + What you haven't seen, though, + is that when you initialize a &consenv;, + you can set the values of the + environment's &consvars; + to control how a program is built. + For example: + + </para> + + <programlisting> + env = Environment(CC = 'gcc', + CCFLAGS = '-O2') + + env.Program('foo.c') + </programlisting> <para> + + This example, rather than using the default, + explicitly specifies use of the + GNU C compiler &gcc;, + and further specifies that the <literal>-O2</literal> + (optimization level two) + flag should be used when compiling the object file. + So a run from this example would look like: - X + </para> -<!-- + <literallayout> + % <userinput>scons</userinput> + gcc -c -O2 foo.c -o foo.o + gcc -o foo foo.o + </literallayout> -A key simplification of Cons is the idea of a B<construction environment>. A -construction environment is an B<object> characterized by a set of key/value -pairs and a set of B<methods>. In order to tell Cons how to build something, -you invoke the appropriate method via an appropriate construction -environment. Consider the following example: + <section> + <title>Multiple &ConsEnvs;</title> + <para> + So far, we've always created a &consenv; named + <literal>env</literal>. + <literal>env</literal>, however, + is simply a Python variable name, + and you can use any other variable name that we like. + For example: - $env = new cons( - CC => 'gcc', - LIBS => 'libworld.a' - ); + </para> + + <programlisting> + my_env = Environment(CC = 'gcc', + CCFLAGS = '-O2') - Program $env 'hello', 'hello.c'; + my_env.Program('foo.c') + </programlisting> -In this case, rather than using the default construction environment, as is, -we have overridden the value of C<CC> so that the GNU C Compiler equivalent -is used, instead. Since this version of B<Hello, World!> requires a library, -F<libworld.a>, we have specified that any program linked in this environment -should be linked with that library. If the library exists already, well and -good, but if not, then we'll also have to include the statement: + <para> + This opens up the possibility of + using multiple &consenvs;, + each with a separate variable name. + We can then use these separate &consenvs; + to build different programs in different ways: + </para> - Library $env 'libworld', 'world.c'; + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') -Now if you type C<cons hello>, the library will be built before the program -is linked, and, of course, C<gcc> will be used to compile both modules: + opt.Program('foo', 'foo.c') + dbg.Program('bar', 'bar.c') + </programlisting> + <literallayout> + % <userinput>scons</userinput> + cc -c -O2 bar.c -o bar.o + cc -o bar bar.o + cc -c -g foo.c -o foo.o + cc -o foo foo.o + </literallayout> - % cons hello - gcc -c hello.c -o hello.o - gcc -c world.c -o world.o - ar r libworld.a world.o - ar: creating libworld.a - ranlib libworld.a - gcc -o hello hello.o libworld.a + <para> ---> + We can even use multiple &consenvs; to build + multiple versions of a single program. + If you do this by simply trying to use the + &Program; builder with both environments, though, + like this: - </para> + </para> - <programlisting> - optimize = Environment(CCFLAGS = '-O2') - debug = Environment(CCFLAGS = '-g') + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') - o = optimize.Object('foo-opt', 'foo.c') - optimize.Program(o) + opt.Program('foo', 'foo.c') - d = debug.Object('foo-debug', 'foo.c') - debug.Program(d) - </programlisting> + dbg.Program('foo', 'foo.c') + </programlisting> - <literallayout> - % <userinput>scons .</userinput> - cc -c -g foo.c -o foo-debug.o - cc -o foo-debug foo-debug.o - cc -c -O2 foo.c -o foo-opt.o - cc -o foo-opt foo-opt.o - </literallayout> + <para> + + Then &SCons; generates the following error: + + </para> + + <literallayout> + % <userinput>scons</userinput> + scons: *** Two different environments were specified for the same target: foo.o + File "SConstruct", line 6, in ? + </literallayout> + + <para> + + This is because the two &Program; calls have + each implicitly told &SCons; to generate an object file named + <filename>foo.o</filename>, + one with a &CCFLAGS; value of + <literal>-O2</literal> + and one with a &CCFLAGS; value of + <literal>-g</literal>. + To work around this, + we must explicitly specify + that each environment compile + <filename>foo.c</filename> + to a separately-named object file + using the &Object; call, like so: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </programlisting> + + <para> + + Notice that each call to the &Object; builder + returns a value, + an internal &SCons; object that + represents the file that will be built. + We then use that object + as input to the &Program; builder. + This avoids having to specify explicitly + the object file name in multiple places, + and makes for a compact, readable + &SConstruct file. + Our &SCons; output then looks like: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c -g foo.c -o foo-dbg.o + cc -o foo-dbg foo-dbg.o + cc -c -O2 foo.c -o foo-opt.o + cc -o foo-opt foo-opt.o + </literallayout> + + </section> <section> - <title>The &Environment; Constructor</title> + <title>Copying &ConsEnvs;</title> <para> - X + Sometimes you want to more than one &consenv; + to use the same values for one or more variables. + Rather than always having to repeat all of the common + variables when you create each &consenv;, + you can use the &Copy; method + to create a copy of a &consenv;. + Like the &Environment; call that creates a &consenv;, + the &Copy; method takes &consvar; assignments, + which will override the values in the copied &consenv;. + For example, suppose we want to use &gcc; + to create three versions of a program, + one optimized, one debug, and one with neither. + We could do this by creating a "base" &consenv; + that sets &CC; to &gcc;, + and then creating two copies, + one which sets &CCFLAGS; for optimization + and the other with sets &CCFLAGS; for debugging: + + </para> + + <programlisting> + env = Environment(CC = 'gcc') + opt = env.Copy(CCFLAGS = '-O2') + dbg = env.Copy(CCFLAGS = '-g') + + e = opt.Object('foo', 'foo.c') + + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) + + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </programlisting> + + <para> + + Then our output would look like: </para> + <literallayout> + % <userinput>scons</userinput> + gcc -c foo.c -o foo.o + gcc -o foo foo.o + gcc -c -g foo.c -o foo-dbg.o + gcc -o foo-dbg foo-dbg.o + gcc -c -O2 foo.c -o foo-opt.o + gcc -o foo-opt foo-opt.o + </literallayout> + </section> <section> - <title>The &Copy; Method</title> + <title>Fetching Values From a &ConsEnv;</title> <para> @@ -522,4 +647,74 @@ is linked, and, of course, C<gcc> will be used to compile both modules: </para> + <programlisting> + env = Environment() + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + </literallayout> + + </section> + + <section> + <title>Modifying a &ConsEnv;</title> + + <section> + <title>Replacing Values in a &ConsEnv;</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + </literallayout> + + </section> + + <section> + <title>Appending to the End of Values in a &ConsEnv;</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + </literallayout> + + </section> + + <section> + <title>Appending to the Beginning of Values in a &ConsEnv;</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + </literallayout> + + </section> + </section> diff --git a/doc/user/help.sgml b/doc/user/help.sgml index 5e2ced3..233809e 100644 --- a/doc/user/help.sgml +++ b/doc/user/help.sgml @@ -69,7 +69,7 @@ If there is no &Help; text in the &SConstruct; or &SConscript; files, &SCons; will revert to displaying its - standard list and description of available command-line + standard list that describes the &SCons; command-line options. This list is also always displayed whenever the <literal>-H</literal> option is used. diff --git a/doc/user/hierarchy.sgml b/doc/user/hierarchy.sgml index aa56c8d..617eb59 100644 --- a/doc/user/hierarchy.sgml +++ b/doc/user/hierarchy.sgml @@ -36,44 +36,6 @@ C<Import> commands. =head2 The Build command -The C<Build> command takes a list of F<Conscript> file names, and arranges -for them to be included in the build. For example: - - Build qw( - drivers/display/Conscript - drivers/mouse/Conscript - parser/Conscript - utilities/Conscript - ); - -This is a simple two-level hierarchy of build scripts: all the subsidiary -F<Conscript> files are mentioned in the top-level F<Construct> file. Notice -that not all directories in the tree necessarily have build scripts -associated with them. - -This could also be written as a multi-level script. For example, the -F<Construct> file might contain this command: - - Build qw( - parser/Conscript - drivers/Conscript - utilities/Conscript - ); - -and the F<Conscript> file in the F<drivers> directory might contain this: - - Build qw( - display/Conscript - mouse/Conscript - ); - -Experience has shown that the former model is a little easier to understand, -since the whole construction tree is laid out in front of you, at the -top-level. Hybrid schemes are also possible. A separately maintained -component that needs to be incorporated into a build tree, for example, -might hook into the build tree in one place, but define its own construction -hierarchy. - By default, Cons does not change its working directory to the directory containing a subsidiary F<Conscript> file it is including. This behavior can be enabled for a build by specifying, in the top-level F<Construct> @@ -220,30 +182,169 @@ make no difference to the build. --> - <para> + <para> + + The source code for large software projects + rarely stays in a single directory, + but is nearly always divided into a + hierarchy of directories. + Organizing a large software build using &SCons; + involves creating a hierarchy of build scripts + using the &SConscript; function. + + </para> + + <section> + <title>&SConscript; Files</title> + + <para> + + As we've already seen, + the build script at the top of the tree is called &SConstruct;. + The top-level &SConstruct; file can + use the &SConscript; function to + include other subsidiary scripts in the build. + These subsidiary scripts can, in turn, + use the &SConscript; function + to include still other scripts in the build. + By convention, these subsidiary scripts are usually + named &SConscript;. + For example, a top-level &SConstruct; file might + arrange for four subsidiary scripts to be included + in the build as follows: + + </para> + + <programlisting> + SConscript(['drivers/display/SConscript', + 'drivers/mouse/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </programlisting> + + <para> + + In this case, the &SConstruct; file + lists all of the &SConscript; files in the build explicitly. + (Note, however, that not every directory in the tree + necessarily has an &SConscript; file.) + Alternatively, the <literal>drivers</literal> + subdirectory might contain an intermediate + &SConscript; file, + in which case the &SConscript; call in + the top-level &SConstruct; file + would look like: + + </para> + + <programlisting> + SConscript(['drivers/SConscript', + 'parser/SConscript', + 'utilities/SConscript']) + </programlisting> + + <para> + + And the subsidiary &SConscript; file in the + <literal>drivers</literal> subdirectory + would look like: + + </para> + + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> + + <para> + + Whether you list all of the &SConscript; files in the + top-level &SConstruct; file, + or place a subsidiary &SConscript; file in + intervening directories, + or use some mix of the two schemes, + is up to you and the needs of your software. + + </para> + + </section> + + <section> + <title>Path Names Are Relative to the &SConscript; Directory</title> + + <para> + + X + + </para> + + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> + + </section> + + <section> + <title>Sharing Environments (and Other Variables) Between &SConscript; Files</title> + + <para> + + X + + </para> + + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> + + <section> + <title>Exporting Variables</title> + + <para> + + X + + </para> + + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> + + </section> + + <section> + <title>Importing Variables</title> - X + <para> - </para> + X - <section> - <title>&SConscript; Files</title> + </para> - <para> + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> - X + </section> - </para> + <section> + <title>Returning Values</title> - </section> + <para> - <section> - <title>X</title> + X - <para> + </para> - X + <programlisting> + SConscript(['display/SConscript', + 'mouse/SConscript']) + </programlisting> - </para> + </section> - </section> + </section> diff --git a/doc/user/install.sgml b/doc/user/install.sgml index 530fa7a..2cebbd4 100644 --- a/doc/user/install.sgml +++ b/doc/user/install.sgml @@ -23,75 +23,211 @@ --> -<!-- - -=head2 The C<Install> method - -The C<Install> method arranges for the specified files to be installed in -the specified directory. The installation is optimized: the file is not -copied if it can be linked. If this is not the desired behavior, you will -need to use a different method to install the file. It is called as follows: - - Install $env <directory>, <names>; - -Note that, while the files to be installed may be arbitrarily named, -only the last component of each name is used for the installed target -name. So, for example, if you arrange to install F<foo/bar> in F<baz>, -this will create a F<bar> file in the F<baz> directory (not F<foo/bar>). - - -=head2 The C<InstallAs> method + <para> + + Once a program is built, + it is often appropriate to install it in another + directory for public use. + You use the &Install; method + to arrange for a program, or any other file, + to be copied into a destination directory: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + </programlisting> + + <para> + + Note, however, that installing a file is + still considered a type of file "build." + This is important when you remember that + the default behavior of &SCons; is + to build files in or below the current directory. + If, as in the example above, + you are installing files in a directory + outside of the top-level &SConstruct; file's directory tree, + you must specify that directory + (or a higher directory, such as <literal>/</literal>) + for it to install anything there: + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + % <userinput>scons /usr/bin</userinput> + Install file: "hello" as "/usr/bin/hello" + </literallayout> + + <para> + + It can, however, be cumbersome to remember + (and type) the specific destination directory + in which the program (or any other file) + should be installed. + This is an area where the &Alias; + function comes in handy, + allowing you, if you wish, + to create a pseudo-target named <literal>install</literal> + that can expand to the specified destination directory: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.Install('/usr/bin', hello) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + This then yields the more natural + ability to install the program + in its destination as follows: + + </para> -The C<InstallAs> method arranges for the specified source file(s) to be -installed as the specified target file(s). Multiple files should be -specified as a file list. The installation is optimized: the file is not -copied if it can be linked. If this is not the desired behavior, you will -need to use a different method to install the file. It is called as follows: + <literallayout> + % <userinput>scons install</userinput> + Install file: "hello" as "/usr/bin/hello" + </literallayout> + + <section> + <title>Installing Multiple Files in a Directory</title> + + <para> + + You can install multiple files into a directory + simploy by calling the &Install; function multiple times: + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('/usr/bin', hello) + env.Install('/usr/bin', goodbye]) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + Or, more succinctly, listing the multiple input + files in a list + (just like you can do with any other builder): + + </para> + + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.Install('/usr/bin', [hello, goodbye]) + env.Alias('install', '/usr/bin') + </programlisting> + + <para> + + Either of these two examples yields: + + </para> + + <literallayout> + % <userinput>scons install</userinput> + cc -c goodbye.c -o goodbye.o + cc -o goodbye goodbye.o + cc -c hello.c -o hello.o + cc -o hello hello.o + Install file: "goodbye" as "/usr/bin/goodbye" + Install file: "hello" as "/usr/bin/hello" + </literallayout> + + </section> + + <section> + <title>Installing a File Under a Different Name</title> -C<InstallAs> works in two ways: + <para> + + The &Install; method preserves the name + of the file when it is copied into the + destination directory. + If you need to change the name of the file + when you copy it, use the &InstallAs; function: -Single file install: + </para> - InstallAs $env TgtFile, SrcFile; - -Multiple file install: - - InstallAs $env ['tgt1', 'tgt2'], ['src1', 'src2']; - -Or, even as: - - @srcs = qw(src1 src2 src3); - @tgts = qw(tgt1 tgt2 tgt3); - InstallAs $env [@tgts], [@srcs]; - -Both the target and the sources lists should be of the same length. - ---> + <programlisting> + env = Environment() + hello = env.Program('hello.c') + env.InstallAs('/usr/bin/hello-new', hello) + env.Alias('install', '/usr/bin') + </programlisting> - <para> + <para> - X + This installs the <literal>hello</literal> + program with the name <literal>hello-new</literal> + as follows: - </para> + </para> - <section> - <title>The &Install; Builder</title> + <literallayout> + % <userinput>scons install</userinput> + cc -c hello.c -o hello.o + cc -o hello hello.o + Install file: "hello" as "/usr/bin/hello-new" + </literallayout> - <para> + </section> - X + <section> + <title>Installing Multiple Files Under Different Names</title> - </para> + <para> - </section> + Lastly, if you have multiple files that all + need to be installed with different file names, + you can either call the &InstallAs; function + multiple times, or as a shorthand, + you can supply same-length lists + for the both the target and source arguments: - <section> - <title>The &InstallAs; Method</title> + </para> - <para> + <programlisting> + env = Environment() + hello = env.Program('hello.c') + goodbye = env.Program('goodbye.c') + env.InstallAs(['/usr/bin/hello-new', + '/usr/bin/goodbye-new', + [hello, goodbye]) + </programlisting> + + <para> - X + In this case, the &InstallAs; function + loops through both lists simultaneously, + and copies each source file into its corresponding + target file name: - </para> + </para> + + <literallayout> + % <userinput>scons install</userinput> + cc -c goodbye.c -o goodbye.o + cc -o goodbye goodbye.o + cc -c hello.c -o hello.o + cc -o hello hello.o + Install file: "goodbye" as "/usr/bin/goodbye-new" + Install file: "hello" as "/usr/bin/hello-new" + </literallayout> - </section> + </section> diff --git a/doc/user/library.sgml b/doc/user/library.sgml deleted file mode 100644 index 0c9292c..0000000 --- a/doc/user/library.sgml +++ /dev/null @@ -1,81 +0,0 @@ -<!-- - - Copyright (c) 2001, 2002, 2003 Steven Knight - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---> - -<!-- - -=head2 The C<Library> method - -The C<Library> method arranges to create the specified library from the -specified object files. It is invoked as follows: - - Library $env <library name>, <source or object files>; - -The library name will have the value of the C<SUFLIB> construction -variable appended (by default, C<.lib> on Win32 systems, C<.a> on Unix -systems) if the suffix is not already present. - -Source files may be specified in place of objects files-,-the C<Objects> -method will be invoked to arrange the conversion of all the files into -object files, and hence all the observations about the C<Objects> method, -above, apply to this method also. - -The actual creation of the library will be handled by an external -command which results from expanding the C<ARCOM> construction variable, -with C<%E<lt>> set to the library members (in the order presented), -and C<%E<gt>> to the library to be created. (See the section above -on construction variable expansion for details.) The user may set -variables in the construction environment which will affect the -operation of the command. These include C<AR>, the archive program -to use, C<ARFLAGS>, which can be used to modify the flags given to -the program specified by C<AR>, and C<RANLIB>, the name of a archive -index generation program, if needed (if the particular need does not -require the latter functionality, then C<ARCOM> must be redefined to not -reference C<RANLIB>). - -The C<Library> method allows the same library to be specified in multiple -method invocations. All of the contributing objects from all the invocations -(which may be from different directories) are combined and generated by a -single archive command. Note, however, that if you prune a build so that -only part of a library is specified, then only that part of the library will -be generated (the rest will disappear!). - ---> - - <para> - - X - - </para> - - <section> - <title>The &Library; Builder</title> - - <para> - - X - - </para> - - </section> diff --git a/doc/user/main.sgml b/doc/user/main.sgml index b285696..68bc59c 100644 --- a/doc/user/main.sgml +++ b/doc/user/main.sgml @@ -47,19 +47,15 @@ <!ENTITY help SYSTEM "help.sgml"> <!ENTITY hierarchy SYSTEM "hierarchy.sgml"> <!ENTITY install SYSTEM "install.sgml"> - <!ENTITY library SYSTEM "library.sgml"> <!ENTITY make SYSTEM "make.sgml"> - <!ENTITY more SYSTEM "more.sgml"> - <!ENTITY object SYSTEM "object.sgml"> <!ENTITY precious SYSTEM "precious.sgml"> <!ENTITY preface SYSTEM "preface.sgml"> - <!ENTITY program SYSTEM "program.sgml"> - <!ENTITY reference SYSTEM "reference.sgml"> <!ENTITY repositories SYSTEM "repositories.sgml"> <!ENTITY run SYSTEM "run.sgml"> <!ENTITY scanners SYSTEM "scanners.sgml"> <!ENTITY separate SYSTEM "separate.sgml"> <!ENTITY simple SYSTEM "simple.sgml"> + <!ENTITY sourcecode SYSTEM "sourcecode.sgml"> <!ENTITY troubleshoot SYSTEM "troubleshoot.sgml"> <!ENTITY variants SYSTEM "variants.sgml"> @@ -111,8 +107,6 @@ &depends; </chapter> - - <chapter id="chap-default"> <title>Default Targets</title> &default; @@ -128,31 +122,6 @@ &install; </chapter> - <chapter id="chap-program"> - <title>The Program Builder</title> - &program; - </chapter> - - <chapter id="chap-library"> - <title>The Library Builder</title> - &library; - </chapter> - - <chapter id="chap-more"> - <title>More Things to Do With Builds</title> - &more; - </chapter> - - <chapter id="chap-command"> - <title>The Command Builder</title> - &command; - </chapter> - - <chapter id="chap-object"> - <title>The Object Builder</title> - &object; - </chapter> - <chapter id="chap-precious"> <title>Preventing Removal of Targets</title> &precious; @@ -178,6 +147,11 @@ &builders; </chapter> + <chapter id="chap-command"> + <title>Avoiding Having to Write Builders</title> + &command; + </chapter> + <chapter id="chap-actions"> <title>SCons Actions</title> &actions; @@ -193,35 +167,45 @@ &repositories; </chapter> + <chapter id="chap-sourcecode"> + <title>Fetching Files From Source Code Management Systems</title> + &sourcecode; + </chapter> + <chapter id="chap-caching"> <title>Caching Built Files</title> &caching; </chapter> - <chapter id="chap-run"> - <title>How to Run &SCons;</title> - &run; - </chapter> - <chapter id="chap-alias"> <title>Alias Targets</title> &alias; </chapter> + <chapter id="chap-run"> + <title>How to Run &SCons;</title> + &run; + </chapter> + <chapter id="chap-troubleshooting"> <title>Troubleshooting</title> &troubleshoot; </chapter> - <appendix id="app-quick"> - <title>Quick Reference</title> - &reference; - </appendix> - - <appendix id="app-errors"> - <title>Errors Generated by &SCons;</title> - &errors; - </appendix> + <!-- + AddPostAction() + AddPreAction() + Clean() + Dir() + File() + FindFile() + GetJobs() + SetJobs() + SideEffect() + ParseConfig() + Platform() + Tools() + --> <appendix id="app-example"> <title>Complex &SCons; Example</title> diff --git a/doc/user/more.sgml b/doc/user/more.sgml deleted file mode 100644 index 7defa41..0000000 --- a/doc/user/more.sgml +++ /dev/null @@ -1,63 +0,0 @@ -<!-- - - Copyright (c) 2001, 2002, 2003 Steven Knight - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---> - - <para> - - X - - </para> - - <section> - <title>The &Module; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &RuleSet; Method</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>The &DefaultRules; Method</title> - - <para> - - X - - </para> - - </section> diff --git a/doc/user/object.sgml b/doc/user/object.sgml deleted file mode 100644 index 9e887d8..0000000 --- a/doc/user/object.sgml +++ /dev/null @@ -1,71 +0,0 @@ -<!-- - - Copyright (c) 2001, 2002, 2003 Steven Knight - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---> - -<!-- - -=head2 The C<Objects> method - -The C<Objects> method arranges to create the object files that correspond to -the specified source files. It is invoked as shown below: - - @files = Objects $env <source or object files>; - -Under Unix, source files ending in F<.s> and F<.c> are currently -supported, and will be compiled into a name of the same file ending -in F<.o>. By default, all files are created by invoking the external -command which results from expanding the C<CCCOM> construction variable, -with C<%E<lt>> and C<%E<gt>> set to the source and object files, -respectively. (See the section above on construction variable expansion -for details). The variable C<CPPPATH> is also used when scanning source -files for dependencies. This is a colon separated list of pathnames, and -is also used to create the construction variable C<_IFLAGS,> which will -contain the appropriate list of -C<I> options for the compilation. Any -relative pathnames in C<CPPPATH> is interpreted relative to the -directory in which the associated construction environment was created -(absolute and top-relative names may also be used). This variable is -used by C<CCCOM>. The behavior of this command can be modified by -changing any of the variables which are interpolated into C<CCCOM>, such -as C<CC>, C<CFLAGS>, and, indirectly, C<CPPPATH>. It's also possible -to replace the value of C<CCCOM>, itself. As a convenience, this file -returns the list of object filenames. - ---> - - <para> - - X - - </para> - - <section> - <title>The &Object; Method</title> - - <para> - - X - - </para> - - </section> diff --git a/doc/user/precious.sgml b/doc/user/precious.sgml index 9cd2a43..26ad345 100644 --- a/doc/user/precious.sgml +++ b/doc/user/precious.sgml @@ -25,17 +25,6 @@ <!-- -=head2 The C<Precious> method - -The C<Precious> method asks cons not to delete the specified file or -list of files before building them again. It is invoked as: - - Precious <files>; - -This is especially useful for allowing incremental updates to libraries -or debug information files which are updated rather than rebuilt anew each -time. Cons will still delete the files when the C<-r> flag is specified. - =head2 The C<AfterBuild> method The C<AfterBuild> method evaluates the specified perl string after @@ -53,17 +42,38 @@ which the C<AfterBuild> method is called. <para> - X + By default, &SCons; removes targets before building them. + Sometimes, however, this is not what you want. + For example, you may want to update a library incrementally, + not by having it deleted and then rebuilt from all + of the constituent object files. + In such cases, you can use the + &Precious; method to prevent + &SCons; from removing the target before it is built: </para> - <section> - <title>The &Precious; Method</title> + <programlisting> + env = Environment(XXX NEED LIBRARY FLAGS + LIBFLAGS = '-r') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Precious(lib) + </programlisting> - <para> + <para> - X + XXX: - </para> + </para> - </section> + <literallayout> + % <userinput>scons</userinput> + XXX ANY INPUT HERE? + </literallayout> + + <para> + + &SCons; will still delete files marked as &Precious; + when the <literal>-c</literal> option is used. + + </para> diff --git a/doc/user/program.sgml b/doc/user/program.sgml deleted file mode 100644 index 30f90d2..0000000 --- a/doc/user/program.sgml +++ /dev/null @@ -1,77 +0,0 @@ -<!-- - - Copyright (c) 2001, 2002, 2003 Steven Knight - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---> - -<!-- - -=head2 The C<Program> method - -The C<Program> method arranges to link the specified program with the -specified object files. It is invoked in the following manner: - - Program $env <program name>, <source or object files>; - -The program name will have the value of the C<SUFEXE> construction -variable appended (by default, C<.exe> on Win32 systems, nothing on Unix -systems) if the suffix is not already present. - -Source files may be specified in place of objects files-,-the C<Objects> -method will be invoked to arrange the conversion of all the files into -object files, and hence all the observations about the C<Objects> method, -above, apply to this method also. - -The actual linking of the program will be handled by an external command -which results from expanding the C<LINKCOM> construction variable, with -C<%E<lt>> set to the object files to be linked (in the order presented), -and C<%E<gt>> set to the target. (See the section above on construction -variable expansion for details.) The user may set additional variables -in the construction environment, including C<LINK>, to define which -program to use for linking, C<LIBPATH>, a colon-separated list of -library search paths, for use with library specifications of the form -I<-llib>, and C<LIBS>, specifying the list of libraries to link against -(in either I<-llib> form or just as pathnames. Relative pathnames in -both C<LIBPATH> and C<LIBS> are interpreted relative to the directory -in which the associated construction environment is created (absolute -and top-relative names may also be used). Cons automatically sets up -dependencies on any libraries mentioned in C<LIBS>: those libraries will -be built before the command is linked. - ---> - - <para> - - X - - </para> - - <section> - <title>The &Program; Builder</title> - - <para> - - X - - </para> - - </section> diff --git a/doc/user/reference.sgml b/doc/user/reference.sgml deleted file mode 100644 index ef8e5a9..0000000 --- a/doc/user/reference.sgml +++ /dev/null @@ -1,63 +0,0 @@ -<!-- - - Copyright (c) 2001, 2002, 2003 Steven Knight - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---> - - <para> - - X - - </para> - - <section> - <title>Command-Line Options</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>Default Builders</title> - - <para> - - X - - </para> - - </section> - - <section> - <title>X</title> - - <para> - - X - - </para> - - </section> diff --git a/doc/user/repositories.sgml b/doc/user/repositories.sgml index 2193a8f..616e903 100644 --- a/doc/user/repositories.sgml +++ b/doc/user/repositories.sgml @@ -135,314 +135,326 @@ subdirectories under the repository tree. --> - <para> + <para> + + Often, a software project will have + one or more central repositories, + directory trees that contain + source code, or derived files, or both. + You can eliminate additional unnecessary + rebuilds of files by having &SCons; + use files from one or more code repositories + to build files in your local build tree. + + </para> + + <section> + <title>The &Repository; Method</title> + + <!-- + + The repository directories specified may contain source files, derived files + (objects, libraries and executables), or both. If there is no local file + (source or derived) under the directory in which Cons is executed, then the + first copy of a same-named file found under a repository directory will be + used to build any local derived files. + + --> + + <para> + + It's often useful to allow multiple programmers working + on a project to build software from + source files and/or derived files that + are stored in a centrally-accessible repository, + a directory copy of the source code tree. + (Note that this is not the sort of repository + maintained by a source code management system + like BitKeeper, CVS, or Subversion. + For information about using &SCons; + with these systems, see the section, + "Fetching Files From Source Code Management Systems," + below.) + You use the &Repository; method + to tell &SCons; to search one or more + central code repositories (in order) + for any source files and derived files + that are not present in the local build tree: - Often, a software project will have - one or more central repositories, - directory trees that contain - source code, or derived files, or both. - You can eliminate additional unnecessary - rebuilds of files by having &SCons; - use files from one or more code repositories - to build files in your local build tree. + </para> + + <programlisting> + env = Environment() + env.Program('hello.c') + Repository('/usr/repository1', '/usr/repository2') + </programlisting> + + <para> + + Multiple calls to the &Repository; method + will simply add repositories to the global list + that &SCons; maintains, + with the exception that &SCons; will automatically eliminate + the current directory and any non-existent + directories from the list. - </para> + </para> + + </section> + + <section> + <title>Finding source files in repositories</title> + + <para> + + The above example + specifies that &SCons; + will first search for files under + the <filename>/usr/repository1</filename> tree + and next under the <filename>/usr/repository2</filename> tree. + &SCons; expects that any files it searches + for will be found in the same position + relative to the top-level directory XXX + In the above example, if the &hello_c; file is not + found in the local build tree, + &SCons; will search first for + a <filename>/usr/repository1/hello.c</filename> file + and then for a <filename>/usr/repository1/hello.c</filename> file + to use in its place. + + </para> + + <para> - <section> - <title>The &Repository; Method</title> + So given the &SConstruct; file above, + if the &hello_c; file exists in the local + build directory, + &SCons; will rebuild the &hello; program + as normal: + + </para> -<!-- - -The repository directories specified may contain source files, derived files -(objects, libraries and executables), or both. If there is no local file -(source or derived) under the directory in which Cons is executed, then the -first copy of a same-named file found under a repository directory will be -used to build any local derived files. - ---> - - <para> - - The &Repository; method - tells &SCons; to search one or more - central code repositories (in order) - for any source files and derived files - that are not present in the local build tree: - - </para> - - <programlisting> - env = Environment() - env.Program('hello.c') - Repository('/usr/repository1', '/usr/repository2') - </programlisting> - - <para> - - (Note that multiple calls to the &Repository; method - will simply add repositories to the global list - that &SCons; maintains, - with the exception that &SCons; will automatically eliminate - the current directory and any non-existent - directories from the list.) - - </para> - - </section> - - <section> - <title>Finding source files in repositories</title> - - <para> - - The above example - specifies that &SCons; - will first search for files under - the <filename>/usr/repository1</filename> tree - and next under the <filename>/usr/repository2</filename> tree. - &SCons; expects that any files it searches - for will be found in the same position - relative to the top-level directory XXX - In the above example, if the &hello_c; file is not - found in the local build tree, - &SCons; will search first for - a <filename>/usr/repository1/hello.c</filename> file - and then for a <filename>/usr/repository1/hello.c</filename> file - to use in its place. - - </para> - - <para> - - So given the &SConstruct; file above, - if the &hello_c; file exists in the local - build directory, - &SCons; will rebuild the &hello; program - as normal: - - </para> - - <literallayout> - % <userinput>scons</userinput> - gcc -c hello.c -o hello.o - gcc -o hello hello.o - </literallayout> - - <para> - - If, however, there is no local &hello_c; file, - but one exists in <filename>/usr/repository1</filename>, - &SCons; will recompile the &hello; program - from the source file it finds in the repository: - - </para> - - <literallayout> - % <userinput>scons</userinput> - gcc -c /usr/repository1/hello.c -o hello.o - gcc -o hello hello.o - </literallayout> - - <para> - - And similarly, if there is no local &hello_c; file - and no <filename>/usr/repository1/hello.c</filename>, - but one exists in <filename>/usr/repository2</filename>: - - </para> - - <literallayout> - % <userinput>scons</userinput> - gcc -c /usr/repository2/hello.c -o hello.o - gcc -o hello hello.o - </literallayout> - - <para> + <literallayout> + % <userinput>scons</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> - </para> + If, however, there is no local &hello_c; file, + but one exists in <filename>/usr/repository1</filename>, + &SCons; will recompile the &hello; program + from the source file it finds in the repository: + + </para> + + <literallayout> + % <userinput>scons</userinput> + gcc -c /usr/repository1/hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + And similarly, if there is no local &hello_c; file + and no <filename>/usr/repository1/hello.c</filename>, + but one exists in <filename>/usr/repository2</filename>: + + </para> + + <literallayout> + % <userinput>scons</userinput> + gcc -c /usr/repository2/hello.c -o hello.o + gcc -o hello hello.o + </literallayout> + + <para> + + </para> - </section> + </section> - <section> - <title>Finding the &SConstruct; file in repositories</title> + <section> + <title>Finding the &SConstruct; file in repositories</title> - <para> + <para> - &SCons; will also search in repositories - for the &SConstruct; file and any specified &SConscript; files. - This poses a problem, though: how can &SCons; search a - repository tree for an &SConstruct; file - if the &SConstruct; file itself contains the information - about the pathname of the repository? - To solve this problem, &SCons; allows you - to specify repository directories - on the command line using the <literal>-Y</literal>: + &SCons; will also search in repositories + for the &SConstruct; file and any specified &SConscript; files. + This poses a problem, though: how can &SCons; search a + repository tree for an &SConstruct; file + if the &SConstruct; file itself contains the information + about the pathname of the repository? + To solve this problem, &SCons; allows you + to specify repository directories + on the command line using the <literal>-Y</literal>: - </para> + </para> - <literallayout> - % <userinput>scons -Y /usr/repository1 -Y /usr/repository2</userinput> - </literallayout> + <literallayout> + % <userinput>scons -Y /usr/repository1 -Y /usr/repository2</userinput> + </literallayout> - <para> + <para> - When looking for source or derived files, - &SCons; will first search the repositories - specified on the command line, - and then search the repositories - specified in the &SConstruct; or &SConscript; files. + When looking for source or derived files, + &SCons; will first search the repositories + specified on the command line, + and then search the repositories + specified in the &SConstruct; or &SConscript; files. - </para> + </para> - </section> + </section> - <section> - <title>Finding derived files in repositories</title> + <section> + <title>Finding derived files in repositories</title> - <para> + <para> - If a repository contains not only source files, - but also derived files (such as object files, - libraries, or executables), &SCons; will perform - its normal MD5 signature calculation to - decide if a derived file in a repository is up-to-date, - or the derived file must be rebuilt in the local build directory. - For the &SCons; signature calculation to work correctly, - a repository tree must contain the &sconsign; files - that &SCons; uses to keep track of signature information. + If a repository contains not only source files, + but also derived files (such as object files, + libraries, or executables), &SCons; will perform + its normal MD5 signature calculation to + decide if a derived file in a repository is up-to-date, + or the derived file must be rebuilt in the local build directory. + For the &SCons; signature calculation to work correctly, + a repository tree must contain the &sconsign; files + that &SCons; uses to keep track of signature information. - </para> + </para> - <para> + <para> - Usually, this would be done by a build integrator - who would run &SCons; in the repository - to create all of its derived files and &sconsign; files, - or who would &SCons; in a separate build directory - and copying the resulting tree to the desired repository: + Usually, this would be done by a build integrator + who would run &SCons; in the repository + to create all of its derived files and &sconsign; files, + or who would &SCons; in a separate build directory + and copying the resulting tree to the desired repository: - </para> + </para> - <literallayout> - % <userinput>cd /usr/repository1</userinput> - % <userinput>scons</userinput> - gcc -c hello.c -o hello.o - gcc -o hello hello.o - </literallayout> + <literallayout> + % <userinput>cd /usr/repository1</userinput> + % <userinput>scons</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + </literallayout> - <para> - - (Note that this is safe even if the &SConstruct; file - lists <filename>/usr/repository1</filename> as a repository, - because &SCons; will remove the current build directory - from its repository list for that invocation.) + <para> + + (Note that this is safe even if the &SConstruct; file + lists <filename>/usr/repository1</filename> as a repository, + because &SCons; will remove the current build directory + from its repository list for that invocation.) - </para> + </para> - <para> + <para> - Now, with the repository populated, - we only need to create the one local source file - we're interested in working with at the moment, - and use the <literal>-Y</literal> option to - tell &SCons; to fetch any other files it needs - from the repository: + Now, with the repository populated, + we only need to create the one local source file + we're interested in working with at the moment, + and use the <literal>-Y</literal> option to + tell &SCons; to fetch any other files it needs + from the repository: - </para> + </para> - <literallayout> - % <userinput>cd $HOME/build</userinput> - % <userinput>edit hello.c</userinput> - % <userinput>scons -Y /usr/repository1</userinput> - gcc -c hello.c -o hello.o - gcc -o hello hello.o - XXXXXXX - </literallayout> + <literallayout> + % <userinput>cd $HOME/build</userinput> + % <userinput>edit hello.c</userinput> + % <userinput>scons -Y /usr/repository1</userinput> + gcc -c hello.c -o hello.o + gcc -o hello hello.o + XXXXXXX + </literallayout> - <para> + <para> - Notice that &SCons; realizes that it does not need to - rebuild a local XXX.o file, - but instead uses the already-compiled XXX.o file - from the repository. + Notice that &SCons; realizes that it does not need to + rebuild a local XXX.o file, + but instead uses the already-compiled XXX.o file + from the repository. - </para> + </para> - </section> + </section> - <section> - <title>Guaranteeing local copies of files</title> + <section> + <title>Guaranteeing local copies of files</title> - <para> + <para> - If the repository tree contains the complete results of a build, - and we try to build from the repository - without any files in our local tree, - something moderately surprising happens: + If the repository tree contains the complete results of a build, + and we try to build from the repository + without any files in our local tree, + something moderately surprising happens: - </para> + </para> - <literallayout> - % <userinput>mkdir $HOME/build2</userinput> - % <userinput>cd $HOME/build2</userinput> - % <userinput>scons -Y /usr/all/repository hello</userinput> - scons: `hello' is up-to-date. - </literallayout> + <literallayout> + % <userinput>mkdir $HOME/build2</userinput> + % <userinput>cd $HOME/build2</userinput> + % <userinput>scons -Y /usr/all/repository hello</userinput> + scons: `hello' is up-to-date. + </literallayout> - <para> + <para> - Why does &SCons; say that the &hello; program - is up-to-date when there is no &hello; program - in the local build directory? - Because the repository (not the local directory) - contains the up-to-date &hello; program, - and &SCons; correctly determines that nothing - needs to be done to rebuild that - up-to-date copy of the file. + Why does &SCons; say that the &hello; program + is up-to-date when there is no &hello; program + in the local build directory? + Because the repository (not the local directory) + contains the up-to-date &hello; program, + and &SCons; correctly determines that nothing + needs to be done to rebuild that + up-to-date copy of the file. - </para> - - <para> + </para> + + <para> - There are, however, many times when you want to ensure that a - local copy of a file always exists. - A packaging or testing script, for example, - may assume that certain generated files exist locally. - To tell &SCons; to make a copy of any up-to-date repository - file in the local build directory, - use the &Local; function: + There are, however, many times when you want to ensure that a + local copy of a file always exists. + A packaging or testing script, for example, + may assume that certain generated files exist locally. + To tell &SCons; to make a copy of any up-to-date repository + file in the local build directory, + use the &Local; function: - </para> + </para> - <programlisting> - env = Environment() - hello = env.Program('hello.c') - Local(hello) - </programlisting> + <programlisting> + env = Environment() + hello = env.Program('hello.c') + Local(hello) + </programlisting> - <para> + <para> - If we then run the same command, - &SCons; will make a local copy of the program - from the repository copy, - and tell you that it is doing so: + If we then run the same command, + &SCons; will make a local copy of the program + from the repository copy, + and tell you that it is doing so: - </para> + </para> - <literallayout> - % cons -R /usr/all/repository hello - Local copy of hello from /usr/all/repository/hello - scons: `hello' is up-to-date. - XXXXXX DO WE REALLY REPORT up-to-date, TOO? - </literallayout> + <literallayout> + % scons -Y /usr/all/repository hello + Local copy of hello from /usr/all/repository/hello + scons: `hello' is up-to-date. + XXXXXX DO WE REALLY REPORT up-to-date, TOO? + </literallayout> - <para> + <para> - (Notice that, because the act of making the local copy - is not considered a "build" of the &hello; file, - &SCons; still reports that it is up-to-date.) - XXXXXX DO WE REALLY REPORT up-to-date, TOO? + (Notice that, because the act of making the local copy + is not considered a "build" of the &hello; file, + &SCons; still reports that it is up-to-date.) + XXXXXX DO WE REALLY REPORT up-to-date, TOO? - </para> + </para> - </section> + </section> diff --git a/doc/user/separate.sgml b/doc/user/separate.sgml index e1c0e49..9050eb7 100644 --- a/doc/user/separate.sgml +++ b/doc/user/separate.sgml @@ -112,12 +112,178 @@ program using the F<build/foo.c> path name. <para> - X + It's often useful to keep any built files completely + separate from the source files. + This is usually done by creating one or more separate + <emphasis>build directories</emphasis> + that are used to hold the built objects files, libraries, + and executable programs, etc. + for a specific flavor of build. + &SCons; provides two ways of doing this, + one with a little more flexibility. </para> <section> - <title>X</title> + <title>The &BuildDir; Function</title> + + <para> + + X + + </para> + + <programlisting> + BuildDir('build', 'src') + env = Environment() + env.Program('build/hello.c') + </programlisting> + + <para> + + X + + </para> + + <literallayout> + % <userinput>ls src</userinput> + hello.c + % <userinput>scons</userinput> + cc -c build/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls -1 build</userinput> + hello + hello.c + hello.o + </literallayout> + + </section> + + <section> + <title>Avoiding Duplicate Source Files in the Build Directory</title> + + <para> + + X + + </para> + + <programlisting> + BuildDir('build', 'src', duplicate=0) + env = Environment() + env.Program('build/hello.c') + </programlisting> + + <para> + + X + + </para> + + <literallayout> + % <userinput>ls -1 src</userinput> + hello.c + % <userinput>scons</userinput> + cc -c src/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls -1 build</userinput> + hello + hello.o + </literallayout> + + <para> + + X + + </para> + + </section> + + <section> + <title>Why &SCons; Duplicates Source Files by Default</title> + + <para> + + X + + </para> + + <programlisting> + env = Environmnet() + </programlisting> + + <para> + + X + + </para> + + <literallayout> + % <userinput>scons</userinput> + cc -c build/hello.c -o build/hello.o + cc -o build/hello build/hello.o + </literallayout> + + </section> + + <section> + <title>Using &BuildDir; With an &SConscript; File</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.Program('hello.c') + </programlisting> + + <para> + + X + + </para> + + <programlisting> + BuildDir('build', 'src') + SConscript('build/SConscript') + </programlisting> + + <para> + + X + + </para> + + <literallayout> + % <userinput>ls -1 src</userinput> + SConscript + hello.c + % <userinput>scons</userinput> + cc -c build/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls -1 build</userinput> + hello + hello.c + hello.o + </literallayout> + + </section> + + <section> + <title>Specifying a Build Directory as Part of an &SConscript; Call</title> + + <para> + + X + + </para> + + <programlisting> + SConscript('src/SConscript', build_dir='build') + </programlisting> <para> @@ -125,4 +291,45 @@ program using the F<build/foo.c> path name. </para> + <literallayout> + % <userinput>ls -1 src</userinput> + SConscript + hello.c + % <userinput>scons</userinput> + cc -c build/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls -1 build</userinput> + hello + hello.c + hello.o + </literallayout> + + <para> + + X + + </para> + + <programlisting> + SConscript('src/SConscript', build_dir='build', duplicate=0) + </programlisting> + + <para> + + X + + </para> + + <literallayout> + % <userinput>ls -1 src</userinput> + SConscript + hello.c + % <userinput>scons</userinput> + cc -c src/hello.c -o build/hello.o + cc -o build/hello build/hello.o + % <userinput>ls -1 build</userinput> + hello + hello.o + </literallayout> + </section> diff --git a/doc/user/simple.sgml b/doc/user/simple.sgml index 8cafe2d..a86fd34 100644 --- a/doc/user/simple.sgml +++ b/doc/user/simple.sgml @@ -147,10 +147,10 @@ requirements of a build. an &SConstruct; file and a &Makefile: the &SConstruct; file is actually a Python script. If you're not already familiar with Python, don't worry; - Python is extremely easy to learn, + Python is very easy to learn, and this User's Guide will introduce you step-by-step to the relatively small amount of Python you'll - neede to know to be able to use &SCons; effectively. + need to know to be able to use &SCons; effectively. </para> @@ -254,7 +254,7 @@ requirements of a build. <para> - One minor drawback to the use of a Python list + One drawback to the use of a Python list for source files is that each file name must be enclosed in quotes (either single quotes or double quotes). diff --git a/doc/user/sourcecode.sgml b/doc/user/sourcecode.sgml new file mode 100644 index 0000000..4ee49d4 --- /dev/null +++ b/doc/user/sourcecode.sgml @@ -0,0 +1,144 @@ +<!-- + + Copyright (c) 2001, 2002, 2003 Steven Knight + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<!-- + +--> + + <para> + + X + + </para> + + <section> + <title>Fetching Source Code From BitKeeper</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.BitKeeper('XXX') + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> + + <section> + <title>Fetching Source Code From CVS</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.CVS('XXX') + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> + + <section> + <title>Fetching Source Code From RCS</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.RCS() + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> + + <section> + <title>Fetching Source Code From SCCS</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.SCCS() + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> + + <section> + <title>Fetching Source Code From Subversion</title> + + <para> + + X + + </para> + + <programlisting> + env = Environment() + env.SourceCode('.', env.Subversion('XXX') + env.Program('hello.c') + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + XXX + </literallayout> + + </section> diff --git a/doc/user/variants.sgml b/doc/user/variants.sgml index fdd209e..6ad9360 100644 --- a/doc/user/variants.sgml +++ b/doc/user/variants.sgml @@ -122,4 +122,25 @@ is pretty smart about rebuilding things when you change options. </para> + <programlisting> + env = Environment(OS = ARGUMENT['os']) + SConscript('src/SConscript', build_dir='build/$OS') + </programlisting> + + <para> + + X + + </para> + + <programlisting> + env = Environment(OS = ) + for os in ['newell', 'post']: + SConscript('src/SConscript', build_dir='build/' + os) + </programlisting> + + <literallayout> + % <userinput>scons</userinput> + </literallayout> + </section> |