diff options
Diffstat (limited to 'doc/user/environments.xml')
-rw-r--r-- | doc/user/environments.xml | 1992 |
1 files changed, 1256 insertions, 736 deletions
diff --git a/doc/user/environments.xml b/doc/user/environments.xml index 01ae2ed..0aac0d8 100644 --- a/doc/user/environments.xml +++ b/doc/user/environments.xml @@ -1,25 +1,25 @@ <!-- - __COPYRIGHT__ - - 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. + __COPYRIGHT__ + + 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. --> @@ -38,120 +38,120 @@ build behavior. Construction variables from a construction environment are expanded by preceding the keyword with a C<%> (percent sign): - Construction variables: + Construction variables: XYZZY => 'abracadabra', - The string: "The magic word is: %XYZZY!" - expands to: "The magic word is: abracadabra!" + The string: "The magic word is: %XYZZY!" + expands to: "The magic word is: abracadabra!" A construction variable name may be surrounded by C<{> and C<}> (curly braces), which are stripped as part of the expansion. This can sometimes be necessary to separate a variable expansion from trailing alphanumeric characters: - Construction variables: + Construction variables: OPT => 'value1', OPTION => 'value2', - The string: "%OPT %{OPT}ION %OPTION %{OPTION}" - expands to: "value1 value1ION value2 value2" + The string: "%OPT %{OPT}ION %OPTION %{OPTION}" + expands to: "value1 value1ION value2 value2" Construction variable expansion is recursive, that is, a string containing C<%->expansions after substitution will be re-expanded until no further substitutions can be made: - Construction variables: + Construction variables: STRING => 'The result is: %FOO', FOO => '%BAR', BAR => 'final value', - The string: "The string says: %STRING" - expands to: "The string says: The result is: final value" + The string: "The string says: %STRING" + expands to: "The string says: The result is: final value" If a construction variable is not defined in an environment, then the null string is substituted: - Construction variables: + Construction variables: FOO => 'value1', BAR => 'value2', - The string: "%FOO <%NO_VARIABLE> %BAR" - expands to: "value1 <> value2" + The string: "%FOO <%NO_VARIABLE> %BAR" + expands to: "value1 <> value2" A doubled C<%%> will be replaced by a single C<%>: - The string: "Here is a percent sign: %%" - expands to: "Here is a percent sign: %" + The string: "Here is a percent sign: %%" + expands to: "Here is a percent sign: %" =head2 Default construction variables When you specify no arguments when creating a new construction environment: - $env = new cons(); + $env = new cons(); Cons creates a reference to a new, default construction environment. This contains a number of construction variables and some methods. At the present writing, the default construction variables on a UNIX system are: - CC => 'cc', - CFLAGS => '', - CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>', - CXX => '%CC', - CXXFLAGS => '%CFLAGS', - CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>', - INCDIRPREFIX => '-I', - INCDIRSUFFIX => '', - LINK => '%CXX', - LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS', - LINKMODULECOM => '%LD -r -o %> %<', - LIBDIRPREFIX => '-L', - LIBDIRSUFFIX => '', - AR => 'ar', - ARFLAGS => 'r', - ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'], - RANLIB => 'ranlib', - AS => 'as', - ASFLAGS => '', - ASCOM => '%AS %ASFLAGS %< -o %>', - LD => 'ld', - LDFLAGS => '', - PREFLIB => 'lib', - SUFLIB => '.a', - SUFLIBS => '.so:.a', - SUFOBJ => '.o', - SIGNATURE => [ '*' => 'build' ], - ENV => { 'PATH' => '/bin:/usr/bin' }, + CC => 'cc', + CFLAGS => '', + CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>', + CXX => '%CC', + CXXFLAGS => '%CFLAGS', + CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>', + INCDIRPREFIX => '-I', + INCDIRSUFFIX => '', + LINK => '%CXX', + LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS', + LINKMODULECOM => '%LD -r -o %> %<', + LIBDIRPREFIX => '-L', + LIBDIRSUFFIX => '', + AR => 'ar', + ARFLAGS => 'r', + ARCOM => ['%AR %ARFLAGS %> %<', '%RANLIB %>'], + RANLIB => 'ranlib', + AS => 'as', + ASFLAGS => '', + ASCOM => '%AS %ASFLAGS %< -o %>', + LD => 'ld', + LDFLAGS => '', + PREFLIB => 'lib', + SUFLIB => '.a', + SUFLIBS => '.so:.a', + SUFOBJ => '.o', + SIGNATURE => [ '*' => 'build' ], + ENV => { 'PATH' => '/bin:/usr/bin' }, And on a Windows system (Windows NT), the default construction variables are (unless the default rule style is set using the B<DefaultRules> method): - CC => 'cl', - CFLAGS => '/nologo', - CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>', - CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>', - INCDIRPREFIX => '/I', - INCDIRSUFFIX => '', - LINK => 'link', - LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS', - LINKMODULECOM => '%LD /r /o %> %<', - LIBDIRPREFIX => '/LIBPATH:', - LIBDIRSUFFIX => '', - AR => 'lib', - ARFLAGS => '/nologo ', - ARCOM => "%AR %ARFLAGS /out:%> %<", - RANLIB => '', - LD => 'link', - LDFLAGS => '/nologo ', - PREFLIB => '', - SUFEXE => '.exe', - SUFLIB => '.lib', - SUFLIBS => '.dll:.lib', - SUFOBJ => '.obj', - SIGNATURE => [ '*' => 'build' ], + CC => 'cl', + CFLAGS => '/nologo', + CCCOM => '%CC %CFLAGS %_IFLAGS /c %< /Fo%>', + CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>', + INCDIRPREFIX => '/I', + INCDIRSUFFIX => '', + LINK => 'link', + LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS', + LINKMODULECOM => '%LD /r /o %> %<', + LIBDIRPREFIX => '/LIBPATH:', + LIBDIRSUFFIX => '', + AR => 'lib', + ARFLAGS => '/nologo ', + ARCOM => "%AR %ARFLAGS /out:%> %<", + RANLIB => '', + LD => 'link', + LDFLAGS => '/nologo ', + PREFLIB => '', + SUFEXE => '.exe', + SUFLIB => '.lib', + SUFLIBS => '.dll:.lib', + SUFOBJ => '.obj', + SIGNATURE => [ '*' => 'build' ], These variables are used by the various methods associated with the environment. In particular, any method that ultimately invokes an external @@ -160,7 +160,7 @@ appropriate. For example, the C<Objects> method takes a number of source files and arranges to derive, if necessary, the corresponding object files: - Objects $env 'foo.c', 'bar.c'; + Objects $env 'foo.c', 'bar.c'; This will arrange to produce, if necessary, F<foo.o> and F<bar.o>. The command invoked is simply C<%CCCOM>, which expands, through substitution, @@ -234,32 +234,32 @@ anywhere else in the current command line (via C<%1>, C<%2>, etc.), then those will be deleted from the list provided by C<%E<lt>>. Consider the following command found in a F<Conscript> file in the F<test> directory: - Command $env 'tgt', qw(foo bar baz), qq( + Command $env 'tgt', qw(foo bar baz), qq( echo %< -i %1 > %> echo %< -i %2 >> %> echo %< -i %3 >> %> - ); + ); If F<tgt> needed to be updated, then this would result in the execution of the following commands, assuming that no remapping has been established for the F<test> directory: - echo test/bar test/baz -i test/foo > test/tgt - echo test/foo test/baz -i test/bar >> test/tgt - echo test/foo test/bar -i test/baz >> test/tgt + echo test/bar test/baz -i test/foo > test/tgt + echo test/foo test/baz -i test/bar >> test/tgt + echo test/foo test/bar -i test/baz >> test/tgt =back Any of the above pseudo-variables may be followed immediately by one of the following suffixes to select a portion of the expanded path name: - :a the absolute path to the file name - :b the directory plus the file name stripped of any suffix - :d the directory - :f the file name - :s the file name suffix - :F the file name stripped of any suffix - :S the absolute path path to a Linked source file + :a the absolute path to the file name + :b the directory plus the file name stripped of any suffix + :d the directory + :f the file name + :s the file name suffix + :F the file name stripped of any suffix + :S the absolute path path to a Linked source file Continuing with the above example, C<%E<lt>:f> would expand to C<foo bar baz>, and C<%E<gt>:d> would expand to C<test>. @@ -277,17 +277,17 @@ as a Perl code reference; the results of this call will be used to replace the contents of the brackets in the command line. For example, given an existing input file named F<tgt.in>: - @keywords = qw(foo bar baz); - $env = new cons(X_COMMA => sub { join(",", @_) }); - Command $env 'tgt', 'tgt.in', qq( + @keywords = qw(foo bar baz); + $env = new cons(X_COMMA => sub { join(",", @_) }); + Command $env 'tgt', 'tgt.in', qq( echo '# Keywords: %[X_COMMA @keywords %]' > %> cat %< >> %> - ); + ); This will execute: - echo '# Keywords: foo,bar,baz' > tgt - cat tgt.in >> tgt + echo '# Keywords: foo,bar,baz' > tgt + cat tgt.in >> tgt =item %( %) @@ -313,833 +313,1353 @@ Cons expands construction variables in the source and target file names passed to the various construction methods according to the expansion rules described above: - $env = new cons( + $env = new cons( DESTDIR => 'programs', SRCDIR => 'src', - ); - Program $env '%DESTDIR/hello', '%SRCDIR/hello.c'; + ); + Program $env '%DESTDIR/hello', '%SRCDIR/hello.c'; This allows for flexible configuration, through the construction environment, of directory names, suffixes, etc. -=head1 Default construction methods +--> -The list of default construction methods includes the following: + <para> + + An <literal>environment</literal> + is a collection of values that + can affect how a program executes. + &SCons; distinguishes between three + different types of environments + that can affect the behavior of &SCons; itself + (subject to the configuration in the &SConscript; files), + as well as the compilers and other tools it executes: + + </para> + + <variablelist> + + <varlistentry> + <term>External Environment</term> + + <listitem> + <para> + + The <literal>external environment</literal> + is the set of variables in the user's environment + at the time the user runs &SCons;. + These variables are available within the &SConscript; files + through the Python <literal>os.environ</literal> dictionary. + See <xref linkend="sect-external-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>&ConsEnv;</term> + + <listitem> + <para> + + A &consenv; + is a distinct object creating within + a &SConscript; file and + and which contains values that + affect how &SCons; decides + what action to use to build a target, + and even to define which targets + should be built from which sources. + One of the most powerful features of &SCons; + is the ability to create multiple &consenvs;, + including the ability to clone a new, customized + &consenv; from an existing &consenv;. + See <xref linkend="sect-construction-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Execution Environment</term> + + <listitem> + <para> + + An <literal>execution environment</literal> + is the values that &SCons; sets + when executing an external + command (such as a compiler or linker) + to build one or more targets. + Note that this is not the same as + the <literal>external environment</literal> + (see above). + See <xref linkend="sect-execution-environments"></xref>, below. + + </para> + </listitem> + </varlistentry> + + </variablelist> + + <para> + + Unlike &Make;, &SCons; does not automatically + copy or import values between different environments + (with the exception of explicit clones of &consenvs;, + which inherit values from their parent). + This is a deliberate design choice + to make sure that builds are, + by default, repeatable regardless of + the values in the user's external environment. + This avoids a whole class of problems with builds + where a developer's local build works + because a custom variable setting + causes a different comiler or build option to be used, + but the checked-in change breaks the official build + because it uses different environment variable settings. + + </para> + + <para> + + Note that the &SConscript; writer can + easily arrange for variables to be + copied or imported between environments, + and this is often very useful + (or even downright necessary) + to make it easy for developers + to customize the build in appropriate ways. + The point is <emphasis>not</emphasis> + that copying variables between different environments + is evil and must always be avoided. + Instead, it should be up to the + implementer of the build system + to make conscious choices + about how and when to import + a variable from one environment to another, + making informed decisions about + striking the right balance + between making the build + repeatable on the one hand + and convenient to use on the other. + + </para> + + <section id="sect-external-environments"> + <title>Using Values From the External Environment</title> + + <para> + + The <literal>external environment</literal> + variable settings that + the user has in force + when executing &SCons; + are available through the normal Python + <envar>os.environ</envar> + dictionary. + This means that you must add an + <literal>import os</literal> statuement + to any &SConscript; file + in which you want to use + values from the user's external environment. + + </para> + <programlisting> + import os + </programlisting> -=head2 The C<new> constructor + <para> + + More usefully, you can use the + <envar>os.environ</envar> + dictionary in your &SConscript; + files to initialize &consenvs; + with values from the user's external environment. + See the next section, + <xref linkend="sect-construction-environments"></xref>, + for information on how to do this. + + </para> + + </section> + + <section id="sect-construction-environments"> + <title>Construction Environments</title> -The C<new> method is a Perl object constructor. That is, it is not invoked -via a reference to an existing construction environment B<reference>, but, -rather statically, using the name of the Perl B<package> where the -constructor is defined. The method is invoked like this: + <para> - $env = new cons(<overrides>); + It is rare that all of the software in a large, + complicated system needs to be built the same way. + For example, different source files may need different options + enabled on the command line, + or different executable programs need to be linked + with different libraries. + &SCons; accommodates these different build + requirements by allowing you to create and + configure multiple &consenvs; + that control how the software is built. + A &consenv; is an object + that has a number of associated + &consvars;, each with a name and a value. + (A construction environment also has an attached + set of &Builder; methods, + about which we'll learn more later.) -The environment you get back is blessed into the package C<cons>, which -means that it will have associated with it the default methods described -below. Individual construction variables can be overridden by providing -name/value pairs in an override list. Note that to override any command -environment variable (i.e. anything under C<ENV>), you will have to override -all of them. You can get around this difficulty by using the C<copy> method -on an existing construction environment. + </para> + <section> + <title>Creating a &ConsEnv;: the &Environment; Function</title> -=head2 The C<clone> method + <para> -The C<clone> method creates a clone of an existing construction environment, -and can be called as in the following example: + A &consenv; is created by the &Environment; method: - $env2 = $env1->clone(<overrides>); + </para> -You can provide overrides in the usual manner to create a different -environment from the original. If you just want a new name for the same -environment (which may be helpful when exporting environments to existing -components), you can just use simple assignment. + <programlisting> + env = Environment() + </programlisting> + <para> -=head2 The C<copy> method + By default, &SCons; initializes every + new construction environment + with a set of &consvars; + based on the tools that it finds on your system, + plus the default set of builder methods + necessary for using those tools. + The construction variables + are initialized with values describing + the C compiler, + the Fortran compiler, + the linker, + etc., + as well as the command lines to invoke them. -The C<copy> method extracts the externally defined construction variables -from an environment and returns them as a list of name/value -pairs. Overrides can also be provided, in which case, the overridden values -will be returned, as appropriate. The returned list can be assigned to a -hash, as shown in the prototype, below, but it can also be manipulated in -other ways: + </para> - %env = $env1->copy(<overrides>); + <para> -The value of C<ENV>, which is itself a hash, is also copied to a new hash, -so this may be changed without fear of affecting the original -environment. So, for example, if you really want to override just the -C<PATH> variable in the default environment, you could do the following: + When you initialize a construction environment + you can set the values of the + environment's &consvars; + to control how a program is built. + For example: - %cons = new cons()->copy(); - $cons{ENV}{PATH} = "<your path here>"; - $cons = new cons(%cons); + </para> -This will leave anything else that might be in the default execution -environment undisturbed. + <programlisting> + import os ---> + env = Environment(CC = 'gcc', + CCFLAGS = '-O2') - <para> - - It is rare that all of the software in a large, - complicated system needs to be built the same way. - For example, different source files may need different options - enabled on the command line, - or different executable programs need to be linked - with different libraries. - &SCons; accommodates 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 construction environment also has an attached - set of &Builder; methods, - about which we'll learn more later.) - - </para> - - <para> - - A &consenv; is created by the &Environment; method: - - </para> - - <programlisting> - env = Environment() - </programlisting> - - <para> - - By default, &SCons; initializes every - new construction environment - with a set of &consvars; - based on the tools that it finds on your system, - plus the default set of builder methods - necessary for using those tools. - The construction variables - are initialized with values describing - the C compiler, - the Fortran compiler, - the linker, - etc., - as well as the command lines to invoke them. - - </para> - - <para> - - When you initialize a construction environment - 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> - - The construction environment in this example - is still initialized with the same default - construction variable values, - except that the user has explicitly specified 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. - In other words, the explicit initializations of - &cv-link-CC; and &cv-link-CCFLAGS; - override the default values in the newly-created - construction environment. - So a run from this example would look like: - - </para> - - <screen> - % <userinput>scons -Q</userinput> - gcc -o foo.o -c -O2 foo.c - gcc -o foo foo.o - </screen> - - <section> - <title>Multiple &ConsEnvs;</title> - - <para> - - The real advantage of construction environments - is that you can create as many different construction - environments as you need, - each tailored to a different way to build - some piece of software or other file. - If, for example, we need to build - one program with the <literal>-O2</literal> flag - and another with the <literal>-g</literal> (debug) flag, - we would do this like so: - - </para> + env.Program('foo.c') + </programlisting> - <programlisting> - opt = Environment(CCFLAGS = '-O2') - dbg = Environment(CCFLAGS = '-g') + <para> - opt.Program('foo', 'foo.c') + The construction environment in this example + is still initialized with the same default + construction variable values, + except that the user has explicitly specified 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. + In other words, the explicit initializations of + &cv-link-CC; and &cv-link-CCFLAGS; + override the default values in the newly-created + construction environment. + So a run from this example would look like: - dbg.Program('bar', 'bar.c') - </programlisting> + </para> - <screen> - % <userinput>scons -Q</userinput> - cc -o bar.o -c -g bar.c - cc -o bar bar.o - cc -o foo.o -c -O2 foo.c - cc -o foo foo.o - </screen> + <screen> + % <userinput>scons -Q</userinput> + gcc -o foo.o -c -O2 foo.c + gcc -o foo foo.o + </screen> - <para> + </section> - We can even use multiple construction environments to build - multiple versions of a single program. - If you do this by simply trying to use the - &b-link-Program; builder with both environments, though, - like this: + <section> + <title>Fetching Values From a &ConsEnv;</title> - </para> + <para> - <programlisting> - opt = Environment(CCFLAGS = '-O2') - dbg = Environment(CCFLAGS = '-g') + You can fetch individual construction variables + using the normal syntax + for accessing individual named items in a Python dictionary: + + </para> + + <programlisting> + env = Environment() + print "CC is:", env['CC'] + </programlisting> - opt.Program('foo', 'foo.c') + <para> - dbg.Program('foo', 'foo.c') - </programlisting> + This example &SConstruct; file doesn't build anything, + but because it's actually a Python script, + it will print the value of &cv-link-CC; for us: - <para> + </para> - Then &SCons; generates the following error: + <screen> + % <userinput>scons -Q</userinput> + CC is: cc + scons: `.' is up to date. + </screen> - </para> + <para> - <screen> - % <userinput>scons -Q</userinput> - - scons: *** Two environments with different actions were specified for the same target: foo.o - File "/home/my/project/SConstruct", line 6, in <module> - </screen> + A construction environment, however, + is actually an object with associated methods, etc. + If you want to have direct access to only the + dictionary of construction variables, + you can fetch this using the &Dictionary; method: - <para> + </para> + + <programlisting> + env = Environment(FOO = 'foo', BAR = 'bar') + dict = env.Dictionary() + for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: + print "key = %s, value = %s" % (key, dict[key]) + </programlisting> - This is because the two &b-Program; calls have - each implicitly told &SCons; to generate an object file named - <filename>foo.o</filename>, - one with a &cv-link-CCFLAGS; value of - <literal>-O2</literal> - and one with a &cv-link-CCFLAGS; value of - <literal>-g</literal>. - &SCons; can't just decide that one of them - should take precedence over the other, - so it generates the error. - To avoid this problem, - we must explicitly specify - that each environment compile - <filename>foo.c</filename> - to a separately-named object file - using the &b-link-Object; builder, like so: + <para> - </para> + This &SConstruct; file + will print the specified dictionary items for us on POSIX + systems as follows: - <programlisting> - opt = Environment(CCFLAGS = '-O2') - dbg = Environment(CCFLAGS = '-g') + </para> - o = opt.Object('foo-opt', 'foo.c') - opt.Program(o) + <screen> + % <userinput>scons -Q</userinput> + key = OBJSUFFIX, value = .o + key = LIBSUFFIX, value = .a + key = PROGSUFFIX, value = + scons: `.' is up to date. + </screen> - d = dbg.Object('foo-dbg', 'foo.c') - dbg.Program(d) - </programlisting> + <para> - <para> - - Notice that each call to the &b-Object; builder - returns a value, - an internal &SCons; object that - represents the object file that will be built. - We then use that object - as input to the &b-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> - - <screen> - % <userinput>scons -Q</userinput> - cc -o foo-dbg.o -c -g foo.c - cc -o foo-dbg foo-dbg.o - cc -o foo-opt.o -c -O2 foo.c - cc -o foo-opt foo-opt.o - </screen> - - </section> - - <section> - <title>Copying &ConsEnvs;</title> - - <para> - - Sometimes you want more than one construction environment - to share the same values for one or more variables. - Rather than always having to repeat all of the common - variables when you create each construction environment, - you can use the &Clone; method - to create a copy of a construction environment. - - </para> - - <para> - - Like the &Environment; call that creates a construction environment, - the &Clone; method takes &consvar; assignments, - which will override the values in the copied construction environment. - 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" construction environment - that sets &cv-link-CC; to &gcc;, - and then creating two copies, - one which sets &cv-link-CCFLAGS; for optimization - and the other which sets &cv-CCFLAGS; for debugging: - - </para> + And on Windows: - <programlisting> - env = Environment(CC = 'gcc') - opt = env.Clone(CCFLAGS = '-O2') - dbg = env.Clone(CCFLAGS = '-g') + </para> - env.Program('foo', 'foo.c') + <screen> + C:\><userinput>scons -Q</userinput> + key = OBJSUFFIX, value = .obj + key = LIBSUFFIX, value = .lib + key = PROGSUFFIX, value = .exe + scons: `.' is up to date. + </screen> + + <para> - o = opt.Object('foo-opt', 'foo.c') - opt.Program(o) + If you want to loop and print the values of + all of the construction variables in a construction environment, + the Python code to do that in sorted order might look something like: - d = dbg.Object('foo-dbg', 'foo.c') - dbg.Program(d) - </programlisting> + </para> - <para> + <programlisting> + env = Environment() + dict = env.Dictionary() + keys = dict.keys() + keys.sort() + for key in keys: + print "construction variable = '%s', value = '%s'" % (key, dict[key]) + </programlisting> - Then our output would look like: + </section> - </para> + <section> + <title>Expanding Values From a &ConsEnv;: the &subst; Method</title> - <screen> - % <userinput>scons -Q</userinput> - gcc -o foo.o -c foo.c - gcc -o foo foo.o - gcc -o foo-dbg.o -c -g foo.c - gcc -o foo-dbg foo-dbg.o - gcc -o foo-opt.o -c -O2 foo.c - gcc -o foo-opt foo-opt.o - </screen> + <para> - </section> + Another way to get information from + a construction environment. + is to use the &subst; method + on a string containing <literal>$</literal> expansions + of construction variable names. + As a simple example, + the example from the previous + section that used + <literal>env['CC']</literal> + to fetch the value of &cv-link-CC; + could also be written as: - <section> - <title>Fetching Values From a &ConsEnv;</title> + </para> - <para> + <programlisting> + env = Environment() + print "CC is:", env.subst('$CC') + </programlisting> - You can fetch individual construction variables - using the normal syntax - for accessing individual named items in a Python dictionary: + <para> - </para> + One advantage of using + &subst; to expand strings is + that construction variables + in the result get re-expanded until + there are no expansions left in the string. + So a simple fetch of a value like + &cv-link-CCCOM;: - <programlisting> - env = Environment() - print "CC is:", env['CC'] - </programlisting> + </para> - <para> + <programlisting> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env['CCCOM'] + </programlisting> - This example &SConstruct; file doesn't build anything, - but because it's actually a Python script, - it will print the value of &cv-link-CC; for us: + <para> - </para> + Will print the unexpanded value of &cv-CCCOM;, + showing us the construction + variables that still need to be expanded: - <screen> - % <userinput>scons -Q</userinput> - CC is: cc - scons: `.' is up to date. - </screen> + </para> - <para> + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES + scons: `.' is up to date. + </screen> - A construction environment, however, - is actually an object with associated methods, etc. - If you want to have direct access to only the - dictionary of construction variables, - you can fetch this using the &Dictionary; method: + <para> - </para> + Calling the &subst; method on <varname>$CCOM</varname>, + however: - <programlisting> - env = Environment(FOO = 'foo', BAR = 'bar') - dict = env.Dictionary() - for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: - print "key = %s, value = %s" % (key, dict[key]) - </programlisting> + </para> - <para> + <programlisting> + env = Environment(CCFLAGS = '-DFOO') + print "CCCOM is:", env.subst('$CCCOM') + </programlisting> - This &SConstruct; file - will print the specified dictionary items for us on POSIX - systems as follows: + <para> - </para> + Will recursively expand all of + the construction variables prefixed + with <literal>$</literal> (dollar signs), + showing us the final output: - <screen> - % <userinput>scons -Q</userinput> - key = OBJSUFFIX, value = .o - key = LIBSUFFIX, value = .a - key = PROGSUFFIX, value = - scons: `.' is up to date. - </screen> + </para> - <para> + <screen> + % <userinput>scons -Q</userinput> + CCCOM is: gcc -DFOO -c -o + scons: `.' is up to date. + </screen> - And on Windows: + <para> + + Note that because we're not expanding this + in the context of building something + there are no target or source files + for &cv-link-TARGET; and &cv-link-SOURCES; to expand. - </para> + </para> - <screen> - C:\><userinput>scons -Q</userinput> - key = OBJSUFFIX, value = .obj - key = LIBSUFFIX, value = .lib - key = PROGSUFFIX, value = .exe - scons: `.' is up to date. - </screen> + </section> - <para> + <section> + <title>Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function</title> - If you want to loop through and print the values of - all of the construction variables in a construction environment, - the Python code to do that in sorted order might look something like: + <para> - </para> + All of the &Builder; functions that we've introduced so far, + like &Program; and &Library;, + actually use a default &consenv; + that contains settings + for the various compilers + and other tools that + &SCons; configures by default, + or otherwise knows about + and has discovered on your system. + The goal of the default construction environment + is to make many configurations to "just work" + to build software using + readily available tools + with a minimum of configuration changes. - <programlisting> - env = Environment() - dict = env.Dictionary() - keys = dict.keys() - keys.sort() - for key in keys: - print "construction variable = '%s', value = '%s'" % (key, dict[key]) - </programlisting> + </para> - </section> + <para> - <section> - <title>Expanding Values From a &ConsEnv;</title> + You can, however, control the settings + in the default contstruction environment + by using the &DefaultEnvironment; function + to initialize various settings: - <para> + </para> - Another way to get information from - a construction environment. - is to use the &subst; method - on a string containing $-expansions - of construction variable names. - As a simple example, - the example from the previous - section that used - <literal>env['CC']</literal> - to fetch the value of &cv-link-CC; - could also be written as: + <programlisting> - </para> + DefaultEnvironment(CC = '/usr/local/bin/gcc') - <programlisting> - env = Environment() - print "CC is:", env.subst('$CC') - </programlisting> + </programlisting> - <para> + <para> - The real advantage of using - &subst; to expand strings is - that construction variables - in the result get - re-expanded until - there are no expansions left in the string. - So a simple fetch of a value like - &cv-link-CCCOM;: + When configured as above, + all calls to the &Program; + or &Object; Builder + will build object files with the + <filename>/usr/local/bin/gcc</filename> + compiler. - </para> + </para> - <programlisting> - env = Environment(CCFLAGS = '-DFOO') - print "CCCOM is:", env['CCCOM'] - </programlisting> + <para> - <para> + Note that the &DefaultEnvironment; function + returns the initialized + default construction environment object, + which can then be manipulated like any + other construction environment. + So the following + would be equivalent to the + previous example, + setting the &cv-CC; + variable to <filename>/usr/local/bin/gcc</filename> + but as a separate step after + the default construction environment has been initialized: - Will print the unexpanded value of &cv-CCCOM;, - showing us the construction - variables that still need to be expanded: + </para> - </para> + <programlisting> - <screen> - % <userinput>scons -Q</userinput> - CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES - scons: `.' is up to date. - </screen> + env = DefaultEnvironment() + env['CC'] = '/usr/local/bin/gcc' - <para> + </programlisting> - Calling the &subst; method on <varname>$CCOM</varname>, - however: + <para> - </para> + One very common use of the &DefaultEnvironment; function + is to speed up &SCons; initialization. + As part of trying to make most default + configurations "just work," + &SCons; will actually + search the local system for installed + compilers and other utilities. + This search can take time, + especially on systems with + slow or networked file systems. + If you know which compiler(s) and/or + other utilities you want to configure, + you can control the search + that &SCons; performs + by specifying some specific + tool modules with which to + initialize the default construction environment: - <programlisting> - env = Environment(CCFLAGS = '-DFOO') - print "CCCOM is:", env.subst('$CCCOM') - </programlisting> + </para> - <para> + <programlisting> - Will recursively expand all of - the $-prefixed construction variables, - showing us the final output: + env = DefaultEnvironment(tools = ['gcc', 'gnulink'], + CC = '/usr/local/bin/gcc') + + </programlisting> + + <para> - </para> + So the above example would tell &SCons; + to explicitly configure the default environment + to use its normal GNU Compiler and GNU Linker settings + (without having to search for them, + or any other utilities for that matter), + and specifically to use the compiler found at + <filename>/usr/local/bin/gcc</filename>. - <screen> - % <userinput>scons -Q</userinput> - CCCOM is: gcc -DFOO -c -o - scons: `.' is up to date. - </screen> + </para> - <para> + </section> - (Note that because we're not expanding this - in the context of building something - there are no target or source files - for &cv-link-TARGET; and &cv-link-SOURCES; to expand.) + <section> + <title>Multiple &ConsEnvs;</title> - </para> + <para> - </section> + The real advantage of construction environments + is that you can create as many different construction + environments as you need, + each tailored to a different way to build + some piece of software or other file. + If, for example, we need to build + one program with the <literal>-O2</literal> flag + and another with the <literal>-g</literal> (debug) flag, + we would do this like so: - <section> - <title>Modifying a &ConsEnv;</title> + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('bar', 'bar.c') + </programlisting> + + <screen> + % <userinput>scons -Q</userinput> + cc -o bar.o -c -g bar.c + cc -o bar bar.o + cc -o foo.o -c -O2 foo.c + cc -o foo foo.o + </screen> + + <para> + + We can even use multiple construction environments to build + multiple versions of a single program. + If you do this by simply trying to use the + &b-link-Program; builder with both environments, though, + like this: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') + + opt.Program('foo', 'foo.c') + + dbg.Program('foo', 'foo.c') + </programlisting> + + <para> + + Then &SCons; generates the following error: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + + scons: *** Two environments with different actions were specified for the same target: foo.o + File "/home/my/project/SConstruct", line 6, in <module> + </screen> + + <para> + + This is because the two &b-Program; calls have + each implicitly told &SCons; to generate an object file named + <filename>foo.o</filename>, + one with a &cv-link-CCFLAGS; value of + <literal>-O2</literal> + and one with a &cv-link-CCFLAGS; value of + <literal>-g</literal>. + &SCons; can't just decide that one of them + should take precedence over the other, + so it generates the error. + To avoid this problem, + we must explicitly specify + that each environment compile + <filename>foo.c</filename> + to a separately-named object file + using the &b-link-Object; builder, like so: + + </para> + + <programlisting> + opt = Environment(CCFLAGS = '-O2') + dbg = Environment(CCFLAGS = '-g') - <para> + o = opt.Object('foo-opt', 'foo.c') + opt.Program(o) - &SCons; provides various methods that - support modifying existing values in a construction environment. + d = dbg.Object('foo-dbg', 'foo.c') + dbg.Program(d) + </programlisting> - </para> + <para> - <section> - <title>Replacing Values in a &ConsEnv;</title> + Notice that each call to the &b-Object; builder + returns a value, + an internal &SCons; object that + represents the object file that will be built. + We then use that object + as input to the &b-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> + </para> - You can replace existing construction variable values - using the &Replace; method: + <screen> + % <userinput>scons -Q</userinput> + cc -o foo-dbg.o -c -g foo.c + cc -o foo-dbg foo-dbg.o + cc -o foo-opt.o -c -O2 foo.c + cc -o foo-opt foo-opt.o + </screen> - </para> + </section> - <programlisting> - env = Environment(CCFLAGS = '-DDEFINE1') - env.Replace(CCFLAGS = '-DDEFINE2') - env.Program('foo.c') - </programlisting> + <section> + <title>Making Copies of &ConsEnvs;: the &Clone; Method</title> - <para> + <para> - The replacing value - (<literal>-DDEFINE2</literal> in the above example) - completely replaces the value in the - construction environment: + Sometimes you want more than one construction environment + to share the same values for one or more variables. + Rather than always having to repeat all of the common + variables when you create each construction environment, + you can use the &Clone; method + to create a copy of a construction environment. - </para> + </para> - <screen> - % <userinput>scons -Q</userinput> - cc -o foo.o -c -DDEFINE2 foo.c - cc -o foo foo.o - </screen> + <para> - <para> + Like the &Environment; call that creates a construction environment, + the &Clone; method takes &consvar; assignments, + which will override the values in the copied construction environment. + 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" construction environment + that sets &cv-link-CC; to &gcc;, + and then creating two copies, + one which sets &cv-link-CCFLAGS; for optimization + and the other which sets &cv-CCFLAGS; for debugging: - You can safely call &Replace; - for construction variables that - don't exist in the construction environment: + </para> + + <programlisting> + env = Environment(CC = 'gcc') + opt = env.Clone(CCFLAGS = '-O2') + dbg = env.Clone(CCFLAGS = '-g') + + env.Program('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> + + <screen> + % <userinput>scons -Q</userinput> + gcc -o foo.o -c foo.c + gcc -o foo foo.o + gcc -o foo-dbg.o -c -g foo.c + gcc -o foo-dbg foo-dbg.o + gcc -o foo-opt.o -c -O2 foo.c + gcc -o foo-opt foo-opt.o + </screen> - </para> + </section> - <programlisting> - env = Environment() - env.Replace(NEW_VARIABLE = 'xyzzy') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - </programlisting> + <section> + <title>Replacing Values: the &Replace; Method</title> + + <para> + + You can replace existing construction variable values + using the &Replace; method: + + </para> + + <programlisting> + env = Environment(CCFLAGS = '-DDEFINE1') + env.Replace(CCFLAGS = '-DDEFINE2') + env.Program('foo.c') + </programlisting> + + <para> + + The replacing value + (<literal>-DDEFINE2</literal> in the above example) + completely replaces the value in the + construction environment: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DDEFINE2 foo.c + cc -o foo foo.o + </screen> - <para> + <para> - In this case, - the construction variable simply - gets added to the construction environment: + You can safely call &Replace; + for construction variables that + don't exist in the construction environment: + + </para> + + <programlisting> + env = Environment() + env.Replace(NEW_VARIABLE = 'xyzzy') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> + + <para> - </para> + In this case, + the construction variable simply + gets added to the construction environment: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = xyzzy + scons: `.' is up to date. + </screen> + + <para> - <screen> - % <userinput>scons -Q</userinput> - NEW_VARIABLE = xyzzy - scons: `.' is up to date. - </screen> + Because the variables + aren't expanded until the construction environment + is actually used to build the targets, + and because &SCons; function and method calls + are order-independent, + the last replacement "wins" + and is used to build all targets, + regardless of the order in which + the calls to Replace() are + interspersed with calls to + builder methods: - <para> + </para> - Because the variables - aren't expanded until the construction environment - is actually used to build the targets, - and because &SCons; function and method calls - are order-independent, - the last replacement "wins" - and is used to build all targets, - regardless of the order in which - the calls to Replace() are - interspersed with calls to - builder methods: + <programlisting> + env = Environment(CCFLAGS = '-DDEFINE1') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('foo.c') - </para> + env.Replace(CCFLAGS = '-DDEFINE2') + print "CCFLAGS =", env['CCFLAGS'] + env.Program('bar.c') + </programlisting> - <programlisting> - env = Environment(CCFLAGS = '-DDEFINE1') - print "CCFLAGS =", env['CCFLAGS'] - env.Program('foo.c') + <para> - env.Replace(CCFLAGS = '-DDEFINE2') - print "CCFLAGS =", env['CCFLAGS'] - env.Program('bar.c') - </programlisting> + The timing of when the replacement + actually occurs relative + to when the targets get built + becomes apparent + if we run &scons; without the <literal>-Q</literal> + option: - <para> + </para> - The timing of when the replacement - actually occurs relative - to when the targets get built - becomes apparent - if we run &scons; without the <literal>-Q</literal> - option: + <screen> + % <userinput>scons</userinput> + scons: Reading SConscript files ... + CCFLAGS = -DDEFINE1 + CCFLAGS = -DDEFINE2 + scons: done reading SConscript files. + scons: Building targets ... + cc -o bar.o -c -DDEFINE2 bar.c + cc -o bar bar.o + cc -o foo.o -c -DDEFINE2 foo.c + cc -o foo foo.o + scons: done building targets. + </screen> - </para> + <para> - <screen> - % <userinput>scons</userinput> - scons: Reading SConscript files ... - CCFLAGS = -DDEFINE1 - CCFLAGS = -DDEFINE2 - scons: done reading SConscript files. - scons: Building targets ... - cc -o bar.o -c -DDEFINE2 bar.c - cc -o bar bar.o - cc -o foo.o -c -DDEFINE2 foo.c - cc -o foo foo.o - scons: done building targets. - </screen> + Because the replacement occurs while + the &SConscript; files are being read, + the &cv-link-CCFLAGS; + variable has already been set to + <literal>-DDEFINE2</literal> + by the time the &foo_o; target is built, + even though the call to the &Replace; + method does not occur until later in + the &SConscript; file. - <para> + </para> - Because the replacement occurs while - the &SConscript; files are being read, - the &cv-link-CCFLAGS; - variable has already been set to - <literal>-DDEFINE2</literal> - by the time the &foo_o; target is built, - even though the call to the &Replace; - method does not occur until later in - the &SConscript; file. + </section> - </para> + <section> + <title>Setting Values Only If They're Not Already Defined: the &SetDefault; Method</title> - </section> + <para> - <!-- + Sometimes it's useful to be able to specify + that a construction variable should be + set to a value only if the construction environment + does not already have that variable defined + You can do this with the &SetDefault; method, + which behaves similarly to the <function>set_default</function> + method of Python dictionary objects: - <section> - <title>Setting Values Only If They're Not Already Defined</title> + </para> - <para> + <programlisting> + env.SetDefault(SPECIAL_FLAG = '-extra-option') + </programlisting> - XXX SetDefault() + <para> - </para> + This is especially useful + when writing your own <literal>Tool</literal> modules + to apply variables to construction environments. + <!-- + See <xref linkend="chap-tool-modules"></xref> + for more information about writing + Tool modules. + --> - </section> + </para> - --> + </section> - <section> - <title>Appending to the End of Values in a &ConsEnv;</title> + <section> + <title>Appending to the End of Values: the &Append; Method</title> - <para> + <para> - You can append a value to - an existing construction variable - using the &Append; method: + You can append a value to + an existing construction variable + using the &Append; method: - </para> + </para> - <programlisting> - env = Environment(CCFLAGS = '-DMY_VALUE') - env.Append(CCFLAGS = ' -DLAST') - env.Program('foo.c') - </programlisting> + <programlisting> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Append(CCFLAGS = ['-DLAST']) + env.Program('foo.c') + </programlisting> - <para> + <para> - &SCons; then supplies both the <literal>-DMY_VALUE</literal> and - <literal>-DLAST</literal> flags when compiling the object file: + &SCons; then supplies both the <literal>-DMY_VALUE</literal> and + <literal>-DLAST</literal> flags when compiling the object file: - </para> + </para> - <screen> - % <userinput>scons -Q</userinput> - cc -o foo.o -c -DMY_VALUE -DLAST foo.c - cc -o foo foo.o - </screen> + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DMY_VALUE -DLAST foo.c + cc -o foo foo.o + </screen> - <para> + <para> - If the construction variable doesn't already exist, - the &Append; method will create it: + If the construction variable doesn't already exist, + the &Append; method will create it: - </para> + </para> - <programlisting> - env = Environment() - env.Append(NEW_VARIABLE = 'added') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - </programlisting> + <programlisting> + env = Environment() + env.Append(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> - <para> + <para> - Which yields: + Which yields: - </para> + </para> - <screen> - % <userinput>scons -Q</userinput> - NEW_VARIABLE = added - scons: `.' is up to date. - </screen> + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = added + scons: `.' is up to date. + </screen> - <!-- + <para> - XXX AppendUnique() + Note that the &Append; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. - --> + </para> - </section> + </section> - <section> - <title>Appending to the Beginning of Values in a &ConsEnv;</title> + <section> + <title>Appending Unique Values: the &AppendUnique; Method</title> - <para> + <para> - You can append a value to the beginning of - an existing construction variable - using the &Prepend; method: + Some times it's useful to add a new value + only if the existing construction variable + doesn't already contain the value. + This can be done using the &AppendUnique; method: - </para> + </para> - <programlisting> - env = Environment(CCFLAGS = '-DMY_VALUE') - env.Prepend(CCFLAGS = '-DFIRST ') - env.Program('foo.c') - </programlisting> + <programlisting> + env.AppendUnique(CCFLAGS=['-g']) + </programlisting> - <para> + <para> - &SCons; then supplies both the <literal>-DFIRST</literal> and - <literal>-DMY_VALUE</literal> flags when compiling the object file: + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. - </para> + </para> - <screen> - % <userinput>scons -Q</userinput> - cc -o foo.o -c -DFIRST -DMY_VALUE foo.c - cc -o foo foo.o - </screen> + </section> - <para> + <section> + <title>Appending to the Beginning of Values: the &Prepend; Method</title> - If the construction variable doesn't already exist, - the &Prepend; method will create it: + <para> - </para> + You can append a value to the beginning of + an existing construction variable + using the &Prepend; method: - <programlisting> - env = Environment() - env.Prepend(NEW_VARIABLE = 'added') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - </programlisting> + </para> - <para> + <programlisting> + env = Environment(CCFLAGS = ['-DMY_VALUE']) + env.Prepend(CCFLAGS = ['-DFIRST']) + env.Program('foo.c') + </programlisting> - Which yields: + <para> - </para> + &SCons; then supplies both the <literal>-DFIRST</literal> and + <literal>-DMY_VALUE</literal> flags when compiling the object file: - <screen> - % <userinput>scons -Q</userinput> - NEW_VARIABLE = added - scons: `.' is up to date. - </screen> + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o foo.o -c -DFIRST -DMY_VALUE foo.c + cc -o foo foo.o + </screen> + + <para> + + If the construction variable doesn't already exist, + the &Prepend; method will create it: + + </para> + + <programlisting> + env = Environment() + env.Prepend(NEW_VARIABLE = 'added') + print "NEW_VARIABLE =", env['NEW_VARIABLE'] + </programlisting> + + <para> + + Which yields: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + NEW_VARIABLE = added + scons: `.' is up to date. + </screen> + + <para> + + Like the &Append; function, + the &Prepend; function tries to be "smart" + about how the new value is appended to the old value. + If both are strings, the previous and new strings + are simply concatenated. + Similarly, if both are lists, + the lists are concatenated. + If, however, one is a string and the other is a list, + the string is added as a new element to the list. + + </para> + + </section> + + <section> + <title>Prepending Unique Values: the &PrependUnique; Method</title> + + <para> + + Some times it's useful to add a new value + to the beginning of a construction variable + only if the existing value + doesn't already contain the to-be-added value. + This can be done using the &PrependUnique; method: + + </para> + + <programlisting> + env.PrependUnique(CCFLAGS=['-g']) + </programlisting> + + <para> - <!-- + In the above example, + the <literal>-g</literal> would be added + only if the &cv-CCFLAGS; variable + does not already contain a <literal>-g</literal> value. - XXX PrependUnique() + </para> - --> + </section> - </section> + </section> - <!-- + <section id="sect-execution-environments"> + <title>Controlling the Execution Environment for Issued Commands</title> - <section> - <title>Adding to Values in the Execution Environment</title> + <para> - <para> + When &SCons; builds a target file, + it does not execute the commands with + the same external environment + that you used to execute &SCons;. + Instead, it uses the dictionary + stored in the &cv-link-ENV; construction variable + as the external environment + for executing commands. - XXX AppendENVPath() + </para> - XXX PrependENVPath() + <para> - </para> + The most important ramification of this behavior + is that the &PATH; environment variable, + which controls where the operating system + will look for commands and utilities, + is not the same as in the external environment + from which you called &SCons;. + This means that &SCons; will not, by default, + necessarily find all of the tools + that you can execute from the command line. - </section> + </para> - --> + <para> - </section> + The default value of the &PATH; environment variable + on a POSIX system + is <literal>/usr/local/bin:/bin:/usr/bin</literal>. + The default value of the &PATH; environment variable + on a Windows system comes from the Windows registry + value for the command interpreter. + If you want to execute any commands--compilers, linkers, etc.--that + are not in these default locations, + you need to set the &PATH; value + in the &cv-ENV; dictionary + in your construction environment. + + </para> + + <para> + + The simplest way to do this is to initialize explicitly + the value when you create the construction environment; + this is one way to do that: + + </para> + + <programlisting> + path = ['/usr/local/bin', '/bin', '/usr/bin'] + env = Environment(ENV = {'PATH' : path}) + </programlisting> + + <para> + + Assign a dictionary to the &cv-ENV; + construction variable in this way + completely resets the external environment + so that the only variable that will be + set when external commands are executed + will be the &PATH; value. + If you want to use the rest of + the values in &cv-ENV; and only + set the value of &PATH;, + the most straightforward way is probably: + + </para> + + <programlisting> + env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin'] + </programlisting> + + <para> + + Note that &SCons; does allow you to define + the directories in the &PATH; in a string, + separated by the pathname-separator character + for your system (':' on POSIX systems, ';' on Windows): + + </para> + + <programlisting> + env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' + </programlisting> + + <para> + + But doing so makes your &SConscript; file less portable, + (although in this case that may not be a huge concern + since the directories you list are likley system-specific, anyway). + + </para> + + <!-- + + <scons_example name="ex1"> + <file name="SConstruct" printme="1"> + env = Environment() + env.Command('foo', [], '__ROOT__/usr/bin/printenv.py') + </file> + <file name="__ROOT__/usr/bin/printenv.py" chmod="0755"> + #!/usr/bin/env python + import os + import sys + if len(sys.argv) > 1: + keys = sys.argv[1:] + else: + keys = os.environ.keys() + keys.sort() + for key in keys: + print " " + key + "=" + os.environ[key] + </file> + </scons_example> + + <para> + + </para> + + <scons_output example="ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + --> + + <section> + <title>Propagating &PATH; From the External Environment</title> + + <para> + + You may want to propagate the external &PATH; + to the execution environment for commands. + You do this by initializing the &PATH; + variable with the &PATH; value from + the <literal>os.environ</literal> + dictionary, + which is Python's way of letting you + get at the external environment: + + </para> + + <programlisting> + import os + env = Environment(ENV = {'PATH' : os.environ['PATH']}) + </programlisting> + + <para> + + Alternatively, you may find it easier + to just propagate the entire external + environment to the execution environment + for commands. + This is simpler to code than explicity + selecting the &PATH; value: + + </para> + + <programlisting> + import os + env = Environment(ENV = os.environ) + </programlisting> + + <para> + + Either of these will guarantee that + &SCons; will be able to execute + any command that you can execute from the command line. + The drawback is that the build can behave + differently if it's run by people with + different &PATH; values in their environment--for example, + if both the <literal>/bin</literal> and + <literal>/usr/local/bin</literal> directories + have different &cc; commands, + then which one will be used to compile programs + will depend on which directory is listed + first in the user's &PATH; variable. + + </para> + + </section> + + <section> + <title>Adding to <varname>PATH</varname> Values in the Execution Environment</title> + + <para> + + One of the most common requirements + for manipulating a variable in the execution environment + is to add one or more custom directories to a search + like the <envar>$PATH</envar> variable on Linux or POSIX systems, + or the <envar>%PATH%</envar> variable on Windows, + so that a locally-installed compiler or other utility + can be found when &SCons; tries to execute it to update a target. + &SCons; provides &PrependENVPath; and &AppendENVPath; functions + to make adding things to execution variables convenient. + You call these functions by specifying the variable + to which you want the value added, + and then value itself. + So to add some <filename>/usr/local</filename> directories + to the <envar>$PATH</envar> and <envar>$LIB</envar> variables, + you might: + + </para> + + <programlisting> + env = Environment(ENV = os.environ) + env.PrependENVPath('PATH', '/usr/local/bin') + env.AppendENVPath('LIB', '/usr/local/lib') + </programlisting> + + <para> + + Note that the added values are strings, + and if you want to add multiple directories to + a variable like <envar>$PATH</envar>, + you must include the path separate character + (<literal>:</literal> on Linux or POSIX, + <literal>;</literal> on Windows) + in the string. + + </para> + + </section> + + </section> |