From 9e7cf970a730549348fd22a0921ea0ed2e894a69 Mon Sep 17 00:00:00 2001 From: Dirk Baechle Date: Sat, 4 May 2013 00:08:59 +0200 Subject: - removed *.in files from the user guide --- doc/user/actions.in | 404 ------- doc/user/actions.xml | 8 +- doc/user/add-method.in | 127 --- doc/user/add-method.xml | 51 +- doc/user/alias.in | 102 -- doc/user/alias.xml | 74 +- doc/user/ant.in | 52 - doc/user/build-install.in | 709 ------------ doc/user/builders-built-in.in | 950 ---------------- doc/user/builders-built-in.xml | 105 +- doc/user/builders-commands.in | 156 --- doc/user/builders-commands.xml | 40 +- doc/user/builders-writing.in | 1108 ------------------- doc/user/builders-writing.xml | 284 +++-- doc/user/builders.in | 57 - doc/user/caching.in | 502 --------- doc/user/caching.xml | 144 ++- doc/user/command-line.in | 2345 ---------------------------------------- doc/user/command-line.xml | 824 +++++++------- doc/user/copyright.in | 32 - doc/user/depends.in | 1872 -------------------------------- doc/user/depends.xml | 536 ++++----- doc/user/environments.in | 1752 ------------------------------ doc/user/environments.xml | 392 +++---- doc/user/errors.in | 41 - doc/user/example.in | 41 - doc/user/factories.in | 507 --------- doc/user/factories.xml | 209 ++-- doc/user/file-removal.in | 223 ---- doc/user/file-removal.xml | 91 +- doc/user/functions.in | 38 - doc/user/gettext.in | 351 ------ doc/user/gettext.xml | 51 +- doc/user/hierarchy.in | 794 -------------- doc/user/hierarchy.xml | 214 ++-- doc/user/install.in | 247 ----- doc/user/install.xml | 136 +-- doc/user/java.in | 657 ----------- doc/user/java.xml | 366 +++++-- doc/user/less-simple.in | 623 ----------- doc/user/less-simple.xml | 171 +-- doc/user/libraries.in | 445 -------- doc/user/libraries.xml | 193 ++-- doc/user/main.in | 411 ------- doc/user/make.in | 121 --- doc/user/mergeflags.in | 137 --- doc/user/mergeflags.xml | 45 +- doc/user/misc.in | 606 ----------- doc/user/misc.xml | 221 ++-- doc/user/nodes.in | 431 -------- doc/user/nodes.xml | 117 +- doc/user/output.in | 681 ------------ doc/user/output.xml | 138 ++- doc/user/parseconfig.in | 140 --- doc/user/parseconfig.xml | 12 +- doc/user/parseflags.in | 176 --- doc/user/parseflags.xml | 92 +- doc/user/preface.in | 426 -------- doc/user/python.in | 154 --- doc/user/repositories.in | 641 ----------- doc/user/repositories.xml | 160 ++- doc/user/run.in | 375 ------- doc/user/scanners.in | 392 ------- doc/user/scanners.xml | 26 +- doc/user/sconf.in | 486 --------- doc/user/sconf.xml | 54 +- doc/user/separate.in | 540 --------- doc/user/separate.xml | 150 +-- doc/user/sideeffect.in | 216 ---- doc/user/sideeffect.xml | 37 +- doc/user/simple.in | 517 --------- doc/user/simple.xml | 194 ++-- doc/user/sourcecode.in | 162 --- doc/user/sourcecode.xml | 71 +- doc/user/tasks.in | 146 --- doc/user/tasks.xml | 39 +- doc/user/tools.in | 38 - doc/user/troubleshoot.in | 914 ---------------- doc/user/troubleshoot.xml | 798 ++++---------- doc/user/variables.in | 56 - doc/user/variants.in | 151 --- doc/user/variants.xml | 64 +- 82 files changed, 3241 insertions(+), 24918 deletions(-) delete mode 100644 doc/user/actions.in delete mode 100644 doc/user/add-method.in delete mode 100644 doc/user/alias.in delete mode 100644 doc/user/ant.in delete mode 100644 doc/user/build-install.in delete mode 100644 doc/user/builders-built-in.in delete mode 100644 doc/user/builders-commands.in delete mode 100644 doc/user/builders-writing.in delete mode 100644 doc/user/builders.in delete mode 100644 doc/user/caching.in delete mode 100644 doc/user/command-line.in delete mode 100644 doc/user/copyright.in delete mode 100644 doc/user/depends.in delete mode 100644 doc/user/environments.in delete mode 100644 doc/user/errors.in delete mode 100644 doc/user/example.in delete mode 100644 doc/user/factories.in delete mode 100644 doc/user/file-removal.in delete mode 100644 doc/user/functions.in delete mode 100644 doc/user/gettext.in delete mode 100644 doc/user/hierarchy.in delete mode 100644 doc/user/install.in delete mode 100644 doc/user/java.in delete mode 100644 doc/user/less-simple.in delete mode 100644 doc/user/libraries.in delete mode 100644 doc/user/main.in delete mode 100644 doc/user/make.in delete mode 100644 doc/user/mergeflags.in delete mode 100644 doc/user/misc.in delete mode 100644 doc/user/nodes.in delete mode 100644 doc/user/output.in delete mode 100644 doc/user/parseconfig.in delete mode 100644 doc/user/parseflags.in delete mode 100644 doc/user/preface.in delete mode 100644 doc/user/python.in delete mode 100644 doc/user/repositories.in delete mode 100644 doc/user/run.in delete mode 100644 doc/user/scanners.in delete mode 100644 doc/user/sconf.in delete mode 100644 doc/user/separate.in delete mode 100644 doc/user/sideeffect.in delete mode 100644 doc/user/simple.in delete mode 100644 doc/user/sourcecode.in delete mode 100644 doc/user/tasks.in delete mode 100644 doc/user/tools.in delete mode 100644 doc/user/troubleshoot.in delete mode 100644 doc/user/variables.in delete mode 100644 doc/user/variants.in diff --git a/doc/user/actions.in b/doc/user/actions.in deleted file mode 100644 index d2a3dad..0000000 --- a/doc/user/actions.in +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - &SCons; supports several types of &build_actions; - that can be performed to build one or more target files. - Usually, a &build_action; is a command-line string - that invokes an external command. - A build action can also be an external command - specified as a list of arguments, - or even a Python function. - - - - - - Build action objects are created by the &Action; function. - This function is, in fact, what &SCons; uses - to interpret the &action; - keyword argument when you call the &Builder; function. - So the following line that creates a simple Builder: - - - - - b = Builder(action = 'build < $SOURCE > $TARGET') - - - - - Is equivalent to: - - - - - b = Builder(action = Action('build < $SOURCE > $TARGET')) - - - - - The advantage of using the &Action; function directly - is that it can take a number of additional options - to modify the action's behavior in many useful ways. - - - -
- Command Strings as Actions - -
- Suppressing Command-Line Printing - - - - XXX - - - -
- -
- Ignoring Exit Status - - - - XXX - - - -
- -
- -
- Argument Lists as Actions - - - - XXX - - - -
- -
- Python Functions as Actions - - - - XXX - - - -
- -
- Modifying How an Action is Printed - -
- XXX: the &strfunction; keyword argument - - - - XXX - - - -
- -
- XXX: the &cmdstr; keyword argument - - - - XXX - - - -
- -
- -
- Making an Action Depend on Variable Contents: the &varlist; keyword argument - - - - XXX - - - -
- -
- chdir=1 - - - - XXX - - - -
- -
- Batch Building of Multiple Targets from Separate Sources: the &batch_key; keyword argument - - - - XXX - - - -
- -
- Manipulating the Exit Status of an Action: the &exitstatfunc; keyword argument - - - - XXX - - - -
- - diff --git a/doc/user/actions.xml b/doc/user/actions.xml index ea76eb9..d2a3dad 100644 --- a/doc/user/actions.xml +++ b/doc/user/actions.xml @@ -244,9 +244,9 @@ solutions to the above limitations. - + b = Builder(action = 'build < $SOURCE > $TARGET') - + @@ -254,9 +254,9 @@ solutions to the above limitations. - + b = Builder(action = Action('build < $SOURCE > $TARGET')) - + diff --git a/doc/user/add-method.in b/doc/user/add-method.in deleted file mode 100644 index 2deb07a..0000000 --- a/doc/user/add-method.in +++ /dev/null @@ -1,127 +0,0 @@ - - - - - The &AddMethod; function is used to add a method - to an environment. It's typically used to add a "pseudo-builder," - a function that looks like a &Builder; but - wraps up calls to multiple other &Builder;s - or otherwise processes its arguments - before calling one or more &Builder;s. - In the following example, - we want to install the program into the standard - /usr/bin directory hierarchy, - but also copy it into a local install/bin - directory from which a package might be built: - - - - - - def install_in_bin_dirs(env, source): - """Install source in both bin dirs""" - i1 = env.Install("$BIN", source) - i2 = env.Install("$LOCALBIN", source) - return [i1[0], i2[0]] # Return a list, like a normal builder - env = Environment(BIN='__ROOT__/usr/bin', LOCALBIN='#install/bin') - env.AddMethod(install_in_bin_dirs, "InstallInBinDirs") - env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs - - - int main() { printf("Hello, world!\n"); } - - - - - This produces the following: - - - - scons -Q / - - - - - As mentioned, a pseudo-builder also provides more flexibility - in parsing arguments than you can get with a &Builder;. - The next example shows a pseudo-builder with a - named argument that modifies the filename, and a separate argument - for the resource file (rather than having the builder figure it out - by file extension). This example also demonstrates using the global - &AddMethod; function to add a method to the global Environment class, - so it will be used in all subsequently created environments. - - - - - - def BuildTestProg(env, testfile, resourcefile, testdir="tests"): - """Build the test program; - prepends "test_" to src and target, - and puts target into testdir.""" - srcfile = "test_%s.c" % testfile - target = "%s/test_%s" % (testdir, testfile) - if env['PLATFORM'] == 'win32': - resfile = env.RES(resourcefile) - p = env.Program(target, [srcfile, resfile]) - else: - p = env.Program(target, srcfile) - return p - AddMethod(Environment, BuildTestProg) - - env = Environment() - env.BuildTestProg('stuff', resourcefile='res.rc') - - - int main() { printf("Hello, world!\n"); } - - - res.rc - - - - - This produces the following on Linux: - - - - scons -Q - - - - And the following on Windows: - - - - scons -Q - - - - Using &AddMethod; is better than just adding an instance method - to a &consenv; because it gets called as a proper method, - and because &AddMethod; provides for copying the method - to any clones of the &consenv; instance. - diff --git a/doc/user/add-method.xml b/doc/user/add-method.xml index 3aac7a8..2deb07a 100644 --- a/doc/user/add-method.xml +++ b/doc/user/add-method.xml @@ -39,28 +39,29 @@ - + + def install_in_bin_dirs(env, source): """Install source in both bin dirs""" i1 = env.Install("$BIN", source) i2 = env.Install("$LOCALBIN", source) return [i1[0], i2[0]] # Return a list, like a normal builder - env = Environment(BIN='/usr/bin', LOCALBIN='#install/bin') + env = Environment(BIN='__ROOT__/usr/bin', LOCALBIN='#install/bin') env.AddMethod(install_in_bin_dirs, "InstallInBinDirs") env.InstallInBinDirs(Program('hello.c')) # installs hello in both bin dirs - + + + int main() { printf("Hello, world!\n"); } + + This produces the following: - - % scons -Q / - cc -o hello.o -c hello.c - cc -o hello hello.o - Install file: "hello" as "/usr/bin/hello" - Install file: "hello" as "install/bin/hello" - + + scons -Q / + @@ -75,7 +76,8 @@ - + + def BuildTestProg(env, testfile, resourcefile, testdir="tests"): """Build the test program; prepends "test_" to src and target, @@ -92,29 +94,30 @@ env = Environment() env.BuildTestProg('stuff', resourcefile='res.rc') - + + + int main() { printf("Hello, world!\n"); } + + + res.rc + + This produces the following on Linux: - - % scons -Q - cc -o test_stuff.o -c test_stuff.c - cc -o tests/test_stuff test_stuff.o - + + scons -Q + And the following on Windows: - - C:\>scons -Q - rc /fores.res res.rc - cl /Fotest_stuff.obj /c test_stuff.c /nologo - link /nologo /OUT:tests\test_stuff.exe test_stuff.obj res.res - embedManifestExeCheck(target, source, env) - + + scons -Q + Using &AddMethod; is better than just adding an instance method diff --git a/doc/user/alias.in b/doc/user/alias.in deleted file mode 100644 index 686c004..0000000 --- a/doc/user/alias.in +++ /dev/null @@ -1,102 +0,0 @@ - - - - - We've already seen how you can use the &Alias; - function to create a target named install: - - - - - - env = Environment() - hello = env.Program('hello.c') - env.Install('__ROOT__/usr/bin', hello) - env.Alias('install', '__ROOT__/usr/bin') - - - int main() { printf("Hello, world!\n"); } - - - - - - You can then use this alias on the command line - to tell &SCons; more naturally that you want to install files: - - - - - scons -Q install - - - - - 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: - - - - - - env = Environment() - p = env.Program('foo.c') - l = env.Library('bar.c') - env.Install('__ROOT__/usr/bin', p) - env.Install('__ROOT__/usr/lib', l) - ib = env.Alias('install-bin', '__ROOT__/usr/bin') - il = env.Alias('install-lib', '__ROOT__/usr/lib') - env.Alias('install', [ib, il]) - - - int main() { printf("foo.c\n"); } - - - void bar() { printf("bar.c\n"); } - - - - - - This example defines separate install, - install-bin, - and install-lib aliases, - allowing you finer control over what gets installed: - - - - - scons -Q install-bin - scons -Q install-lib - scons -Q -c __ROOT__/ - scons -Q install - diff --git a/doc/user/alias.xml b/doc/user/alias.xml index f285d70..686c004 100644 --- a/doc/user/alias.xml +++ b/doc/user/alias.xml @@ -30,12 +30,17 @@ - + + env = Environment() hello = env.Program('hello.c') - env.Install('/usr/bin', hello) - env.Alias('install', '/usr/bin') - + env.Install('__ROOT__/usr/bin', hello) + env.Alias('install', '__ROOT__/usr/bin') + + + int main() { printf("Hello, world!\n"); } + + @@ -44,12 +49,9 @@ - - % scons -Q install - cc -o hello.o -c hello.c - cc -o hello hello.o - Install file: "hello" as "/usr/bin/hello" - + + scons -Q install + @@ -64,16 +66,24 @@ - + + env = Environment() p = env.Program('foo.c') l = env.Library('bar.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.Install('__ROOT__/usr/bin', p) + env.Install('__ROOT__/usr/lib', l) + ib = env.Alias('install-bin', '__ROOT__/usr/bin') + il = env.Alias('install-lib', '__ROOT__/usr/lib') env.Alias('install', [ib, il]) - + + + int main() { printf("foo.c\n"); } + + + void bar() { printf("bar.c\n"); } + + @@ -84,29 +94,9 @@ - - % scons -Q install-bin - cc -o foo.o -c foo.c - cc -o foo foo.o - Install file: "foo" as "/usr/bin/foo" - % scons -Q install-lib - cc -o bar.o -c bar.c - ar rc libbar.a bar.o - ranlib libbar.a - Install file: "libbar.a" as "/usr/lib/libbar.a" - % scons -Q -c / - Removed foo.o - Removed foo - Removed /usr/bin/foo - Removed bar.o - Removed libbar.a - Removed /usr/lib/libbar.a - % scons -Q install - cc -o foo.o -c foo.c - cc -o foo foo.o - Install file: "foo" as "/usr/bin/foo" - cc -o bar.o -c bar.c - ar rc libbar.a bar.o - ranlib libbar.a - Install file: "libbar.a" as "/usr/lib/libbar.a" - + + scons -Q install-bin + scons -Q install-lib + scons -Q -c __ROOT__/ + scons -Q install + diff --git a/doc/user/ant.in b/doc/user/ant.in deleted file mode 100644 index 0df1027..0000000 --- a/doc/user/ant.in +++ /dev/null @@ -1,52 +0,0 @@ - - - - - XXX - - - -
- Differences Between &Ant; and &SCons; - - - - XXX - - - -
- -
- Advantages of &SCons; Over &Ant; - - - - XXX - - - -
diff --git a/doc/user/build-install.in b/doc/user/build-install.in deleted file mode 100644 index 821d2be..0000000 --- a/doc/user/build-install.in +++ /dev/null @@ -1,709 +0,0 @@ - - - - - This chapter will take you through the basic steps - of installing &SCons; on your system, - and building &SCons; if you don't have a - pre-built package available - (or simply prefer the flexibility of building it yourself). - Before that, however, this chapter will also describe the basic steps - involved in installing Python on your system, - in case that is necessary. - Fortunately, both &SCons; and Python - are very easy to install on almost any system, - and Python already comes installed on many systems. - - - - - -
- Installing Python - - - - Because &SCons; is written in Python, - you must obviously have Python installed on your system - to use &SCons;. - Before you try to install Python, - you should check to see if Python is already - available on your system by typing - python -V - (capital 'V') - or - python --version - at your system's command-line prompt. - - - - - $ python -V - Python 2.5.1 - - - - - And on a Windows system with Python installed: - - - - - C:\>python -V - Python 2.5.1 - - - - - If Python is not installed on your system, - you will see an error message - stating something like "command not found" - (on UNIX or Linux) - or "'python' is not recognized - as an internal or external command, operable progam or batch file" - (on Windows). - In that case, you need to install Python - before you can install &SCons;. - - - - - - The standard location for information - about downloading and installing Python is - http://www.python.org/download/. - See that page for information about - how to download and install Python on your system. - - - - - - &SCons; will work with any 2.x version of Python from 2.4 on; - 3.0 and later are not yet supported. - If you need to install Python and have a choice, - we recommend using the most recent 2.x Python version available. - Newer Pythons have significant improvements - that help speed up the performance of &SCons;. - - - -
- -
- Installing &SCons; From Pre-Built Packages - - - - &SCons; comes pre-packaged for installation on a number of systems, - including Linux and Windows systems. - You do not need to read this entire section, - you should need to read only the section - appropriate to the type of system you're running on. - - - -
- Installing &SCons; on Red Hat (and Other RPM-based) Linux Systems - - - - &SCons; comes in RPM (Red Hat Package Manager) format, - pre-built and ready to install on Red Hat Linux, - Fedora, - or any other Linux distribution that uses RPM. - Your distribution may - already have an &SCons; RPM built specifically for it; - many do, including SUSE, Mandrake and Fedora. - You can check for the availability of an &SCons; RPM - on your distribution's download servers, - or by consulting an RPM search site like - http://www.rpmfind.net/ or - http://rpm.pbone.net/. - - - - - - If your distribution supports installation via - yum, - you should be able to install &SCons; by running: - - - - - # yum install scons - - - - - If your Linux distribution does not already have - a specific &SCons; RPM file, - you can download and install from the - generic RPM provided by the &SCons; project. - This will install the - SCons script(s) in /usr/bin, - and the SCons library modules in - /usr/lib/scons. - - - - - - To install from the command line, simply download the - appropriate .rpm file, - and then run: - - - - - # rpm -Uvh scons-__VERSION__-1.noarch.rpm - - - - - Or, you can use a graphical RPM package manager. - See your package manager application's documention - for specific instructions about - how to use it to install a downloaded RPM. - - - -
- -
- Installing &SCons; on Debian Linux Systems - - - - Debian Linux systems use a different package management - format that also makes it very easy to install &SCons;. - - - - - - If your system is connected to the Internet, - you can install the latest official Debian package - by running: - - - - - # apt-get install scons - - - - -
- -
- Installing &SCons; on Windows Systems - - - - &SCons; provides a Windows installer - that makes installation extremely easy. - Download the scons-__VERSION__.win32.exe - file from the &SCons; download page at - http://www.scons.org/download.php. - Then all you need to do is execute the file - (usually by clicking on its icon in Windows Explorer). - These will take you through a small - sequence of windows that will install - &SCons; on your system. - - - - - - - - - -
- -
- -
- Building and Installing &SCons; on Any System - - - - If a pre-built &SCons; package is not available for your system, - then you can still easily build and install &SCons; using the native - Python distutils package. - - - - - - The first step is to download either the - scons-__VERSION__.tar.gz - or scons-__VERSION__.zip, - which are available from the SCons download page at - http://www.scons.org/download.html. - - - - - - Unpack the archive you downloaded, - using a utility like tar - on Linux or UNIX, - or WinZip on Windows. - This will create a directory called - scons-__VERSION__, - usually in your local directory. - Then change your working directory to that directory - and install &SCons; by executing the following commands: - - - - - # cd scons-__VERSION__ - # python setup.py install - - - - - This will build &SCons;, - install the &scons; script - in the python which is used to run the setup.py's scripts directory - (/usr/local/bin or - C:\Python25\Scripts), - and will install the &SCons; build engine - in the corresponding library directory for the python used - (/usr/local/lib/scons or - C:\Python25\scons). - Because these are system directories, - you may need root (on Linux or UNIX) or Administrator (on Windows) - privileges to install &SCons; like this. - - - - - -
- Building and Installing Multiple Versions of &SCons; Side-by-Side - - - - The &SCons; setup.py script - has some extensions that support - easy installation of multiple versions of &SCons; - in side-by-side locations. - This makes it easier to download and - experiment with different versions of &SCons; - before moving your official build process to a new version, - for example. - - - - - - To install &SCons; in a version-specific location, - add the option - when you call setup.py: - - - - - # python setup.py install --version-lib - - - - - This will install the &SCons; build engine - in the - /usr/lib/scons-__VERSION__ - or - C:\Python25\scons-__VERSION__ - directory, for example. - - - - - - If you use the option - the first time you install &SCons;, - you do not need to specify it each time you install - a new version. - The &SCons; setup.py script - will detect the version-specific directory name(s) - and assume you want to install all versions - in version-specific directories. - You can override that assumption in the future - by explicitly specifying the option. - - - -
- -
- Installing &SCons; in Other Locations - - - - You can install &SCons; in locations other than - the default by specifying the option: - - - - - # python setup.py install --prefix=/opt/scons - - - - - This would - install the scons script in - /opt/scons/bin - and the build engine in - /opt/scons/lib/scons, - - - - - - Note that you can specify both the - and the options - at the same type, - in which case setup.py - will install the build engine - in a version-specific directory - relative to the specified prefix. - Adding to the - above example would install the build engine in - /opt/scons/lib/scons-__VERSION__. - - - -
- -
- Building and Installing &SCons; Without Administrative Privileges - - - - If you don't have the right privileges to install &SCons; - in a system location, - simply use the --prefix= option - to install it in a location of your choosing. - For example, - to install &SCons; in appropriate locations - relative to the user's $HOME directory, - the &scons; script in - $HOME/bin - and the build engine in - $HOME/lib/scons, - simply type: - - - - - $ python setup.py install --prefix=$HOME - - - - - You may, of course, specify any other location you prefer, - and may use the option - if you would like to install version-specific directories - relative to the specified prefix. - - - - - - This can also be used to experiment with a newer - version of &SCons; than the one installed - in your system locations. - Of course, the location in which you install the - newer version of the &scons; script - ($HOME/bin in the above example) - must be configured in your &PATH; variable - before the directory containing - the system-installed version - of the &scons; script. - - - -
- -
- - diff --git a/doc/user/builders-built-in.in b/doc/user/builders-built-in.in deleted file mode 100644 index 3b5b981..0000000 --- a/doc/user/builders-built-in.in +++ /dev/null @@ -1,950 +0,0 @@ - - - - - &SCons; provides the ability to build a lot of different - types of files right "out of the box." - So far, we've been using &SCons;' ability to build - programs, objects and libraries to - illustrate much of the underlying functionality of &SCons; - This section will describe all of the different - types of files that you can build with &SCons;, - and the built-in &Builder; objects used to build them. - By default, all of the &Builder; objects in this section - can be built either with or without an explicit - construction environment. - - - -
- Programs: the &Program; Builder - - - - As we've seen, the &b-link-Program; Builder - is used to build an executable program. - The &source; argument is one or more - source-code files or object files, - and the ⌖ argument is the - name of the executable program name to be created. - For example: - - - - - Program('prog', 'file1.o') - - - - - Will create the &prog; - executable on a POSIX system, - the &prog_exe; executable on a Windows system. - - - - - - The target file's prefix and suffix may be omitted, - and the values from the - &cv-link-PROGPREFIX; - and - &cv-link-PROGSUFFIX; - construction variables - will be appended appropriately. - For example: - - - - - env = Environment(PROGPREFIX='my', PROGSUFFIX='.xxx') - env.Program('prog', ['file1.o', 'file2.o']) - - - - - Will create a program named - myprog.xxx - regardless of the system on which it is run. - - - - - - If you omit the ⌖, - the base of the first input - file name specified - becomes the base of the target - program created. - For example: - - - - - Program(['hello.c', 'goodbye.c']) - - - - - Will create the &hello; - executable on a POSIX system, - the &hello_exe; executable on a Windows system. - - - - - - Two construction variables control what libraries - will be linked with the resulting program. - The &cv-link-LIBS; variable is a list of the names of - libraries that will be linked into any programs, - and the &cv-link-LIBPATH; variables is a list of - directories that will be searched for - the specified libraries. - &SCons; will construct the right command-line - options for the running system. - For example: - - - - - - env = Environment(LIBS = ['foo1', 'foo2'], - LIBPATH = ['/usr/dir1', 'dir2']) - env.Program(['hello.c', 'goodbye.c']) - - - int hello() { printf("Hello, world!\n"); } - - - int goodbye() { printf("Goodbye, world!\n"); } - - - - - - Will execute as follows on a POSIX system: - - - - - scons -Q - - - - - And execute as follows on a Windows system: - - - - - scons -Q - - - - - The &cv-LIBS; construction variable - is turned into command line options - by appending the &cv-link-LIBLINKPREFIX; and &cv-link-LIBLINKSUFFIX; - construction variables to the beginning and end, - respectively, of each specified library. - - - - - - The &cv-LIBPATH; construction variable - is turned into command line options - by appending the &cv-link-LIBDIRPREFIX; and &cv-link-LIBDIRSUFFIX; - construction variables to the beginning and end, - respectively, of each specified library. - - - - - - Other relevant construction variables - include those used by the &b-link-Object; - builders to affect how the - source files specified as input to the &t-Program; - builders are turned into object files; - see the next section. - - - - - - The command line used to control how a program is linked - is specified by the &cv-link-LINKCOM; construction variable. - By default, it uses the - &cv-link-LINK; construction variable - and the &cv-link-LINKFLAGS; construction variable. - - - -
- -
- Object-File Builders - - - - &SCons; provides separate Builder objects - to create static and shared object files. - The distinction becomes especially important when - archiving object files into different types of libraries. - - - -
- The &StaticObject; Builder - - - - The &b-link-StaticObject; Builder - is used to build an object file - suitable for static linking into a program, - or for inclusion in a static library. - The &source; argument is a single source-code file, - and the ⌖ argument is the - name of the static object file to be created. - For example: - - - - - StaticObject('file', 'file.c') - - - - - Will create the &file_o; - object file on a POSIX system, - the &file_obj; executable on a Windows system. - - - - - - The target file's prefix and suffix may be omitted, - and the values from the - &cv-link-OBJPREFIX; - and - &cv-link-OBJSUFFIX; - construction variables - will be appended appropriately. - For example: - - - - - env = Environment(OBJPREFIX='my', OBJSUFFIX='.xxx') - env.StaticObject('file', 'file.c') - - - - - Will create an object file named - myfile.xxx - regardless of the system on which it is run. - - - - - - If you omit the ⌖, - the base of the first input - file name specified - beomces the base of the name - of the static object file to be created. - For example: - - - - - StaticObject('file.c') - - - - - Will create the &file_o; - executable on a POSIX system, - the &file_obj; executable on a Windows system. - - - -
- -
- The &SharedObject; Builder - - - - The &b-link-SharedObject; Builder - is used to build an object file - suitable for shared linking into a program, - or for inclusion in a shared library. - The &source; argument is a single source-code file, - and the ⌖ argument is the - name of the shared object file to be created. - For example: - - - - - SharedObject('file', 'file.c') - - - - - Will create the &file_o; - object file on a POSIX system, - the &file_obj; executable on a Windows system. - - - - - - The target file's prefix and suffix may be omitted, - and the values from the - &cv-link-SHOBJPREFIX; - and - &cv-link-SHOBJSUFFIX; - construction variables - will be appended appropriately. - For example: - - - - - env = Environment(SHOBJPREFIX='my', SHOBJSUFFIX='.xxx') - env.SharedObject('file', 'file.c') - - - - - Will create an object file named - myfile.xxx - regardless of the system on which it is run. - - - - - - If you omit the ⌖, - the base of the first input - file name specified - becomes the base of the name - of the shared object file to be created. - For example: - - - - - SharedObject('file.c') - - - - - Will create the &file_o; - executable on a POSIX system, - the &file_obj; executable on a Windows system. - - - -
- -
- The &Object; Builder - - - - The &b-link-Object; Builder is a synonym for &b-link-StaticObject; - and is completely equivalent. - - - -
- -
- -
- Library Builders - - - - &SCons; provides separate Builder objects - to create static and shared libraries. - - - -
- The &StaticLibrary; Builder - - - - The &b-link-StaticLibrary; Builder - is used to create a library - suitable for static linking into a program. - The &source; argument is one or more - source-code files or object files, - and the ⌖ argument is the - name of the static library to be created. - For example: - - - - - StaticLibrary('foo', ['file1.c', 'file2.c']) - - - - - The target file's prefix and suffix may be omitted, - and the values from the - &cv-link-LIBPREFIX; - and - &cv-link-LIBSUFFIX; - construction variables - will be appended appropriately. - For example: - - - - - env = Environment(LIBPREFIX='my', LIBSUFFIX='.xxx') - env.StaticLibrary('lib', ['file1.o', 'file2.o']) - - - - - Will create an object file named - mylib.xxx - regardless of the system on which it is run. - - - - - StaticLibrary('foo', ['file1.c', 'file2.c']) - - - - - If you omit the ⌖, - the base of the first input - file name specified - becomes the base of the name of the static object file to be created. - For example: - - - - - StaticLibrary(['file.c', 'another.c']) - - - - - Will create the &libfile_a; - library on a POSIX system, - the &file_lib; library on a Windows system. - - - -
- -
- The &SharedLibrary; Builder - - - - The &b-link-SharedLibrary; Builder - is used to create a shared library - suitable for linking with a program. - The &source; argument is one or more - source-code files or object files, - and the ⌖ argument is the - name of the shared library to be created. - For example: - - - - - SharedLibrary('foo', ['file1.c', 'file2.c']) - - - - - The target file's prefix and suffix may be omitted, - and the values from the - &cv-link-SHLIBPREFIX; - and - &cv-link-SHLIBSUFFIX; - construction variables - will be appended appropriately. - For example: - - - - - env = Environment(SHLIBPREFIX='my', SHLIBSUFFIX='.xxx') - env.SharedLibrary('shared', ['file1.o', 'file2.o']) - - - - - Will create an object file named - myshared.xxx - regardless of the system on which it is run. - - - - - SharedLibrary('foo', ['file1.c', 'file2.c']) - - - - - If you omit the ⌖, - the base of the first input - file name specified - becomes the base of the name of the shared library to be created. - For example: - - - - - SharedLibrary(['file.c', 'another.c']) - - - - - Will create the &libfile_so; - library on a POSIX system, - the &file_dll; library on a Windows system. - - - -
- -
- The &Library; Builder - - - - The &b-link-Library; Builder is a synonym for &b-link-StaticLibrary; - and is completely equivalent. - - - -
- -
- -
- Pre-Compiled Headers: the &PCH; Builder - - - - XXX PCH() - - - -
- -
- Microsoft Visual C++ Resource Files: the &RES; Builder - - - - XXX RES() - - - -
- -
- Source Files - - - - By default - &SCons; supports two Builder objects - that know how to build source files - from other input files. - These are typically invoked "internally" - to turn files that need preprocessing into other source files. - - - -
- The &CFile; Builder - - - - XXX CFile() - - - - - XXX CFile() programlisting - - - - XXX CFile() screen - - -
- -
- The &CXXFile; Builder - - - - XXX CXXFILE() - - - - - XXX CXXFILE() programlisting - - - - XXX CXXFILE() screen - - -
- -
- -
- Documents - - - - &SCons; provides a number of Builder objects - for creating different types of documents. - - - -
- The &DVI; Builder - - - - XXX DVI() para - - - - - XXX DVI() programlisting - - - - XXX DVI() screen - - -
- -
- The &PDF; Builder - - - - XXX PDF() para - - - -
- -
- The &PostScript; Builder - - - - XXX PostScript() para - - - - - XXX PostScript() programlisting - - - - XXX PostScript() screen - - -
- -
- -
- Archives - - - - &SCons; provides Builder objects - for creating two different types of archive files. - - - -
- The &Tar; Builder - - - - The &b-link-Tar; Builder object uses the &tar; - utility to create archives of files - and/or directory trees: - - - - - - env = Environment() - env.Tar('out1.tar', ['file1', 'file2']) - env.Tar('out2', 'directory') - - - file1 - - - file2 - - - directory/file3 - - - - - scons -Q . - - - - - One common requirement when creating a &tar; archive - is to create a compressed archive using the - option. - This is easily handled by specifying - the value of the &cv-link-TARFLAGS; variable - when you create the construction environment. - Note, however, that the used to - to instruct &tar; to create the archive - is part of the default value of &cv-TARFLAGS;, - so you need to set it both options: - - - - - - env = Environment(TARFLAGS = '-c -z') - env.Tar('out.tar.gz', 'directory') - - - directory/file - - - - - scons -Q . - - - - - you may also wish to set the value of the - &cv-link-TARSUFFIX; construction variable - to your desired suffix for compress &tar; archives, - so that &SCons; can append it to the target file name - without your having to specify it explicitly: - - - - - - env = Environment(TARFLAGS = '-c -z', - TARSUFFIX = '.tgz') - env.Tar('out', 'directory') - - - directory/file - - - - - scons -Q . - - -
- -
- The &Zip; Builder - - - - The &b-link-Zip; Builder object creates archives of files - and/or directory trees in the ZIP file format. - Python versions 1.6 or later - contain an internal &zipfile; module - that &SCons; will use. - In this case, given the following - &SConstruct; file: - - - - - - env = Environment() - env.Zip('out', ['file1', 'file2']) - - - file1 - - - file2 - - - - - - Your output will reflect the fact - that an internal Python function - is being used to create the output ZIP archive: - - - - - scons -Q . - - -
- -
- -
- Java - - - - &SCons; provides Builder objects - for creating various types of Java output files. - - - -
- Building Class Files: the &Java; Builder - - - - The &b-link-Java; builder takes one or more input - .java files - and turns them into one or more - .class files - Unlike most builders, however, - the &Java; builder takes - target and source directories, - not files, as input. - - - - - env = Environment() - env.Java(target = 'classes', source = 'src') - - - - - The &Java; builder will then - search the specified source directory - tree for all .java files, - and pass any out-of-date - - - - - XXX Java() screen - - -
- -
- The &Jar; Builder - - - - XXX The &Jar; builder object - - - - - env = Environment() - env.Java(target = 'classes', source = 'src') - env.Jar(target = '', source = 'classes') - - - - XXX Jar() screen - - -
- -
- Building C header and stub files: the &JavaH; Builder - - - - XXX JavaH() para - - - - - XXX JavaH() programlisting - - - - XXX JavaH() screen - - -
- -
- Building RMI stub and skeleton class files: the &RMIC; Builder - - - - XXX RMIC() para - - - - - XXX RMIC() programlisting - - - - XXX RMIC() screen - - -
- -
diff --git a/doc/user/builders-built-in.xml b/doc/user/builders-built-in.xml index 1356022..3b5b981 100644 --- a/doc/user/builders-built-in.xml +++ b/doc/user/builders-built-in.xml @@ -130,11 +130,19 @@ - + + env = Environment(LIBS = ['foo1', 'foo2'], LIBPATH = ['/usr/dir1', 'dir2']) env.Program(['hello.c', 'goodbye.c']) - + + + int hello() { printf("Hello, world!\n"); } + + + int goodbye() { printf("Goodbye, world!\n"); } + + @@ -142,12 +150,9 @@ - - % scons -Q - cc -o goodbye.o -c goodbye.c - cc -o hello.o -c hello.c - cc -o hello hello.o goodbye.o -L/usr/dir1 -Ldir2 -lfoo1 -lfoo2 - + + scons -Q + @@ -155,13 +160,9 @@ - - C:\>scons -Q - cl /Fogoodbye.obj /c goodbye.c /nologo - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe /LIBPATH:\usr\dir1 /LIBPATH:dir2 foo1.lib foo2.lib hello.obj goodbye.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -720,17 +721,26 @@ - + + env = Environment() env.Tar('out1.tar', ['file1', 'file2']) env.Tar('out2', 'directory') - + + + file1 + + + file2 + + + directory/file3 + + - - % scons -Q . - tar -c -f out1.tar file1 file2 - tar -c -f out2.tar directory - + + scons -Q . + @@ -747,15 +757,19 @@ - + + env = Environment(TARFLAGS = '-c -z') env.Tar('out.tar.gz', 'directory') - + + + directory/file + + - - % scons -Q . - tar -c -z -f out.tar.gz directory - + + scons -Q . + @@ -767,16 +781,20 @@ - + + env = Environment(TARFLAGS = '-c -z', TARSUFFIX = '.tgz') env.Tar('out', 'directory') - + + + directory/file + + - - % scons -Q . - tar -c -z -f out.tgz directory - + + scons -Q . + @@ -795,10 +813,18 @@ - + + env = Environment() env.Zip('out', ['file1', 'file2']) - + + + file1 + + + file2 + + @@ -808,10 +834,9 @@ - - % scons -Q . - zip(["out.zip"], ["file1", "file2"]) - + + scons -Q . + diff --git a/doc/user/builders-commands.in b/doc/user/builders-commands.in deleted file mode 100644 index d0aae61..0000000 --- a/doc/user/builders-commands.in +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - Creating a &Builder; and attaching it to a &consenv; - allows for a lot of flexibility when you - want to re-use 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 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 &b-link-Program;, &b-link-Object;, etc.), - but takes as an additional argument - the command to be executed to build the file: - - - - - - env = Environment() - env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET") - - - foo.in - - - - - - When executed, - &SCons; runs the specified command, - substituting &cv-link-SOURCE; and &cv-link-TARGET; - as expected: - - - - - scons -Q - - - - - This is often more convenient than - creating a &Builder; object - and adding it to the &cv-link-BUILDERS; variable - of a &consenv; - - - - - - Note that the action you specify to the - &Command; &Builder; can be any legal &SCons; &Action;, - such as a Python function: - - - - - - env = Environment() - def build(target, source, env): - # Whatever it takes to build - return None - env.Command('foo.out', 'foo.in', build) - - - foo.in - - - - - - Which executes as follows: - - - - - scons -Q - - - - - Note that &cv-link-SOURCE; and &cv-link-TARGET; are expanded - in the source and target as well as of SCons 1.1, - so you can write: - - - - - - env.Command('${SOURCE.basename}.out', 'foo.in', build) - - - - - - - which does the same thing as the previous example, but allows you - to avoid repeating yourself. - - - diff --git a/doc/user/builders-commands.xml b/doc/user/builders-commands.xml index fcb2a96..d0aae61 100644 --- a/doc/user/builders-commands.xml +++ b/doc/user/builders-commands.xml @@ -69,10 +69,15 @@ - + + env = Environment() - env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET") - + env.Command('foo.out', 'foo.in', "sed 's/x/y/' < $SOURCE > $TARGET") + + + foo.in + + @@ -83,10 +88,9 @@ - - % scons -Q - sed 's/x/y/' < foo.in > foo.out - + + scons -Q + @@ -105,13 +109,18 @@ - + + env = Environment() def build(target, source, env): # Whatever it takes to build return None env.Command('foo.out', 'foo.in', build) - + + + foo.in + + @@ -119,10 +128,9 @@ - - % scons -Q - build(["foo.out"], ["foo.in"]) - + + scons -Q + @@ -132,9 +140,11 @@ - + + env.Command('${SOURCE.basename}.out', 'foo.in', build) - + + diff --git a/doc/user/builders-writing.in b/doc/user/builders-writing.in deleted file mode 100644 index 749a8ba..0000000 --- a/doc/user/builders-writing.in +++ /dev/null @@ -1,1108 +0,0 @@ - - - - - - - Although &SCons; provides many useful methods - for building common software products - (programs, libraries, documents, etc.), - you frequently 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. - (In fact, the &SCons; interfaces for creating - &Builder; objects are flexible enough and easy enough to use - that all of the the &SCons; built-in &Builder; objects - are created using the mechanisms described in this section.) - - - -
- Writing Builders That Execute External Commands - - - - 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 - foobuild, - creating that &Builder; might look like: - - - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - - - - - All the above line does is create a free-standing - &Builder; object. - The next section will show us how to actually use it. - - - -
- -
- Attaching a Builder to a &ConsEnv; - - - - A &Builder; object 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 &cv-link-BUILDERS; - &consvar; in an environment. - The &cv-BUILDERS; variable is a Python dictionary - that maps the names by which you want to call - various &Builder; objects to the objects themselves. - For example, if we want to call the - &Builder; we just defined by the name - Foo, - our &SConstruct; file might look like: - - - - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env = Environment(BUILDERS = {'Foo' : bld}) - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - env.Foo('file.foo', 'file.input') - - - file.input - - - cat - - - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env = Environment(BUILDERS = {'Foo' : bld}) - - - - - With the &Builder; attached to our &consenv; - with the name Foo, - we can now actually call it like so: - - - - - env.Foo('file.foo', 'file.input') - - - - - Then when we run &SCons; it looks like: - - - - - scons -Q - - - - - Note, however, that the default &cv-BUILDERS; - variable in a &consenv; - comes with a default set of &Builder; objects - already defined: - &b-link-Program;, &b-link-Library;, etc. - And when we explicitly set the &cv-BUILDERS; variable - when we create the &consenv;, - the default &Builder;s are no longer part of - the environment: - - - - - - - import SCons.Defaults; SCons.Defaults.ConstructionEnvironment['TOOLS'] = {}; bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file.foo', 'file.input') - env.Program('hello.c') - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file.foo', 'file.input') - env.Program('hello.c') - - - file.input - - - hello.c - - - - - scons -Q - - - - - To be able to use both our own defined &Builder; objects - and the default &Builder; objects in the same &consenv;, - you can either add to the &cv-BUILDERS; variable - using the &Append; function: - - - - - - env = Environment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env.Append(BUILDERS = {'Foo' : bld}) - env.Foo('file.foo', 'file.input') - env.Program('hello.c') - - - file.input - - - hello.c - - - cat - - - - - env = Environment() - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env.Append(BUILDERS = {'Foo' : bld}) - env.Foo('file.foo', 'file.input') - env.Program('hello.c') - - - - - Or you can explicitly set the appropriately-named - key in the &cv-BUILDERS; dictionary: - - - - - env = Environment() - bld = Builder(action = 'foobuild < $SOURCE > $TARGET') - env['BUILDERS']['Foo'] = bld - env.Foo('file.foo', 'file.input') - env.Program('hello.c') - - - - - Either way, the same &consenv; - can then use both the newly-defined - Foo &Builder; - and the default &b-link-Program; &Builder;: - - - - - scons -Q - - -
- -
- Letting &SCons; Handle The File Suffixes - - - - 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 Foo - &Builder; to build the file.foo - target file from the file.input source file, - you can give the .foo - and .input suffixes to the &Builder;, - making for more compact and readable calls to - the Foo &Builder;: - - - - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET', - suffix = '.foo', - src_suffix = '.input') - env = Environment(BUILDERS = {'Foo' : bld}) - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - env.Foo('file1') - env.Foo('file2') - - - file1.input - - - file2.input - - - cat - - - - - bld = Builder(action = 'foobuild < $SOURCE > $TARGET', - suffix = '.foo', - src_suffix = '.input') - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file1') - env.Foo('file2') - - - - scons -Q - - - - - You can also supply a prefix keyword argument - if it's appropriate to have &SCons; append a prefix - to the beginning of target file names. - - - -
- -
- Builders That Execute Python Functions - - - - 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). - Such a &buildfunc; definition looks like: - - - - - def build_function(target, source, env): - # Code to build "target" from "source" - return None - - - - - The arguments of a &buildfunc; are: - - - - - - - target - - - - - A list of Node objects representing - the target or targets to be - built by this builder function. - The file names of these target(s) - may be extracted using the Python &str; function. - - - - - - - source - - - - - A list of Node objects representing - the sources to be - used by this builder function to build the targets. - The file names of these source(s) - may be extracted using the Python &str; function. - - - - - - - env - - - - - The &consenv; used for building the target(s). - The builder function may use any of the - environment's construction variables - in any way to affect how it builds the targets. - - - - - - - - - - The builder function must - return a 0 or None value - if the target(s) are built successfully. - The builder function - may raise an exception - or return any non-zero value - to indicate that the build is unsuccessful, - - - - - - 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 - action - argument: - - - - - - def build_function(target, source, env): - # Code to build "target" from "source" - return None - bld = Builder(action = build_function, - suffix = '.foo', - src_suffix = '.input') - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file') - - - file.input - - - - - - 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: - - - - - scons -Q - - -
- -
- Builders That Create Actions Using a &Generator; - - - - &SCons; Builder objects can create an action "on the fly" - by using a function called a &generator;. - This provides a great deal of flexibility to - construct just the right list of commands - to build your target. - A &generator; looks like: - - - - - def generate_actions(source, target, env, for_signature): - return 'foobuild < %s > %s' % (target[0], source[0]) - - - - - The arguments of a &generator; are: - - - - - - - source - - - - - A list of Node objects representing - the sources to be built - by the command or other action - generated by this function. - The file names of these source(s) - may be extracted using the Python &str; function. - - - - - - - - target - - - - - A list of Node objects representing - the target or targets to be built - by the command or other action - generated by this function. - The file names of these target(s) - may be extracted using the Python &str; function. - - - - - - - - env - - - - - The &consenv; used for building the target(s). - The generator may use any of the - environment's construction variables - in any way to determine what command - or other action to return. - - - - - - - - for_signature - - - - - A flag that specifies whether the - generator is being called to contribute to a build signature, - as opposed to actually executing the command. - - - - - - - - - - - - - The &generator; must return a - command string or other action that will be used to - build the specified target(s) from the specified source(s). - - - - - - Once you've defined a &generator;, - you create a &Builder; to use it - by specifying the generator keyword argument - instead of action. - - - - - - def generate_actions(source, target, env, for_signature): - return 'foobuild < %s > %s' % (source[0], target[0]) - bld = Builder(generator = generate_actions, - suffix = '.foo', - src_suffix = '.input') - env = Environment(BUILDERS = {'Foo' : bld}) - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - env.Foo('file') - - - file.input - - - cat - - - - - def generate_actions(source, target, env, for_signature): - return 'foobuild < %s > %s' % (source[0], target[0]) - bld = Builder(generator = generate_actions, - suffix = '.foo', - src_suffix = '.input') - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file') - - - - scons -Q - - - - - Note that it's illegal to specify both an - action - and a - generator - for a &Builder;. - - - -
- -
- Builders That Modify the Target or Source Lists Using an &Emitter; - - - - &SCons; supports the ability for a Builder to modify the - lists of target(s) from the specified source(s). - You do this by defining an &emitter; function - that takes as its arguments - the list of the targets passed to the builder, - the list of the sources passed to the builder, - and the construction environment. - The emitter function should return the modified - lists of targets that should be built - and sources from which the targets will be built. - - - - - - For example, suppose you want to define a Builder - that always calls a foobuild program, - and you want to automatically add - a new target file named - new_target - and a new source file named - new_source - whenever it's called. - The &SConstruct; file might look like this: - - - - - - def modify_targets(target, source, env): - target.append('new_target') - source.append('new_source') - return target, source - bld = Builder(action = 'foobuild $TARGETS - $SOURCES', - suffix = '.foo', - src_suffix = '.input', - emitter = modify_targets) - env = Environment(BUILDERS = {'Foo' : bld}) - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - env.Foo('file') - - - file.input - - - new_source - - - cat - - - - - def modify_targets(target, source, env): - target.append('new_target') - source.append('new_source') - return target, source - bld = Builder(action = 'foobuild $TARGETS - $SOURCES', - suffix = '.foo', - src_suffix = '.input', - emitter = modify_targets) - env = Environment(BUILDERS = {'Foo' : bld}) - env.Foo('file') - - - - - And would yield the following output: - - - - - scons -Q - - - - - One very flexible thing that you can do is - use a construction variable to specify - different emitter functions for different - construction variable. - To do this, specify a string - containing a construction variable - expansion as the emitter when you call - the &Builder; function, - and set that construction variable to - the desired emitter function - in different construction environments: - - - - - - - bld = Builder(action = 'my_command $SOURCES > $TARGET', - suffix = '.foo', - src_suffix = '.input', - emitter = '$MY_EMITTER') - def modify1(target, source, env): - return target, source + ['modify1.in'] - def modify2(target, source, env): - return target, source + ['modify2.in'] - env1 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify1) - env2 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify2) - env1.Foo('file1') - env2.Foo('file2') - import os - env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() - env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() - - - file1.input - - - file2.input - - - modify1.input - - - modify2.input - - - cat - - - - - - bld = Builder(action = 'my_command $SOURCES > $TARGET', - suffix = '.foo', - src_suffix = '.input', - emitter = '$MY_EMITTER') - def modify1(target, source, env): - return target, source + ['modify1.in'] - def modify2(target, source, env): - return target, source + ['modify2.in'] - env1 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify1) - env2 = Environment(BUILDERS = {'Foo' : bld}, - MY_EMITTER = modify2) - env1.Foo('file1') - env2.Foo('file2') - - - - - In this example, the modify1.in - and modify2.in files - get added to the source lists - of the different commands: - - - - - scons -Q - - -
- - - -
- Where To Put Your Custom Builders and Tools - - - - The site_scons directories give you a place to - put Python modules and packages that you can import into your &SConscript; files - (site_scons), - add-on tools that can integrate into &SCons; - (site_scons/site_tools), - and a site_scons/site_init.py file that - gets read before any &SConstruct; or &SConscript; file, - allowing you to change &SCons;'s default behavior. - - - - - - Each system type (Windows, Mac, Linux, etc.) searches a canonical - set of directories for site_scons; see the man page for details. - The top-level SConstruct's site_scons dir is always searched last, - and its dir is placed first in the tool path so it overrides all - others. - - - - - - If you get a tool from somewhere (the &SCons; wiki or a third party, - for instance) and you'd like to use it in your project, a - site_scons dir is the simplest place to put it. - Tools come in two flavors; either a Python function that operates on - an &Environment; or a Python module or package containing two functions, - exists() and generate(). - - - - - - A single-function Tool can just be included in your - site_scons/site_init.py file where it will be - parsed and made available for use. For instance, you could have a - site_scons/site_init.py file like this: - - - - - - def TOOL_ADD_HEADER(env): - """A Tool to add a header from $HEADER to the source file""" - add_header = Builder(action=['echo "$HEADER" > $TARGET', - 'cat $SOURCE >> $TARGET']) - env.Append(BUILDERS = {'AddHeader' : add_header}) - env['HEADER'] = '' # set default value - - - env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") - env.AddHeader('tgt', 'src') - - - hi there - - - - - - and a &SConstruct; like this: - - - - - # Use TOOL_ADD_HEADER from site_scons/site_init.py - env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") - env.AddHeader('tgt', 'src') - - - - - The TOOL_ADD_HEADER tool method will be - called to add the AddHeader tool to the - environment. - - - - - - - A more full-fledged tool with - exists() and generate() - methods can be installed either as a module in the file - site_scons/site_tools/toolname.py or as a - package in the - directory site_scons/site_tools/toolname. In - the case of using a package, the exists() - and generate() are in the - file site_scons/site_tools/toolname/__init__.py. - (In all the above case toolname is replaced - by the name of the tool.) - Since site_scons/site_tools is automatically - added to the head of the tool search path, any tool found there - will be available to all environments. Furthermore, a tool found - there will override a built-in tool of the same name, so if you - need to change the behavior of a built-in - tool, site_scons gives you the hook you need. - - - - Many people have a library of utility Python functions they'd like - to include in &SConscript;s; just put that module in - site_scons/my_utils.py or any valid Python module name of your - choice. For instance you can do something like this in - site_scons/my_utils.py to add - build_id and MakeWorkDir - functions: - - - - - from SCons.Script import * # for Execute and Mkdir - def build_id(): - """Return a build ID (stub version)""" - return "100" - def MakeWorkDir(workdir): - """Create the specified dir immediately""" - Execute(Mkdir(workdir)) - - - import my_utils - MakeWorkDir('/tmp/work') - print "build_id=" + my_utils.build_id() - - - - - - And then in your &SConscript; or any sub-&SConscript; anywhere in - your build, you can import my_utils and use it: - - - - - import my_utils - print "build_id=" + my_utils.build_id() - my_utils.MakeWorkDir('/tmp/work') - - - - Note that although you can put this library in - site_scons/site_init.py, - it is no better there than site_scons/my_utils.py - since you still have to import that module into your &SConscript;. - Also note that in order to refer to objects in the SCons namespace - such as &Environment; or &Mkdir; or &Execute; in any file other - than a &SConstruct; or &SConscript; you always need to do - - - from SCons.Script import * - - - - This is true in modules in site_scons such as - site_scons/site_init.py as well. - - - - - You can use any of the user- or machine-wide site dirs such as - ~/.scons/site_scons instead of - ./site_scons, or use the - --site-dir option to point to your own dir. - site_init.py and - site_tools will be located under that dir. - To avoid using a site_scons dir at all, - even if it exists, use the --no-site-dir - option. - - - -
- - - diff --git a/doc/user/builders-writing.xml b/doc/user/builders-writing.xml index f42a61f..749a8ba 100644 --- a/doc/user/builders-writing.xml +++ b/doc/user/builders-writing.xml @@ -129,7 +129,7 @@ This functionality could be invoked as in the following example:
- bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') @@ -163,12 +163,26 @@ This functionality could be invoked as in the following example: - + + + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file.foo', 'file.input') + + + file.input + + + cat + + - + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') env = Environment(BUILDERS = {'Foo' : bld}) - + @@ -188,10 +202,9 @@ This functionality could be invoked as in the following example: - - % scons -Q - foobuild < file.input > file.foo - + + scons -Q + @@ -224,19 +237,30 @@ This functionality could be invoked as in the following example: in the generated error consistent with what the user will see in the User's Guide. --> - + + + import SCons.Defaults; SCons.Defaults.ConstructionEnvironment['TOOLS'] = {}; bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env = Environment(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') env = Environment(BUILDERS = {'Foo' : bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') - + + + file.input + + + hello.c + + - - % scons -Q - AttributeError: 'SConsEnvironment' object has no attribute 'Program': - File "/home/my/project/SConstruct", line 4: - env.Program('hello.c') - + + scons -Q + @@ -247,15 +271,34 @@ This functionality could be invoked as in the following example: - + + + env = Environment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + bld = Builder(action = 'foobuild < $SOURCE > $TARGET') + env.Append(BUILDERS = {'Foo' : bld}) + env.Foo('file.foo', 'file.input') + env.Program('hello.c') + + + file.input + + + hello.c + + + cat + + - + env = Environment() bld = Builder(action = 'foobuild < $SOURCE > $TARGET') env.Append(BUILDERS = {'Foo' : bld}) env.Foo('file.foo', 'file.input') env.Program('hello.c') - + @@ -264,13 +307,13 @@ This functionality could be invoked as in the following example: - + env = Environment() bld = Builder(action = 'foobuild < $SOURCE > $TARGET') env['BUILDERS']['Foo'] = bld env.Foo('file.foo', 'file.input') env.Program('hello.c') - + @@ -281,12 +324,9 @@ This functionality could be invoked as in the following example: - - % scons -Q - foobuild < file.input > file.foo - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -310,22 +350,40 @@ This functionality could be invoked as in the following example: - + + + bld = Builder(action = 'foobuild < $SOURCE > $TARGET', + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file1') + env.Foo('file2') + + + file1.input + + + file2.input + + + cat + + - + bld = Builder(action = 'foobuild < $SOURCE > $TARGET', suffix = '.foo', src_suffix = '.input') env = Environment(BUILDERS = {'Foo' : bld}) env.Foo('file1') env.Foo('file2') - + - - % scons -Q - foobuild < file1.input > file1.foo - foobuild < file2.input > file2.foo - + + scons -Q + @@ -439,7 +497,8 @@ This functionality could be invoked as in the following example: - + + def build_function(target, source, env): # Code to build "target" from "source" return None @@ -448,7 +507,11 @@ This functionality could be invoked as in the following example: src_suffix = '.input') env = Environment(BUILDERS = {'Foo' : bld}) env.Foo('file') - + + + file.input + + @@ -459,10 +522,9 @@ This functionality could be invoked as in the following example: - - % scons -Q - build_function(["file.foo"], ["file.input"]) - + + scons -Q + @@ -482,7 +544,7 @@ This functionality could be invoked as in the following example: def generate_actions(source, target, env, for_signature): - return 'foobuild < %s > %s' % (target[0], source[0]) + return 'foobuild < %s > %s' % (target[0], source[0]) @@ -582,9 +644,27 @@ This functionality could be invoked as in the following example: - + + + def generate_actions(source, target, env, for_signature): + return 'foobuild < %s > %s' % (source[0], target[0]) + bld = Builder(generator = generate_actions, + suffix = '.foo', + src_suffix = '.input') + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file') + + + file.input + + + cat + + - + def generate_actions(source, target, env, for_signature): return 'foobuild < %s > %s' % (source[0], target[0]) bld = Builder(generator = generate_actions, @@ -592,12 +672,11 @@ This functionality could be invoked as in the following example: src_suffix = '.input') env = Environment(BUILDERS = {'Foo' : bld}) env.Foo('file') - + - - % scons -Q - foobuild < file.input > file.foo - + + scons -Q + @@ -643,9 +722,33 @@ This functionality could be invoked as in the following example: - + + + def modify_targets(target, source, env): + target.append('new_target') + source.append('new_source') + return target, source + bld = Builder(action = 'foobuild $TARGETS - $SOURCES', + suffix = '.foo', + src_suffix = '.input', + emitter = modify_targets) + env = Environment(BUILDERS = {'Foo' : bld}) + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + env.Foo('file') + + + file.input + + + new_source + + + cat + + - + def modify_targets(target, source, env): target.append('new_target') source.append('new_source') @@ -656,7 +759,7 @@ This functionality could be invoked as in the following example: emitter = modify_targets) env = Environment(BUILDERS = {'Foo' : bld}) env.Foo('file') - + @@ -664,10 +767,9 @@ This functionality could be invoked as in the following example: - - % scons -Q - foobuild file.foo new_target - file.input new_source - + + scons -Q + @@ -685,7 +787,9 @@ This functionality could be invoked as in the following example: - + + + bld = Builder(action = 'my_command $SOURCES > $TARGET', suffix = '.foo', src_suffix = '.input', @@ -703,10 +807,26 @@ This functionality could be invoked as in the following example: import os env1['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() env2['ENV']['PATH'] = env2['ENV']['PATH'] + os.pathsep + os.getcwd() + + + file1.input + + + file2.input + + + modify1.input + + + modify2.input + + + cat + - + - + bld = Builder(action = 'my_command $SOURCES > $TARGET', suffix = '.foo', src_suffix = '.input', @@ -721,7 +841,7 @@ This functionality could be invoked as in the following example: MY_EMITTER = modify2) env1.Foo('file1') env2.Foo('file2') - + @@ -732,11 +852,9 @@ This functionality could be invoked as in the following example: - - % scons -Q - my_command file1.input modify1.in > file1.foo - my_command file2.input modify2.in > file2.foo - + + scons -Q + @@ -820,14 +938,23 @@ This functionality could be invoked as in the following example: - + + def TOOL_ADD_HEADER(env): """A Tool to add a header from $HEADER to the source file""" add_header = Builder(action=['echo "$HEADER" > $TARGET', 'cat $SOURCE >> $TARGET']) env.Append(BUILDERS = {'AddHeader' : add_header}) env['HEADER'] = '' # set default value - + + + env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") + env.AddHeader('tgt', 'src') + + + hi there + + @@ -835,11 +962,11 @@ This functionality could be invoked as in the following example: - + # Use TOOL_ADD_HEADER from site_scons/site_init.py env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====") env.AddHeader('tgt', 'src') - + @@ -885,7 +1012,8 @@ This functionality could be invoked as in the following example: functions: - + + from SCons.Script import * # for Execute and Mkdir def build_id(): """Return a build ID (stub version)""" @@ -893,7 +1021,13 @@ This functionality could be invoked as in the following example: def MakeWorkDir(workdir): """Create the specified dir immediately""" Execute(Mkdir(workdir)) - + + + import my_utils + MakeWorkDir('/tmp/work') + print "build_id=" + my_utils.build_id() + + @@ -902,11 +1036,11 @@ This functionality could be invoked as in the following example: - + import my_utils print "build_id=" + my_utils.build_id() my_utils.MakeWorkDir('/tmp/work') - + Note that although you can put this library in @@ -917,9 +1051,9 @@ This functionality could be invoked as in the following example: such as &Environment; or &Mkdir; or &Execute; in any file other than a &SConstruct; or &SConscript; you always need to do - + from SCons.Script import * - + This is true in modules in site_scons such as diff --git a/doc/user/builders.in b/doc/user/builders.in deleted file mode 100644 index f3989ef..0000000 --- a/doc/user/builders.in +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - -This appendix contains descriptions of all of the -Builders that are potentially -available "out of the box" in this version of SCons. - - - - - -&builders-gen; - - diff --git a/doc/user/caching.in b/doc/user/caching.in deleted file mode 100644 index cb8521b..0000000 --- a/doc/user/caching.in +++ /dev/null @@ -1,502 +0,0 @@ - - - - - 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. - - - -
- Specifying the Shared Cache Directory - - - - To enable sharing of derived files, - use the &CacheDir; function - in any &SConscript; file: - - - - - - env = Environment() - env.Program('hello.c') - CacheDir('cache') - - - hello.c - - - - - CacheDir('/usr/local/build_cache') - - - - - - 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. - - - - - - 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. - - - Actually, the MD5 signature is used as the name of the file - in the shared cache directory in which the contents are stored. - - - 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: - - - - - scons -Q - scons -Q -c - scons -Q - - - - - Note that the &CacheDir; feature still calculates - MD5 build sigantures for the shared cache file names - even if you configure &SCons; to use timestamps - to decide if files are up to date. - (See the - chapter for information about the &Decider; function.) - Consequently, using &CacheDir; may reduce or eliminate any - potential performance improvements - from using timestamps for up-to-date decisions. - - - -
- -
- Keeping Build Output Consistent - - - - One potential drawback to using a shared cache - is that the output printed by &SCons; - 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. - - - - - - If, however, you use the --cache-show option, - &SCons; will print the command line that it - would 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: - - - - - scons -Q - scons -Q -c - scons -Q --cache-show - - - - - 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. - - - -
- -
- Not Using the Shared Cache for Specific Files - - - - You may want to disable caching for certain - specific files in your configuration. - For example, if you only want to put - executable files in a central cache, - but not the intermediate object files, - you can use the &NoCache; - function to specify that the - object files should not be cached: - - - - - - env = Environment() - obj = env.Object('hello.c') - env.Program('hello.c') - CacheDir('cache') - NoCache('hello.o') - - - hello.c - - - - - - - - Then when you run &scons; after cleaning - the built targets, - it will recompile the object file locally - (since it doesn't exist in the shared cache directory), - but still realize that the shared cache directory - contains an up-to-date executable program - that can be retrieved instead of re-linking: - - - - - - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q - cc -o hello.o -c hello.c - Retrieved `hello' from cache - - -
- -
- Disabling the Shared Cache - - - - 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. - - - - - - In these cases, you can specify - the --cache-disable - command-line option to tell &SCons; - to not retrieve already-built files from the - shared cache directory: - - - - - scons -Q - scons -Q -c - scons -Q - scons -Q -c - scons -Q --cache-disable - - -
- -
- Populating a Shared Cache With Already-Built Files - - - - 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. - - - - - - In this case, you can use the - the --cache-force option - to tell &SCons; to put all derived files in the cache, - even if the files already exist in your local tree - from having been built by a previous invocation: - - - - - scons -Q --cache-disable - scons -Q -c - scons -Q --cache-disable - scons -Q --cache-force - scons -Q - - - - - Notice how the above sample run - demonstrates that the --cache-disable - option avoids putting the built - hello.o - and - hello files in the cache, - but after using the --cache-force option, - the files have been put in the cache - for the next invocation to retrieve. - - - -
- -
- Minimizing Cache Contention: the <literal>--random</literal> Option - - - - If you allow multiple builds to update the - shared cache directory simultaneously, - two builds that occur at the same time - can sometimes start "racing" - with one another to build the same files - in the same order. - If, for example, - you are linking multiple files into an executable program: - - - - - - Program('prog', - ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) - - f1.c - f2.c - f3.c - f4.c - f5.c - f6.c - - - - - &SCons; will normally build the input object files - on which the program depends in their normal, sorted order: - - - - - scons -Q - - - - - But if two such builds take place simultaneously, - they may each look in the cache at nearly the same - time and both decide that f1.o - must be rebuilt and pushed into the shared cache directory, - then both decide that f2.o - must be rebuilt (and pushed into the shared cache directory), - then both decide that f3.o - must be rebuilt... - This won't cause any actual build problems--both - builds will succeed, - generate correct output files, - and populate the cache--but - it does represent wasted effort. - - - - - - To alleviate such contention for the cache, - you can use the --random command-line option - to tell &SCons; to build dependencies - in a random order: - - - - - - - % scons -Q --random - cc -o f3.o -c f3.c - cc -o f1.o -c f1.c - cc -o f5.o -c f5.c - cc -o f2.o -c f2.c - cc -o f4.o -c f4.c - cc -o prog f1.o f2.o f3.o f4.o f5.o - - - - - Multiple builds using the --random option - will usually build their dependencies in different, - random orders, - which minimizes the chances for a lot of - contention for same-named files - in the shared cache directory. - Multiple simultaneous builds might still race to try to build - the same target file on occasion, - but long sequences of inefficient contention - should be rare. - - - - - - Note, of course, - the --random option - will cause the output that &SCons; prints - to be inconsistent from invocation to invocation, - which may be an issue when - trying to compare output from different build runs. - - - - - - If you want to make sure dependencies will be built - in a random order without having to specify - the --random on very command line, - you can use the &SetOption; function to - set the random option - within any &SConscript; file: - - - - - - SetOption('random', 1) - Program('prog', - ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) - - f1.c - f2.c - f3.c - f4.c - f5.c - f6.c - - -
- - - - diff --git a/doc/user/caching.xml b/doc/user/caching.xml index 2348d32..cb8521b 100644 --- a/doc/user/caching.xml +++ b/doc/user/caching.xml @@ -43,9 +43,21 @@
- + + + env = Environment() + env.Program('hello.c') + CacheDir('cache') + + + hello.c + + + + CacheDir('/usr/local/build_cache') - + + @@ -86,17 +98,11 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q - Retrieved `hello.o' from cache - Retrieved `hello' from cache - + + scons -Q + scons -Q -c + scons -Q + @@ -142,17 +148,11 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q --cache-show - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + scons -Q -c + scons -Q --cache-show + @@ -181,13 +181,20 @@ - + + env = Environment() obj = env.Object('hello.c') env.Program('hello.c') CacheDir('cache') NoCache('hello.o') - + + + hello.c + + + + @@ -255,23 +262,13 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q - Retrieved `hello.o' from cache - Retrieved `hello' from cache - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q --cache-disable - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + scons -Q -c + scons -Q + scons -Q -c + scons -Q --cache-disable + @@ -306,21 +303,13 @@ - - % scons -Q --cache-disable - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q -c - Removed hello.o - Removed hello - % scons -Q --cache-disable - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q --cache-force - scons: `.' is up to date. - % scons -Q - scons: `.' is up to date. - + + scons -Q --cache-disable + scons -Q -c + scons -Q --cache-disable + scons -Q --cache-force + scons -Q + @@ -354,10 +343,18 @@ - + + Program('prog', ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) - + + f1.c + f2.c + f3.c + f4.c + f5.c + f6.c + @@ -366,15 +363,9 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f2.o -c f2.c - cc -o f3.o -c f3.c - cc -o f4.o -c f4.c - cc -o f5.o -c f5.c - cc -o prog f1.o f2.o f3.o f4.o f5.o - + + scons -Q + @@ -464,14 +455,19 @@ - - Program('prog', - ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) - + + SetOption('random', 1) Program('prog', ['f1.c', 'f2.c', 'f3.c', 'f4.c', 'f5.c']) - + + f1.c + f2.c + f3.c + f4.c + f5.c + f6.c + diff --git a/doc/user/command-line.in b/doc/user/command-line.in deleted file mode 100644 index 33f88ec..0000000 --- a/doc/user/command-line.in +++ /dev/null @@ -1,2345 +0,0 @@ - - - - - &SCons; provides a number of ways - for the writer of the &SConscript; files - to give the users who will run &SCons; - a great deal of control over the build execution. - The arguments that the user can specify on - the command line are broken down into three types: - - - - - - - Options - - - - - Command-line options always begin with - one or two - (hyphen) characters. - &SCons; provides ways for you to examine - and set options values from within your &SConscript; files, - as well as the ability to define your own - custom options. - See , below. - - - - - - - Variables - - - - - Any command-line argument containing an = - (equal sign) is considered a variable setting with the form - variable=value. - &SCons; provides direct access to - all of the command-line variable settings, - the ability to apply command-line variable settings - to construction environments, - and functions for configuring - specific types of variables - (Boolean values, path names, etc.) - with automatic validation of the user's specified values. - See , below. - - - - - - - Targets - - - - - Any command-line argument that is not an option - or a variable setting - (does not begin with a hyphen - and does not contain an equal sign) - is considered a target that the user - (presumably) wants &SCons; to build. - A list of Node objects representing - the target or targets to build. - &SCons; provides access to the list of specified targets, - as well as ways to set the default list of targets - from within the &SConscript; files. - See , below. - - - - - - - -
- Command-Line Options - - - - &SCons; has many command-line options - that control its behavior. - A &SCons; command-line option - always begins with one or two - (hyphen) - characters. - - - -
- Not Having to Specify Command-Line Options Each Time: the &SCONSFLAGS; Environment Variable - - - - Users may find themselves supplying - the same command-line options every time - they run &SCons;. - For example, you might find it saves time - to specify a value of -j 2 - to have &SCons; run up to two build commands in parallel. - To avoid having to type -j 2 by hand - every time, - you can set the external environment variable - &SCONSFLAGS; to a string containing - command-line options that you want &SCons; to use. - - - - - - If, for example, - you're using a POSIX shell that's - compatible with the Bourne shell, - and you always want &SCons; to use the - -Q option, - you can set the &SCONSFLAGS; - environment as follows: - - - - - - def b(target, source, env): - pass - def s(target, source, env): - return " ... [build output] ..." - a = Action(b, strfunction = s) - env = Environment(BUILDERS = {'A' : Builder(action=a)}) - env.A('foo.out', 'foo.in') - - - foo.in - - - - - scons - export SCONSFLAGS="-Q" - scons - - - - - Users of &csh;-style shells on POSIX systems - can set the &SCONSFLAGS; environment as follows: - - - - - $ setenv SCONSFLAGS "-Q" - - - - - Windows users may typically want to set the - &SCONSFLAGS; in the appropriate tab of the - System Properties window. - - - -
- -
- Getting Values Set by Command-Line Options: the &GetOption; Function - - - - &SCons; provides the &GetOption; function - to get the values set by the various command-line options. - One common use of this is to check whether or not - the -h or --help option - has been specified. - Normally, &SCons; does not print its help text - until after it has read all of the &SConscript; files, - because it's possible that help text has been added - by some subsidiary &SConscript; file deep in the - source tree hierarchy. - Of course, reading all of the &SConscript; files - takes extra time. - - - - - - If you know that your configuration does not define - any additional help text in subsidiary &SConscript; files, - you can speed up the command-line help available to users - by using the &GetOption; function to load the - subsidiary &SConscript; files only if the - the user has not specified - the -h or --help option, - like so: - - - - - if not GetOption('help'): - SConscript('src/SConscript', export='env') - - - - - In general, the string that you pass to the - &GetOption; function to fetch the value of a command-line - option setting is the same as the "most common" long option name - (beginning with two hyphen characters), - although there are some exceptions. - The list of &SCons; command-line options - and the &GetOption; strings for fetching them, - are available in the - section, - below. - - - -
- -
- Setting Values of Command-Line Options: the &SetOption; Function - - - - You can also set the values of &SCons; - command-line options from within the &SConscript; files - by using the &SetOption; function. - The strings that you use to set the values of &SCons; - command-line options are available in the - section, - below. - - - - - - One use of the &SetOption; function is to - specify a value for the -j - or --jobs option, - so that users get the improved performance - of a parallel build without having to specify the option by hand. - A complicating factor is that a good value - for the -j option is - somewhat system-dependent. - One rough guideline is that the more processors - your system has, - the higher you want to set the - -j value, - in order to take advantage of the number of CPUs. - - - - - - For example, suppose the administrators - of your development systems - have standardized on setting a - NUM_CPU environment variable - to the number of processors on each system. - A little bit of Python code - to access the environment variable - and the &SetOption; function - provide the right level of flexibility: - - - - - - import os - num_cpu = int(os.environ.get('NUM_CPU', 2)) - SetOption('num_jobs', num_cpu) - print "running with -j", GetOption('num_jobs') - - - foo.in - - - - - - The above snippet of code - sets the value of the --jobs option - to the value specified in the - $NUM_CPU environment variable. - (This is one of the exception cases - where the string is spelled differently from - the from command-line option. - The string for fetching or setting the --jobs - value is num_jobs - for historical reasons.) - The code in this example prints the num_jobs - value for illustrative purposes. - It uses a default value of 2 - to provide some minimal parallelism even on - single-processor systems: - - - - - scons -Q - - - - - But if the $NUM_CPU - environment variable is set, - then we use that for the default number of jobs: - - - - - export NUM_CPU="4" - scons -Q - - - - - But any explicit - -j or --jobs - value the user specifies an the command line is used first, - regardless of whether or not - the $NUM_CPU environment - variable is set: - - - - - scons -Q -j 7 - export NUM_CPU="4" - scons -Q -j 3 - - -
- -
- Strings for Getting or Setting Values of &SCons; Command-Line Options - - - - The strings that you can pass to the &GetOption; - and &SetOption; functions usually correspond to the - first long-form option name - (beginning with two hyphen characters: --), - after replacing any remaining hyphen characters - with underscores. - - - - - - The full list of strings and the variables they - correspond to is as follows: - - - - - - - - - - String for &GetOption; and &SetOption; - Command-Line Option(s) - - - - - - - - cache_debug - - - - - cache_disable - - - - - cache_force - - - - - cache_show - - - - - clean - , - , - - - - - config - - - - - directory - , - - - - - diskcheck - - - - - duplicate - - - - - file - , - , - , - - - - - help - , - - - - - ignore_errors - - - - - implicit_cache - - - - - implicit_deps_changed - - - - - implicit_deps_unchanged - - - - - interactive - , - - - - - keep_going - , - - - - - max_drift - - - - - no_exec - , - , - , - , - - - - - no_site_dir - - - - - num_jobs - , - - - - - profile_file - - - - - question - , - - - - - random - - - - - repository - , - , - - - - - silent - , - , - - - - - site_dir - - - - - stack_size - - - - - taskmastertrace_file - - - - - warn - - - - - - - - -
- -
- Adding Custom Command-Line Options: the &AddOption; Function - - - - &SCons; also allows you to define your own - command-line options with the &AddOption; function. - The &AddOption; function takes the same arguments - as the optparse.add_option function - from the standard Python library. - - - The &AddOption; function is, - in fact, implemented using a subclass - of the optparse.OptionParser. - - - Once you have added a custom command-line option - with the &AddOption; function, - the value of the option (if any) is immediately available - using the standard &GetOption; function. - (The value can also be set using &SetOption;, - although that's not very useful in practice - because a default value can be specified in - directly in the &AddOption; call.) - - - - - - One useful example of using this functionality - is to provide a for users: - - - - - - AddOption('--prefix', - dest='prefix', - type='string', - nargs=1, - action='store', - metavar='DIR', - help='installation prefix') - - env = Environment(PREFIX = GetOption('prefix')) - - installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in') - Default(installed_foo) - - - foo.in - - - - - - The above code uses the &GetOption; function - to set the $PREFIX - construction variable to any - value that the user specifies with a command-line - option of --prefix. - Because $PREFIX - will expand to a null string if it's not initialized, - running &SCons; without the - option of --prefix - will install the file in the - /usr/bin/ directory: - - - - - scons -Q -n - - - - - But specifying --prefix=/tmp/install - on the command line causes the file to be installed in the - /tmp/install/usr/bin/ directory: - - - - - scons -Q -n --prefix=/tmp/install - - -
- -
- -
- Command-Line <varname>variable</varname>=<varname>value</varname> Build Variables - - - - You may want to control various aspects - of your build by allowing the user - to specify variable=value - values on the command line. - For example, suppose you - want users to be able to - build a debug version of a program - by running &SCons; as follows: - - - - - % scons -Q debug=1 - - - - - &SCons; provides an &ARGUMENTS; dictionary - that stores all of the - variable=value - assignments from the command line. - This allows you to modify - aspects of your build in response - to specifications on the command line. - (Note that unless you want to require - that users always - specify a variable, - you probably want to use - the Python - ARGUMENTS.get() function, - which allows you to specify a default value - to be used if there is no specification - on the command line.) - - - - - - The following code sets the &cv-link-CCFLAGS; construction - variable in response to the debug - flag being set in the &ARGUMENTS; dictionary: - - - - - - env = Environment() - debug = ARGUMENTS.get('debug', 0) - if int(debug): - env.Append(CCFLAGS = '-g') - env.Program('prog.c') - - - prog.c - - - - - - This results in the -g - compiler option being used when - debug=1 - is used on the command line: - - - - - scons -Q debug=0 - scons -Q debug=0 - scons -Q debug=1 - scons -Q debug=1 - - - - - Notice that &SCons; keeps track of - the last values used to build the object files, - and as a result correctly rebuilds - the object and executable files - only when the value of the debug - argument has changed. - - - - - - The &ARGUMENTS; dictionary has two minor drawbacks. - First, because it is a dictionary, - it can only store one value for each specified keyword, - and thus only "remembers" the last setting - for each keyword on the command line. - This makes the &ARGUMENTS; dictionary - inappropriate if users should be able to - specify multiple values - on the command line for a given keyword. - Second, it does not preserve - the order in which the variable settings - were specified, - which is a problem if - you want the configuration to - behave differently in response - to the order in which the build - variable settings were specified on the command line. - - - - - - To accomodate these requirements, - &SCons; provides an &ARGLIST; variable - that gives you direct access to - variable=value - settings on the command line, - in the exact order they were specified, - and without removing any duplicate settings. - Each element in the &ARGLIST; variable - is itself a two-element list - containing the keyword and the value - of the setting, - and you must loop through, - or otherwise select from, - the elements of &ARGLIST; to - process the specific settings you want - in whatever way is appropriate for your configuration. - For example, - the following code to let the user - add to the &CPPDEFINES; construction variable - by specifying multiple - define= - settings on the command line: - - - - - - cppdefines = [] - for key, value in ARGLIST: - if key == 'define': - cppdefines.append(value) - env = Environment(CPPDEFINES = cppdefines) - env.Object('prog.c') - - - prog.c - - - - - - Yields the following output: - - - - - scons -Q define=FOO - scons -Q define=FOO define=BAR - - - - - Note that the &ARGLIST; and &ARGUMENTS; - variables do not interfere with each other, - but merely provide slightly different views - into how the user specified - variable=value - settings on the command line. - You can use both variables in the same - &SCons; configuration. - In general, the &ARGUMENTS; dictionary - is more convenient to use, - (since you can just fetch variable - settings through a dictionary access), - and the &ARGLIST; list - is more flexible - (since you can examine the - specific order in which - the user's command-line variabe settings). - - - -
- Controlling Command-Line Build Variables - - - - Being able to use a command-line build variable like - debug=1 is handy, - but it can be a chore to write specific Python code - to recognize each such variable, - check for errors and provide appropriate messages, - and apply the values to a construction variable. - To help with this, - &SCons; supports a class to - define such build variables easily, - and a mechanism to apply the - build variables to a construction environment. - This allows you to control how the build variables affect - construction environments. - - - - - - For example, suppose that you want users to set - a &RELEASE; construction variable on the - command line whenever the time comes to build - a program for release, - and that the value of this variable - should be added to the command line - with the appropriate -D option - (or other command line option) - to pass the value to the C compiler. - Here's how you might do that by setting - the appropriate value in a dictionary for the - &cv-link-CPPDEFINES; construction variable: - - - - - - vars = Variables(None, ARGUMENTS) - vars.Add('RELEASE', 'Set to 1 to build for release', 0) - env = Environment(variables = vars, - CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) - env.Program(['foo.c', 'bar.c']) - - - foo.c - - - bar.c - - - - - - This &SConstruct; file first creates a &Variables; object - which uses the values from the command-line options dictionary &ARGUMENTS; - (the vars = Variables(None, ARGUMENTS) call). - It then uses the object's &Add; - method to indicate that the &RELEASE; - variable can be set on the command line, - and that its default value will be 0 - (the third argument to the &Add; method). - The second argument is a line of help text; - we'll learn how to use it in the next section. - - - - - - We then pass the created &Variables; - object as a &variables; keyword argument - to the &Environment; call - used to create the construction environment. - This then allows a user to set the - &RELEASE; build variable on the command line - and have the variable show up in - the command line used to build each object from - a C source file: - - - - - scons -Q RELEASE=1 - - - - - NOTE: Before &SCons; release 0.98.1, these build variables - were known as "command-line build options." - The class was actually named the &Options; class, - and in the sections below, - the various functions were named - &BoolOption;, &EnumOption;, &ListOption;, - &PathOption;, &PackageOption; and &AddOptions;. - These older names still work, - and you may encounter them in older - &SConscript; files, - but they have been officially deprecated - as of &SCons; version 2.0. - - - -
- -
- Providing Help for Command-Line Build Variables - - - - To make command-line build variables most useful, - you ideally want to provide - some help text that will describe - the available variables - when the user runs scons -h. - You could write this text by hand, - but &SCons; provides an easier way. - &Variables; objects support a - &GenerateHelpText; method - that will, as its name suggests, - generate text that describes - the various variables that - have been added to it. - You then pass the output from this method to - the &Help; function: - - - - - - vars = Variables(None, ARGUMENTS) - vars.Add('RELEASE', 'Set to 1 to build for release', 0) - env = Environment(variables = vars) - Help(vars.GenerateHelpText(env)) - - - - - - &SCons; will now display some useful text - when the -h option is used: - - - - - scons -Q -h - - - - - Notice that the help output shows the default value, - and the current actual value of the build variable. - - - -
- -
- Reading Build Variables From a File - - - - Giving the user a way to specify the - value of a build variable on the command line - is useful, - but can still be tedious - if users must specify the variable - every time they run &SCons;. - We can let users provide customized build variable settings - in a local file by providing a - file name when we create the - &Variables; object: - - - - - - vars = Variables('custom.py') - vars.Add('RELEASE', 'Set to 1 to build for release', 0) - env = Environment(variables = vars, - CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) - env.Program(['foo.c', 'bar.c']) - Help(vars.GenerateHelpText(env)) - - - foo.c - - - bar.c - - - RELEASE = 1 - - - - - - This then allows the user to control the &RELEASE; - variable by setting it in the &custom_py; file: - - - - - - - - Note that this file is actually executed - like a Python script. - Now when we run &SCons;: - - - - - scons -Q - - - - - And if we change the contents of &custom_py; to: - - - - - - vars = Variables('custom.py') - vars.Add('RELEASE', 'Set to 1 to build for release', 0) - env = Environment(variables = vars, - CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) - env.Program(['foo.c', 'bar.c']) - Help(vars.GenerateHelpText(env)) - - - foo.c - - - bar.c - - - RELEASE = 0 - - - - - - The object files are rebuilt appropriately - with the new variable: - - - - - scons -Q - - - - - Finally, you can combine both methods with: - - - - - vars = Variables('custom.py', ARGUMENTS) - - - - - where values in the option file &custom_py; get overwritten - by the ones specified on the command line. - - - -
- -
- Pre-Defined Build Variable Functions - - - - &SCons; provides a number of functions - that provide ready-made behaviors - for various types of command-line build variables. - - - -
- True/False Values: the &BoolVariable; Build Variable Function - - - - It's often handy to be able to specify a - variable that controls a simple Boolean variable - with a &true; or &false; value. - It would be even more handy to accomodate - users who have different preferences for how to represent - &true; or &false; values. - The &BoolVariable; function - makes it easy to accomodate these - common representations of - &true; or &false;. - - - - - - The &BoolVariable; function takes three arguments: - the name of the build variable, - the default value of the build variable, - and the help string for the variable. - It then returns appropriate information for - passing to the &Add; method of a &Variables; object, like so: - - - - - - vars = Variables('custom.py') - vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0)) - env = Environment(variables = vars, - CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) - env.Program('foo.c') - - - foo.c - - - - - - With this build variable, - the &RELEASE; variable can now be enabled by - setting it to the value yes - or t: - - - - - scons -Q RELEASE=yes foo.o - - - - scons -Q RELEASE=t foo.o - - - - - Other values that equate to &true; include - y, - 1, - on - and - all. - - - - - - Conversely, &RELEASE; may now be given a &false; - value by setting it to - no - or - f: - - - - - scons -Q RELEASE=no foo.o - - - - scons -Q RELEASE=f foo.o - - - - - Other values that equate to &false; include - n, - 0, - off - and - none. - - - - - - Lastly, if a user tries to specify - any other value, - &SCons; supplies an appropriate error message: - - - - - scons -Q RELEASE=bad_value foo.o - - -
- -
- Single Value From a List: the &EnumVariable; Build Variable Function - - - - Suppose that we want a user to be able to - set a &COLOR; variable - that selects a background color to be - displayed by an application, - but that we want to restrict the - choices to a specific set of allowed colors. - This can be set up quite easily - using the &EnumVariable;, - which takes a list of &allowed_values; - in addition to the variable name, - default value, - and help text arguments: - - - - - - vars = Variables('custom.py') - vars.Add(EnumVariable('COLOR', 'Set background color', 'red', - allowed_values=('red', 'green', 'blue'))) - env = Environment(variables = vars, - CPPDEFINES={'COLOR' : '"${COLOR}"'}) - env.Program('foo.c') - - - foo.c - - - - - - The user can now explicity set the &COLOR; build variable - to any of the specified allowed values: - - - - - scons -Q COLOR=red foo.o - scons -Q COLOR=blue foo.o - scons -Q COLOR=green foo.o - - - - - But, almost more importantly, - an attempt to set &COLOR; - to a value that's not in the list - generates an error message: - - - - - scons -Q COLOR=magenta foo.o - - - - - The &EnumVariable; function also supports a way - to map alternate names to allowed values. - Suppose, for example, - that we want to allow the user - to use the word navy as a synonym for - blue. - We do this by adding a ↦ dictionary - that will map its key values - to the desired legal value: - - - - - - vars = Variables('custom.py') - vars.Add(EnumVariable('COLOR', 'Set background color', 'red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'})) - env = Environment(variables = vars, - CPPDEFINES={'COLOR' : '"${COLOR}"'}) - env.Program('foo.c') - - - foo.c - - - - - - As desired, the user can then use - navy on the command line, - and &SCons; will translate it into blue - when it comes time to use the &COLOR; - variable to build a target: - - - - - scons -Q COLOR=navy foo.o - - - - - By default, when using the &EnumVariable; function, - arguments that differ - from the legal values - only in case - are treated as illegal values: - - - - - scons -Q COLOR=Red foo.o - scons -Q COLOR=BLUE foo.o - scons -Q COLOR=nAvY foo.o - - - - - The &EnumVariable; function can take an additional - &ignorecase; keyword argument that, - when set to 1, - tells &SCons; to allow case differences - when the values are specified: - - - - - - vars = Variables('custom.py') - vars.Add(EnumVariable('COLOR', 'Set background color', 'red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'}, - ignorecase=1)) - env = Environment(variables = vars, - CPPDEFINES={'COLOR' : '"${COLOR}"'}) - env.Program('foo.c') - - - foo.c - - - - - - Which yields the output: - - - - - scons -Q COLOR=Red foo.o - scons -Q COLOR=BLUE foo.o - scons -Q COLOR=nAvY foo.o - scons -Q COLOR=green foo.o - - - - - Notice that an &ignorecase; value of 1 - preserves the case-spelling that the user supplied. - If you want &SCons; to translate the names - into lower-case, - regardless of the case used by the user, - specify an &ignorecase; value of 2: - - - - - - vars = Variables('custom.py') - vars.Add(EnumVariable('COLOR', 'Set background color', 'red', - allowed_values=('red', 'green', 'blue'), - map={'navy':'blue'}, - ignorecase=2)) - env = Environment(variables = vars, - CPPDEFINES={'COLOR' : '"${COLOR}"'}) - env.Program('foo.c') - - - foo.c - - - - - - Now &SCons; will use values of - red, - green or - blue - regardless of how the user spells - those values on the command line: - - - - - scons -Q COLOR=Red foo.o - scons -Q COLOR=nAvY foo.o - scons -Q COLOR=GREEN foo.o - - -
- -
- Multiple Values From a List: the &ListVariable; Build Variable Function - - - - Another way in which you might want to allow users - to control a build variable is to - specify a list of one or more legal values. - &SCons; supports this through the &ListVariable; function. - If, for example, we want a user to be able to set a - &COLORS; variable to one or more of the legal list of values: - - - - - - vars = Variables('custom.py') - vars.Add(ListVariable('COLORS', 'List of colors', 0, - ['red', 'green', 'blue'])) - env = Environment(variables = vars, - CPPDEFINES={'COLORS' : '"${COLORS}"'}) - env.Program('foo.c') - - - foo.c - - - - - - A user can now specify a comma-separated list - of legal values, - which will get translated into a space-separated - list for passing to the any build commands: - - - - - scons -Q COLORS=red,blue foo.o - scons -Q COLORS=blue,green,red foo.o - - - - - In addition, the &ListVariable; function - allows the user to specify explicit keywords of - &all; or &none; - to select all of the legal values, - or none of them, respectively: - - - - - scons -Q COLORS=all foo.o - scons -Q COLORS=none foo.o - - - - - And, of course, an illegal value - still generates an error message: - - - - - scons -Q COLORS=magenta foo.o - - -
- -
- Path Names: the &PathVariable; Build Variable Function - - - - &SCons; supports a &PathVariable; function - to make it easy to create a build variable - to control an expected path name. - If, for example, you need to - define a variable in the preprocessor - that controls the location of a - configuration file: - - - - - - vars = Variables('custom.py') - vars.Add(PathVariable('CONFIG', - 'Path to configuration file', - '__ROOT__/etc/my_config')) - env = Environment(variables = vars, - CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) - env.Program('foo.c') - - - foo.c - - - /opt/location - - - /opt/location - - - - - - This then allows the user to - override the &CONFIG; build variable - on the command line as necessary: - - - - - scons -Q foo.o - scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o - - - - - By default, &PathVariable; checks to make sure - that the specified path exists and generates an error if it - doesn't: - - - - - scons -Q CONFIG=__ROOT__/does/not/exist foo.o - - - - - &PathVariable; provides a number of methods - that you can use to change this behavior. - If you want to ensure that any specified paths are, - in fact, files and not directories, - use the &PathVariable_PathIsFile; method: - - - - - - vars = Variables('custom.py') - vars.Add(PathVariable('CONFIG', - 'Path to configuration file', - '__ROOT__/etc/my_config', - PathVariable.PathIsFile)) - env = Environment(variables = vars, - CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) - env.Program('foo.c') - - - foo.c - - - /opt/location - - - - - - Conversely, to ensure that any specified paths are - directories and not files, - use the &PathVariable_PathIsDir; method: - - - - - - vars = Variables('custom.py') - vars.Add(PathVariable('DBDIR', - 'Path to database directory', - '__ROOT__/var/my_dbdir', - PathVariable.PathIsDir)) - env = Environment(variables = vars, - CPPDEFINES={'DBDIR' : '"$DBDIR"'}) - env.Program('foo.c') - - - foo.c - - - /opt/location - - - - - - If you want to make sure that any specified paths - are directories, - and you would like the directory created - if it doesn't already exist, - use the &PathVariable_PathIsDirCreate; method: - - - - - - vars = Variables('custom.py') - vars.Add(PathVariable('DBDIR', - 'Path to database directory', - '__ROOT__/var/my_dbdir', - PathVariable.PathIsDirCreate)) - env = Environment(variables = vars, - CPPDEFINES={'DBDIR' : '"$DBDIR"'}) - env.Program('foo.c') - - - foo.c - - - /opt/location - - - - - - Lastly, if you don't care whether the path exists, - is a file, or a directory, - use the &PathVariable_PathAccept; method - to accept any path that the user supplies: - - - - - - vars = Variables('custom.py') - vars.Add(PathVariable('OUTPUT', - 'Path to output file or directory', - None, - PathVariable.PathAccept)) - env = Environment(variables = vars, - CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) - env.Program('foo.c') - - - foo.c - - - -
- -
- Enabled/Disabled Path Names: the &PackageVariable; Build Variable Function - - - - Sometimes you want to give users - even more control over a path name variable, - allowing them to explicitly enable or - disable the path name - by using yes or no keywords, - in addition to allow them - to supply an explicit path name. - &SCons; supports the &PackageVariable; - function to support this: - - - - - - vars = Variables('custom.py') - vars.Add(PackageVariable('PACKAGE', - 'Location package', - '__ROOT__/opt/location')) - env = Environment(variables = vars, - CPPDEFINES={'PACKAGE' : '"$PACKAGE"'}) - env.Program('foo.c') - - - foo.c - - - /opt/location - - - /opt/location - - - - - - When the &SConscript; file uses the &PackageVariable; funciton, - user can now still use the default - or supply an overriding path name, - but can now explicitly set the - specified variable to a value - that indicates the package should be enabled - (in which case the default should be used) - or disabled: - - - - - scons -Q foo.o - scons -Q PACKAGE=__ROOT__/usr/local/location foo.o - scons -Q PACKAGE=yes foo.o - scons -Q PACKAGE=no foo.o - - -
- -
- -
- Adding Multiple Command-Line Build Variables at Once - - - - Lastly, &SCons; provides a way to add - multiple build variables to a &Variables; object at once. - Instead of having to call the &Add; method - multiple times, - you can call the &AddVariables; - method with a list of build variables - to be added to the object. - Each build variable is specified - as either a tuple of arguments, - just like you'd pass to the &Add; method itself, - or as a call to one of the pre-defined - functions for pre-packaged command-line build variables. - in any order: - - - - - - vars = Variables() - vars.AddVariables( - ('RELEASE', 'Set to 1 to build for release', 0), - ('CONFIG', 'Configuration file', '/etc/my_config'), - BoolVariable('warnings', 'compilation with -Wall and similiar', 1), - EnumVariable('debug', 'debug output and symbols', 'no', - allowed_values=('yes', 'no', 'full'), - map={}, ignorecase=0), # case sensitive - ListVariable('shared', - 'libraries to build as shared libraries', - 'all', - names = list_of_libs), - PackageVariable('x11', - 'use X11 installed here (yes = search some places)', - 'yes'), - PathVariable('qtdir', 'where the root of Qt is installed', qtdir), - ) - - - - - - -
- -
- Handling Unknown Command-Line Build Variables: the &UnknownVariables; Function - - - - Users may, of course, - occasionally misspell variable names in their command-line settings. - &SCons; does not generate an error or warning - for any unknown variables the users specifies on the command line. - (This is in no small part because you may be - processing the arguments directly using the &ARGUMENTS; dictionary, - and therefore &SCons; can't know in the general case - whether a given "misspelled" variable is - really unknown and a potential problem, - or something that your &SConscript; file - will handle directly with some Python code.) - - - - - - If, however, you're using a &Variables; object to - define a specific set of command-line build variables - that you expect users to be able to set, - you may want to provide an error - message or warning of your own - if the user supplies a variable setting - that is not among - the defined list of variable names known to the &Variables; object. - You can do this by calling the &UnknownVariables; - method of the &Variables; object: - - - - - - vars = Variables(None) - vars.Add('RELEASE', 'Set to 1 to build for release', 0) - env = Environment(variables = vars, - CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) - unknown = vars.UnknownVariables() - if unknown: - print "Unknown variables:", unknown.keys() - Exit(1) - env.Program('foo.c') - - - foo.c - - - - - - The &UnknownVariables; method returns a dictionary - containing the keywords and values - of any variables the user specified on the command line - that are not - among the variables known to the &Variables; object - (from having been specified using - the &Variables; object's&Add; method). - In the examble above, - we check for whether the dictionary - returned by the &UnknownVariables; is non-empty, - and if so print the Python list - containing the names of the unknwown variables - and then call the &Exit; function - to terminate &SCons;: - - - - - scons -Q NOT_KNOWN=foo - - - - - Of course, you can process the items in the - dictionary returned by the &UnknownVariables; function - in any way appropriate to your build configuration, - including just printing a warning message - but not exiting, - logging an error somewhere, - etc. - - - - - - Note that you must delay the call of &UnknownVariables; - until after you have applied the &Variables; object - to a construction environment - with the variables= - keyword argument of an &Environment; call. - - - -
- -
- -
- Command-Line Targets - -
- Fetching Command-Line Targets: the &COMMAND_LINE_TARGETS; Variable - - - - &SCons; supports a &COMMAND_LINE_TARGETS; variable - that lets you fetch the list of targets that the - user specified on the command line. - You can use the targets to manipulate the - build in any way you wish. - As a simple example, - suppose that you want to print a reminder - to the user whenever a specific program is built. - You can do this by checking for the - target in the &COMMAND_LINE_TARGETS; list: - - - - - - if 'bar' in COMMAND_LINE_TARGETS: - print "Don't forget to copy `bar' to the archive!" - Default(Program('foo.c')) - Program('bar.c') - - - foo.c - - - foo.c - - - - - - Then, running &SCons; with the default target - works as it always does, - but explicity specifying the &bar; target - on the command line generates the warning message: - - - - - scons -Q - scons -Q bar - - - - - Another practical use for the &COMMAND_LINE_TARGETS; variable - might be to speed up a build - by only reading certain subsidiary &SConscript; - files if a specific target is requested. - - - -
- -
- Controlling the Default Targets: the &Default; Function - - - - One of the most basic things you can control - is which targets &SCons; will build by default--that is, - when there are no targets specified on the command line. - As mentioned previously, - &SCons; will normally build every target - in or below the current directory - by default--that is, when you don't - explicitly specify one or more targets - on the command line. - Sometimes, however, you may want - to specify explicitly that only - certain programs, or programs in certain directories, - should be built by default. - You do this with the &Default; function: - - - - - - env = Environment() - hello = env.Program('hello.c') - env.Program('goodbye.c') - Default(hello) - - - hello.c - - - goodbye.c - - - - - - This &SConstruct; file knows how to build two programs, - &hello; and &goodbye;, - but only builds the - &hello; program by default: - - - - - scons -Q - scons -Q - scons -Q goodbye - - - - - Note that, even when you use the &Default; - function in your &SConstruct; file, - you can still explicitly specify the current directory - (.) on the command line - to tell &SCons; to build - everything in (or below) the current directory: - - - - - scons -Q . - - - - - You can also call the &Default; - function more than once, - in which case each call - adds to the list of targets to be built by default: - - - - - - env = Environment() - prog1 = env.Program('prog1.c') - Default(prog1) - prog2 = env.Program('prog2.c') - prog3 = env.Program('prog3.c') - Default(prog3) - - - prog1.c - - - prog2.c - - - prog3.c - - - - - - Or you can specify more than one target - in a single call to the &Default; function: - - - - - env = Environment() - prog1 = env.Program('prog1.c') - prog2 = env.Program('prog2.c') - prog3 = env.Program('prog3.c') - Default(prog1, prog3) - - - - - Either of these last two examples - will build only the - prog1 - and - prog3 - programs by default: - - - - - scons -Q - scons -Q . - - - - - You can list a directory as - an argument to &Default;: - - - - - - env = Environment() - env.Program(['prog1/main.c', 'prog1/foo.c']) - env.Program(['prog2/main.c', 'prog2/bar.c']) - Default('prog1') - - - - - int main() { printf("prog1/main.c\n"); } - - - int foo() { printf("prog1/foo.c\n"); } - - - int main() { printf("prog2/main.c\n"); } - - - int bar() { printf("prog2/bar.c\n"); } - - - - - - In which case only the target(s) in that - directory will be built by default: - - - - - scons -Q - scons -Q - scons -Q . - - - - - Lastly, if for some reason you don't want - any targets built by default, - you can use the Python None - variable: - - - - - - env = Environment() - prog1 = env.Program('prog1.c') - prog2 = env.Program('prog2.c') - Default(None) - - - prog1.c - - - prog2.c - - - - - - Which would produce build output like: - - - - - scons -Q - scons -Q . - - -
- Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable - - - - &SCons; supports a &DEFAULT_TARGETS; variable - that lets you get at the current list of default targets. - The &DEFAULT_TARGETS; variable has - two important differences from the &COMMAND_LINE_TARGETS; variable. - First, the &DEFAULT_TARGETS; variable is a list of - internal &SCons; nodes, - so you need to convert the list elements to strings - if you want to print them or look for a specific target name. - Fortunately, you can do this easily - by using the Python map function - to run the list through str: - - - - - - prog1 = Program('prog1.c') - Default(prog1) - print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS) - - - prog1.c - - - - - - (Keep in mind that all of the manipulation of the - &DEFAULT_TARGETS; list takes place during the - first phase when &SCons; is reading up the &SConscript; files, - which is obvious if - we leave off the -Q flag when we run &SCons;:) - - - - - scons - - - - - Second, - the contents of the &DEFAULT_TARGETS; list change - in response to calls to the &Default; function, - as you can see from the following &SConstruct; file: - - - - - - prog1 = Program('prog1.c') - Default(prog1) - print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) - prog2 = Program('prog2.c') - Default(prog2) - print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) - - - prog1.c - - - prog2.c - - - - - - Which yields the output: - - - - - scons - - - - - In practice, this simply means that you - need to pay attention to the order in - which you call the &Default; function - and refer to the &DEFAULT_TARGETS; list, - to make sure that you don't examine the - list before you've added the default targets - you expect to find in it. - - - -
- -
- -
- Fetching the List of Build Targets, Regardless of Origin: the &BUILD_TARGETS; Variable - - - - We've already been introduced to the - &COMMAND_LINE_TARGETS; variable, - which contains a list of targets specified on the command line, - and the &DEFAULT_TARGETS; variable, - which contains a list of targets specified - via calls to the &Default; method or function. - Sometimes, however, - you want a list of whatever targets - &SCons; will try to build, - regardless of whether the targets came from the - command line or a &Default; call. - You could code this up by hand, as follows: - - - - - if COMMAND_LINE_TARGETS: - targets = COMMAND_LINE_TARGETS - else: - targets = DEFAULT_TARGETS - - - - - &SCons;, however, provides a convenient - &BUILD_TARGETS; variable - that eliminates the need for this by-hand manipulation. - Essentially, the &BUILD_TARGETS; variable - contains a list of the command-line targets, - if any were specified, - and if no command-line targets were specified, - it contains a list of the targets specified - via the &Default; method or function. - - - - - - Because &BUILD_TARGETS; may contain a list of &SCons; nodes, - you must convert the list elements to strings - if you want to print them or look for a specific target name, - just like the &DEFAULT_TARGETS; list: - - - - - - prog1 = Program('prog1.c') - Program('prog2.c') - Default(prog1) - print "BUILD_TARGETS is", map(str, BUILD_TARGETS) - - - prog1.c - - - prog2.c - - - - - - Notice how the value of &BUILD_TARGETS; - changes depending on whether a target is - specified on the command line: - - - - - scons -Q - scons -Q prog2 - scons -Q -c . - - -
- -
diff --git a/doc/user/command-line.xml b/doc/user/command-line.xml index 1006c6b..33f88ec 100644 --- a/doc/user/command-line.xml +++ b/doc/user/command-line.xml @@ -146,19 +146,26 @@ - - - - % scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - ... [build output] ... - scons: done building targets. - % export SCONSFLAGS="-Q" - % scons - ... [build output] ... - + + + def b(target, source, env): + pass + def s(target, source, env): + return " ... [build output] ..." + a = Action(b, strfunction = s) + env = Environment(BUILDERS = {'A' : Builder(action=a)}) + env.A('foo.out', 'foo.in') + + + foo.in + + + + + scons + export SCONSFLAGS="-Q" + scons + @@ -214,10 +221,10 @@ - + if not GetOption('help'): SConscript('src/SConscript', export='env') - + @@ -283,12 +290,17 @@ - + + import os num_cpu = int(os.environ.get('NUM_CPU', 2)) SetOption('num_jobs', num_cpu) print "running with -j", GetOption('num_jobs') - + + + foo.in + + @@ -310,11 +322,9 @@ - - % scons -Q - running with -j 2 - scons: `.' is up to date. - + + scons -Q + @@ -324,12 +334,10 @@ - - % export NUM_CPU="4" - % scons -Q - running with -j 4 - scons: `.' is up to date. - + + export NUM_CPU="4" + scons -Q + @@ -342,15 +350,11 @@ - - % scons -Q -j 7 - running with -j 7 - scons: `.' is up to date. - % export NUM_CPU="4" - % scons -Q -j 3 - running with -j 3 - scons: `.' is up to date. - + + scons -Q -j 7 + export NUM_CPU="4" + scons -Q -j 3 + @@ -600,7 +604,8 @@ - + + AddOption('--prefix', dest='prefix', type='string', @@ -613,7 +618,11 @@ installed_foo = env.Install('$PREFIX/usr/bin', 'foo.in') Default(installed_foo) - + + + foo.in + + @@ -631,10 +640,9 @@ - - % scons -Q -n - Install file: "foo.in" as "/usr/bin/foo.in" - + + scons -Q -n + @@ -644,10 +652,9 @@ - - % scons -Q -n --prefix=/tmp/install - Install file: "foo.in" as "/tmp/install/usr/bin/foo.in" - + + scons -Q -n --prefix=/tmp/install + @@ -702,13 +709,18 @@ - + + env = Environment() debug = ARGUMENTS.get('debug', 0) if int(debug): env.Append(CCFLAGS = '-g') env.Program('prog.c') - + + + prog.c + + @@ -719,18 +731,12 @@ - - % scons -Q debug=0 - cc -o prog.o -c prog.c - cc -o prog prog.o - % scons -Q debug=0 - scons: `.' is up to date. - % scons -Q debug=1 - cc -o prog.o -c -g prog.c - cc -o prog prog.o - % scons -Q debug=1 - scons: `.' is up to date. - + + scons -Q debug=0 + scons -Q debug=0 + scons -Q debug=1 + scons -Q debug=1 + @@ -792,14 +798,19 @@ - + + cppdefines = [] for key, value in ARGLIST: if key == 'define': cppdefines.append(value) env = Environment(CPPDEFINES = cppdefines) env.Object('prog.c') - + + + prog.c + + @@ -807,12 +818,10 @@ - - % scons -Q define=FOO - cc -o prog.o -c -DFOO prog.c - % scons -Q define=FOO define=BAR - cc -o prog.o -c -DFOO -DBAR prog.c - + + scons -Q define=FOO + scons -Q define=FOO define=BAR + @@ -874,13 +883,21 @@ - + + vars = Variables(None, ARGUMENTS) vars.Add('RELEASE', 'Set to 1 to build for release', 0) env = Environment(variables = vars, CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) env.Program(['foo.c', 'bar.c']) - + + + foo.c + + + bar.c + + @@ -911,12 +928,9 @@ - - % scons -Q RELEASE=1 - cc -o bar.o -c -DRELEASE_BUILD=1 bar.c - cc -o foo.o -c -DRELEASE_BUILD=1 foo.c - cc -o foo foo.o bar.o - + + scons -Q RELEASE=1 + @@ -960,12 +974,14 @@ - + + vars = Variables(None, ARGUMENTS) vars.Add('RELEASE', 'Set to 1 to build for release', 0) env = Environment(variables = vars) Help(vars.GenerateHelpText(env)) - + + @@ -974,15 +990,9 @@ - - % scons -Q -h - - RELEASE: Set to 1 to build for release - default: 0 - actual: 0 - - Use scons -H for help about command-line options. - + + scons -Q -h + @@ -1011,14 +1021,25 @@ - + + vars = Variables('custom.py') vars.Add('RELEASE', 'Set to 1 to build for release', 0) env = Environment(variables = vars, CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) env.Program(['foo.c', 'bar.c']) Help(vars.GenerateHelpText(env)) - + + + foo.c + + + bar.c + + + RELEASE = 1 + + @@ -1027,9 +1048,7 @@ - - RELEASE = 1 - + @@ -1039,12 +1058,9 @@ - - % scons -Q - cc -o bar.o -c -DRELEASE_BUILD=1 bar.c - cc -o foo.o -c -DRELEASE_BUILD=1 foo.c - cc -o foo foo.o bar.o - + + scons -Q + @@ -1052,9 +1068,25 @@ - + + + vars = Variables('custom.py') + vars.Add('RELEASE', 'Set to 1 to build for release', 0) + env = Environment(variables = vars, + CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) + env.Program(['foo.c', 'bar.c']) + Help(vars.GenerateHelpText(env)) + + + foo.c + + + bar.c + + RELEASE = 0 - + + @@ -1063,12 +1095,9 @@ - - % scons -Q - cc -o bar.o -c -DRELEASE_BUILD=0 bar.c - cc -o foo.o -c -DRELEASE_BUILD=0 foo.c - cc -o foo foo.o bar.o - + + scons -Q + @@ -1129,13 +1158,18 @@ - + + vars = Variables('custom.py') vars.Add(BoolVariable('RELEASE', 'Set to build for release', 0)) env = Environment(variables = vars, CPPDEFINES={'RELEASE_BUILD' : '${RELEASE}'}) env.Program('foo.c') - + + + foo.c + + @@ -1146,15 +1180,13 @@ - - % scons -Q RELEASE=yes foo.o - cc -o foo.o -c -DRELEASE_BUILD=True foo.c - + + scons -Q RELEASE=yes foo.o + - - % scons -Q RELEASE=t foo.o - cc -o foo.o -c -DRELEASE_BUILD=True foo.c - + + scons -Q RELEASE=t foo.o + @@ -1177,15 +1209,13 @@ - - % scons -Q RELEASE=no foo.o - cc -o foo.o -c -DRELEASE_BUILD=False foo.c - + + scons -Q RELEASE=no foo.o + - - % scons -Q RELEASE=f foo.o - cc -o foo.o -c -DRELEASE_BUILD=False foo.c - + + scons -Q RELEASE=f foo.o + @@ -1206,13 +1236,9 @@ - - % scons -Q RELEASE=bad_value foo.o - - scons: *** Error converting option: RELEASE - Invalid value for boolean option: bad_value - File "/home/my/project/SConstruct", line 4, in <module> - + + scons -Q RELEASE=bad_value foo.o + @@ -1236,14 +1262,19 @@ - + + vars = Variables('custom.py') vars.Add(EnumVariable('COLOR', 'Set background color', 'red', allowed_values=('red', 'green', 'blue'))) env = Environment(variables = vars, CPPDEFINES={'COLOR' : '"${COLOR}"'}) env.Program('foo.c') - + + + foo.c + + @@ -1252,14 +1283,11 @@ - - % scons -Q COLOR=red foo.o - cc -o foo.o -c -DCOLOR="red" foo.c - % scons -Q COLOR=blue foo.o - cc -o foo.o -c -DCOLOR="blue" foo.c - % scons -Q COLOR=green foo.o - cc -o foo.o -c -DCOLOR="green" foo.c - + + scons -Q COLOR=red foo.o + scons -Q COLOR=blue foo.o + scons -Q COLOR=green foo.o + @@ -1270,12 +1298,9 @@ - - % scons -Q COLOR=magenta foo.o - - scons: *** Invalid value for option COLOR: magenta. Valid values are: ('red', 'green', 'blue') - File "/home/my/project/SConstruct", line 5, in <module> - + + scons -Q COLOR=magenta foo.o + @@ -1291,7 +1316,8 @@ - + + vars = Variables('custom.py') vars.Add(EnumVariable('COLOR', 'Set background color', 'red', allowed_values=('red', 'green', 'blue'), @@ -1299,7 +1325,11 @@ env = Environment(variables = vars, CPPDEFINES={'COLOR' : '"${COLOR}"'}) env.Program('foo.c') - + + + foo.c + + @@ -1311,10 +1341,9 @@ - - % scons -Q COLOR=navy foo.o - cc -o foo.o -c -DCOLOR="blue" foo.c - + + scons -Q COLOR=navy foo.o + @@ -1326,20 +1355,11 @@ - - % scons -Q COLOR=Red foo.o - - scons: *** Invalid value for option COLOR: Red. Valid values are: ('red', 'green', 'blue') - File "/home/my/project/SConstruct", line 5, in <module> - % scons -Q COLOR=BLUE foo.o - - scons: *** Invalid value for option COLOR: BLUE. Valid values are: ('red', 'green', 'blue') - File "/home/my/project/SConstruct", line 5, in <module> - % scons -Q COLOR=nAvY foo.o - - scons: *** Invalid value for option COLOR: nAvY. Valid values are: ('red', 'green', 'blue') - File "/home/my/project/SConstruct", line 5, in <module> - + + scons -Q COLOR=Red foo.o + scons -Q COLOR=BLUE foo.o + scons -Q COLOR=nAvY foo.o + @@ -1351,7 +1371,8 @@ - + + vars = Variables('custom.py') vars.Add(EnumVariable('COLOR', 'Set background color', 'red', allowed_values=('red', 'green', 'blue'), @@ -1360,7 +1381,11 @@ env = Environment(variables = vars, CPPDEFINES={'COLOR' : '"${COLOR}"'}) env.Program('foo.c') - + + + foo.c + + @@ -1368,16 +1393,12 @@ - - % scons -Q COLOR=Red foo.o - cc -o foo.o -c -DCOLOR="Red" foo.c - % scons -Q COLOR=BLUE foo.o - cc -o foo.o -c -DCOLOR="BLUE" foo.c - % scons -Q COLOR=nAvY foo.o - cc -o foo.o -c -DCOLOR="blue" foo.c - % scons -Q COLOR=green foo.o - cc -o foo.o -c -DCOLOR="green" foo.c - + + scons -Q COLOR=Red foo.o + scons -Q COLOR=BLUE foo.o + scons -Q COLOR=nAvY foo.o + scons -Q COLOR=green foo.o + @@ -1390,7 +1411,8 @@ - + + vars = Variables('custom.py') vars.Add(EnumVariable('COLOR', 'Set background color', 'red', allowed_values=('red', 'green', 'blue'), @@ -1399,7 +1421,11 @@ env = Environment(variables = vars, CPPDEFINES={'COLOR' : '"${COLOR}"'}) env.Program('foo.c') - + + + foo.c + + @@ -1412,14 +1438,11 @@ - - % scons -Q COLOR=Red foo.o - cc -o foo.o -c -DCOLOR="red" foo.c - % scons -Q COLOR=nAvY foo.o - cc -o foo.o -c -DCOLOR="blue" foo.c - % scons -Q COLOR=GREEN foo.o - cc -o foo.o -c -DCOLOR="green" foo.c - + + scons -Q COLOR=Red foo.o + scons -Q COLOR=nAvY foo.o + scons -Q COLOR=GREEN foo.o + @@ -1437,14 +1460,19 @@ - + + vars = Variables('custom.py') vars.Add(ListVariable('COLORS', 'List of colors', 0, ['red', 'green', 'blue'])) env = Environment(variables = vars, CPPDEFINES={'COLORS' : '"${COLORS}"'}) env.Program('foo.c') - + + + foo.c + + @@ -1455,12 +1483,10 @@ - - % scons -Q COLORS=red,blue foo.o - cc -o foo.o -c -DCOLORS="red blue" foo.c - % scons -Q COLORS=blue,green,red foo.o - cc -o foo.o -c -DCOLORS="blue green red" foo.c - + + scons -Q COLORS=red,blue foo.o + scons -Q COLORS=blue,green,red foo.o + @@ -1472,12 +1498,10 @@ - - % scons -Q COLORS=all foo.o - cc -o foo.o -c -DCOLORS="red green blue" foo.c - % scons -Q COLORS=none foo.o - cc -o foo.o -c -DCOLORS="" foo.c - + + scons -Q COLORS=all foo.o + scons -Q COLORS=none foo.o + @@ -1486,13 +1510,9 @@ - - % scons -Q COLORS=magenta foo.o - - scons: *** Error converting option: COLORS - Invalid value(s) for option: magenta - File "/home/my/project/SConstruct", line 5, in <module> - + + scons -Q COLORS=magenta foo.o + @@ -1511,15 +1531,26 @@ - + + vars = Variables('custom.py') vars.Add(PathVariable('CONFIG', 'Path to configuration file', - '/etc/my_config')) + '__ROOT__/etc/my_config')) env = Environment(variables = vars, CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) env.Program('foo.c') - + + + foo.c + + + /opt/location + + + /opt/location + + @@ -1529,12 +1560,10 @@ - - % scons -Q foo.o - cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c - % scons -Q CONFIG=/usr/local/etc/other_config foo.o - scons: `foo.o' is up to date. - + + scons -Q foo.o + scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o + @@ -1544,12 +1573,9 @@ - - % scons -Q CONFIG=/does/not/exist foo.o - - scons: *** Path for option CONFIG does not exist: /does/not/exist - File "/home/my/project/SConstruct", line 6, in <module> - + + scons -Q CONFIG=__ROOT__/does/not/exist foo.o + @@ -1561,16 +1587,24 @@ - + + vars = Variables('custom.py') vars.Add(PathVariable('CONFIG', 'Path to configuration file', - '/etc/my_config', + '__ROOT__/etc/my_config', PathVariable.PathIsFile)) env = Environment(variables = vars, CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) env.Program('foo.c') - + + + foo.c + + + /opt/location + + @@ -1580,16 +1614,24 @@ - + + vars = Variables('custom.py') vars.Add(PathVariable('DBDIR', 'Path to database directory', - '/var/my_dbdir', + '__ROOT__/var/my_dbdir', PathVariable.PathIsDir)) env = Environment(variables = vars, CPPDEFINES={'DBDIR' : '"$DBDIR"'}) env.Program('foo.c') - + + + foo.c + + + /opt/location + + @@ -1601,16 +1643,24 @@ - + + vars = Variables('custom.py') vars.Add(PathVariable('DBDIR', 'Path to database directory', - '/var/my_dbdir', + '__ROOT__/var/my_dbdir', PathVariable.PathIsDirCreate)) env = Environment(variables = vars, CPPDEFINES={'DBDIR' : '"$DBDIR"'}) env.Program('foo.c') - + + + foo.c + + + /opt/location + + @@ -1621,7 +1671,8 @@ - + + vars = Variables('custom.py') vars.Add(PathVariable('OUTPUT', 'Path to output file or directory', @@ -1630,7 +1681,11 @@ env = Environment(variables = vars, CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) env.Program('foo.c') - + + + foo.c + + @@ -1651,15 +1706,26 @@ - + + vars = Variables('custom.py') vars.Add(PackageVariable('PACKAGE', 'Location package', - '/opt/location')) + '__ROOT__/opt/location')) env = Environment(variables = vars, CPPDEFINES={'PACKAGE' : '"$PACKAGE"'}) env.Program('foo.c') - + + + foo.c + + + /opt/location + + + /opt/location + + @@ -1674,16 +1740,12 @@ - - % scons -Q foo.o - cc -o foo.o -c -DPACKAGE="/opt/location" foo.c - % scons -Q PACKAGE=/usr/local/location foo.o - cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c - % scons -Q PACKAGE=yes foo.o - cc -o foo.o -c -DPACKAGE="True" foo.c - % scons -Q PACKAGE=no foo.o - cc -o foo.o -c -DPACKAGE="False" foo.c - + + scons -Q foo.o + scons -Q PACKAGE=__ROOT__/usr/local/location foo.o + scons -Q PACKAGE=yes foo.o + scons -Q PACKAGE=no foo.o + @@ -1710,7 +1772,8 @@ - + + vars = Variables() vars.AddVariables( ('RELEASE', 'Set to 1 to build for release', 0), @@ -1728,7 +1791,8 @@ 'yes'), PathVariable('qtdir', 'where the root of Qt is installed', qtdir), ) - + + @@ -1769,7 +1833,8 @@ - + + vars = Variables(None) vars.Add('RELEASE', 'Set to 1 to build for release', 0) env = Environment(variables = vars, @@ -1779,7 +1844,11 @@ print "Unknown variables:", unknown.keys() Exit(1) env.Program('foo.c') - + + + foo.c + + @@ -1800,10 +1869,9 @@ - - % scons -Q NOT_KNOWN=foo - Unknown variables: ['NOT_KNOWN'] - + + scons -Q NOT_KNOWN=foo + @@ -1852,12 +1920,20 @@ - + + if 'bar' in COMMAND_LINE_TARGETS: print "Don't forget to copy `bar' to the archive!" Default(Program('foo.c')) Program('bar.c') - + + + foo.c + + + foo.c + + @@ -1868,15 +1944,10 @@ - - % scons -Q - cc -o foo.o -c foo.c - cc -o foo foo.o - % scons -Q bar - Don't forget to copy `bar' to the archive! - cc -o bar.o -c bar.c - cc -o bar bar.o - + + scons -Q + scons -Q bar + @@ -1911,12 +1982,20 @@ - + + env = Environment() hello = env.Program('hello.c') env.Program('goodbye.c') Default(hello) - + + + hello.c + + + goodbye.c + + @@ -1927,16 +2006,11 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q - scons: `hello' is up to date. - % scons -Q goodbye - cc -o goodbye.o -c goodbye.c - cc -o goodbye goodbye.o - + + scons -Q + scons -Q + scons -Q goodbye + @@ -1949,13 +2023,9 @@ - - % scons -Q . - cc -o goodbye.o -c goodbye.c - cc -o goodbye goodbye.o - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q . + @@ -1966,14 +2036,25 @@ - + + env = Environment() prog1 = env.Program('prog1.c') Default(prog1) prog2 = env.Program('prog2.c') prog3 = env.Program('prog3.c') Default(prog3) - + + + prog1.c + + + prog2.c + + + prog3.c + + @@ -2001,16 +2082,10 @@ - - % scons -Q - cc -o prog1.o -c prog1.c - cc -o prog1 prog1.o - cc -o prog3.o -c prog3.c - cc -o prog3 prog3.o - % scons -Q . - cc -o prog2.o -c prog2.c - cc -o prog2 prog2.o - + + scons -Q + scons -Q . + @@ -2019,12 +2094,28 @@ - + + env = Environment() env.Program(['prog1/main.c', 'prog1/foo.c']) env.Program(['prog2/main.c', 'prog2/bar.c']) Default('prog1') - + + + + + int main() { printf("prog1/main.c\n"); } + + + int foo() { printf("prog1/foo.c\n"); } + + + int main() { printf("prog2/main.c\n"); } + + + int bar() { printf("prog2/bar.c\n"); } + + @@ -2033,18 +2124,11 @@ - - % scons -Q - cc -o prog1/foo.o -c prog1/foo.c - cc -o prog1/main.o -c prog1/main.c - cc -o prog1/main prog1/main.o prog1/foo.o - % scons -Q - scons: `prog1' is up to date. - % scons -Q . - cc -o prog2/bar.o -c prog2/bar.c - cc -o prog2/main.o -c prog2/main.c - cc -o prog2/main prog2/main.o prog2/bar.o - + + scons -Q + scons -Q + scons -Q . + @@ -2055,12 +2139,20 @@ - + + env = Environment() prog1 = env.Program('prog1.c') prog2 = env.Program('prog2.c') Default(None) - + + + prog1.c + + + prog2.c + + @@ -2068,15 +2160,10 @@ - - % scons -Q - scons: *** No targets specified and no Default() targets found. Stop. - % scons -Q . - cc -o prog1.o -c prog1.c - cc -o prog1 prog1.o - cc -o prog2.o -c prog2.c - cc -o prog2 prog2.o - + + scons -Q + scons -Q . +
Fetching the List of Default Targets: the &DEFAULT_TARGETS; Variable @@ -2097,11 +2184,16 @@ - + + prog1 = Program('prog1.c') Default(prog1) print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS) - + + + prog1.c + + @@ -2113,16 +2205,9 @@ - - % scons - scons: Reading SConscript files ... - DEFAULT_TARGETS is ['prog1'] - scons: done reading SConscript files. - scons: Building targets ... - cc -o prog1.o -c prog1.c - cc -o prog1 prog1.o - scons: done building targets. - + + scons + @@ -2133,14 +2218,22 @@ - + + prog1 = Program('prog1.c') Default(prog1) print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) prog2 = Program('prog2.c') Default(prog2) print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS) - + + + prog1.c + + + prog2.c + + @@ -2148,19 +2241,9 @@ - - % scons - scons: Reading SConscript files ... - DEFAULT_TARGETS is now ['prog1'] - DEFAULT_TARGETS is now ['prog1', 'prog2'] - scons: done reading SConscript files. - scons: Building targets ... - cc -o prog1.o -c prog1.c - cc -o prog1 prog1.o - cc -o prog2.o -c prog2.c - cc -o prog2 prog2.o - scons: done building targets. - + + scons + @@ -2198,12 +2281,12 @@ - + if COMMAND_LINE_TARGETS: targets = COMMAND_LINE_TARGETS else: targets = DEFAULT_TARGETS - + @@ -2228,12 +2311,20 @@ - + + prog1 = Program('prog1.c') Program('prog2.c') Default(prog1) print "BUILD_TARGETS is", map(str, BUILD_TARGETS) - + + + prog1.c + + + prog2.c + + @@ -2243,22 +2334,11 @@ - - % scons -Q - BUILD_TARGETS is ['prog1'] - cc -o prog1.o -c prog1.c - cc -o prog1 prog1.o - % scons -Q prog2 - BUILD_TARGETS is ['prog2'] - cc -o prog2.o -c prog2.c - cc -o prog2 prog2.o - % scons -Q -c . - BUILD_TARGETS is ['.'] - Removed prog1.o - Removed prog1 - Removed prog2.o - Removed prog2 - + + scons -Q + scons -Q prog2 + scons -Q -c . +
diff --git a/doc/user/copyright.in b/doc/user/copyright.in deleted file mode 100644 index 76e3e50..0000000 --- a/doc/user/copyright.in +++ /dev/null @@ -1,32 +0,0 @@ - - -
- - - SCons User's Guide Copyright (c) 2004, 2005, 2006, 2007 Steven Knight - - -
diff --git a/doc/user/depends.in b/doc/user/depends.in deleted file mode 100644 index f601312..0000000 --- a/doc/user/depends.in +++ /dev/null @@ -1,1872 +0,0 @@ - - - - - So far we've seen how &SCons; handles one-time builds. - But one of the main functions of a build tool like &SCons; - is to rebuild only what is necessary - when source files change--or, put another way, - &SCons; should not - waste time rebuilding things that don't need to be rebuilt. - You can see this at work simply by re-invoking &SCons; - after building our simple &hello; example: - - - - - - Program('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - scons -Q - scons -Q - - - - - 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: - - - - - scons -Q hello - scons -Q hello - - - - - Note that &SCons; reports "...is up to date" - only for target files named explicitly on the command line, - to avoid cluttering the output. - - - -
- Deciding When an Input File Has Changed: the &Decider; Function - - - - Another aspect of avoiding unnecessary rebuilds - is the fundamental build tool behavior - of rebuilding - things when an input file changes, - so that the built software is up to date. - By default, - &SCons; keeps track of this through an - MD5 &signature;, or checksum, of the contents of each file, - although you can easily configure - &SCons; to use the - modification times (or time stamps) - instead. - You can even specify your own Python function - for deciding if an input file has changed. - - - -
- Using MD5 Signatures to Decide if a File Has Changed - - - - By default, - &SCons; keeps track of whether a file has changed - based on an MD5 checksum of the file's contents, - not the file's modification time. - This means that you may be surprised by the - default &SCons; behavior if you are used to the - &Make; convention of forcing - a rebuild by updating the file's modification time - (using the &touch; command, for example): - - - - - scons -Q hello - touch hello.c - scons -Q hello - - - - - Even though the file's modification time has changed, - &SCons; realizes that the contents of the - &hello_c; file have not changed, - and therefore that the &hello; program - need not be rebuilt. - This avoids unnecessary rebuilds when, - for example, someone rewrites the - contents of a file without making a change. - But if the contents of the file really do change, - then &SCons; detects the change - and rebuilds the program as required: - - - - - scons -Q hello - edit hello.c - scons -Q hello - - - - - Note that you can, if you wish, - specify this default behavior - (MD5 signatures) explicitly - using the &Decider; function as follows: - - - - - Program('hello.c') - Decider('MD5') - - - - - You can also use the string 'content' - as a synonym for 'MD5' - when calling the &Decider; function. - - - -
- Ramifications of Using MD5 Signatures - - - - Using MD5 signatures to decide if an input file has changed - has one surprising benefit: - if a source file has been changed - in such a way that the contents of the - rebuilt target file(s) - will be exactly the same as the last time - the file was built, - then any "downstream" target files - that depend on the rebuilt-but-not-changed target - file actually need not be rebuilt. - - - - - - So if, for example, - a user were to only change a comment in a &hello_c; file, - then the rebuilt &hello_o; file - would be exactly the same as the one previously built - (assuming the compiler doesn't put any build-specific - information in the object file). - &SCons; would then realize that it would not - need to rebuild the &hello; program as follows: - - - - - scons -Q hello - edit hello.c - scons -Q hello - - - - - In essence, &SCons; - "short-circuits" any dependent builds - when it realizes that a target file - has been rebuilt to exactly the same file as the last build. - This does take some extra processing time - to read the contents of the target (&hello_o;) file, - but often saves time when the rebuild that was avoided - would have been time-consuming and expensive. - - - -
- -
- -
- Using Time Stamps to Decide If a File Has Changed - - - - If you prefer, you can - configure &SCons; to use the modification time - of a file, not the file contents, - when deciding if a target needs to be rebuilt. - &SCons; gives you two ways to use time stamps - to decide if an input file has changed - since the last time a target has been built. - - - - - - The most familiar way to use time stamps - is the way &Make; does: - that is, have &SCons; decide - that a target must be rebuilt - if a source file's modification time is - newer - than the target file. - To do this, call the &Decider; - function as follows: - - - - - - Object('hello.c') - Decider('timestamp-newer') - - - int main() { printf("Hello, world!\n"); } - - - - - - This makes &SCons; act like &Make; - when a file's modification time is updated - (using the &touch; command, for example): - - - - - scons -Q hello.o - touch hello.c - scons -Q hello.o - - - - - And, in fact, because this behavior is the same - as the behavior of &Make;, - you can also use the string 'make' - as a synonym for 'timestamp-newer' - when calling the &Decider; function: - - - - - Object('hello.c') - Decider('make') - - - - - One drawback to using times stamps exactly like &Make; - is that if an input file's modification time suddenly - becomes older than a target file, - the target file will not be rebuilt. - This can happen if an old copy of a source file is restored - from a backup archive, for example. - The contents of the restored file will likely be different - than they were the last time a dependent target was built, - but the target won't be rebuilt - because the modification time of the source file - is not newer than the target. - - - - - - Because &SCons; actually stores information - about the source files' time stamps whenever a target is built, - it can handle this situation by checking for - an exact match of the source file time stamp, - instead of just whether or not the source file - is newer than the target file. - To do this, specify the argument - 'timestamp-match' - when calling the &Decider; function: - - - - - - Object('hello.c') - Decider('timestamp-match') - - - int main() { printf("Hello, world!\n"); } - - - - - - When configured this way, - &SCons; will rebuild a target whenever - a source file's modification time has changed. - So if we use the touch -t - option to change the modification time of - &hello_c; to an old date (January 1, 1989), - &SCons; will still rebuild the target file: - - - - - scons -Q hello.o - touch -t 198901010000 hello.c - scons -Q hello.o - - - - - In general, the only reason to prefer - timestamp-newer - instead of - timestamp-match, - would be if you have some specific reason - to require this &Make;-like behavior of - not rebuilding a target when an otherwise-modified - source file is older. - - - -
- -
- Deciding If a File Has Changed Using Both MD Signatures and Time Stamps - - - - As a performance enhancement, - &SCons; provides a way to use - MD5 checksums of file contents - but to read those contents - only when the file's timestamp has changed. - To do this, call the &Decider; - function with 'MD5-timestamp' - argument as follows: - - - - - - Program('hello.c') - Decider('MD5-timestamp') - - - int main() { printf("Hello, world!\n"); } - - - - - - So configured, &SCons; will still behave like - it does when using Decider('MD5'): - - - - - - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % touch hello.c - % scons -Q hello - scons: `hello' is up to date. - % edit hello.c - [CHANGE THE CONTENTS OF hello.c] - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - - - - - However, the second call to &SCons; in the above output, - when the build is up-to-date, - will have been performed by simply looking at the - modification time of the &hello_c; file, - not by opening it and performing - an MD5 checksum calcuation on its contents. - This can significantly speed up many up-to-date builds. - - - - - - The only drawback to using - Decider('MD5-timestamp') - is that &SCons; will not - rebuild a target file if a source file was modified - within one second of the last time &SCons; built the file. - While most developers are programming, - this isn't a problem in practice, - since it's unlikely that someone will have built - and then thought quickly enough to make a substantive - change to a source file within one second. - Certain build scripts or - continuous integration tools may, however, - rely on the ability to apply changes to files - automatically and then rebuild as quickly as possible, - in which case use of - Decider('MD5-timestamp') - may not be appropriate. - - - -
- -
- Writing Your Own Custom &Decider; Function - - - - The different string values that we've passed to - the &Decider; function are essentially used by &SCons; - to pick one of several specific internal functions - that implement various ways of deciding if a dependency - (usually a source file) - has changed since a target file has been built. - As it turns out, - you can also supply your own function - to decide if a dependency has changed. - - - - - - For example, suppose we have an input file - that contains a lot of data, - in some specific regular format, - that is used to rebuild a lot of different target files, - but each target file really only depends on - one particular section of the input file. - We'd like to have each target file depend on - only its section of the input file. - However, since the input file may contain a lot of data, - we want to open the input file only if its timestamp has changed. - This could be done with a custom - &Decider; function that might look something like this: - - - - - - Program('hello.c') - def decide_if_changed(dependency, target, prev_ni): - if self.get_timestamp() != prev_ni.timestamp: - dep = str(dependency) - tgt = str(target) - if specific_part_of_file_has_changed(dep, tgt): - return True - return False - Decider(decide_if_changed) - - - int main() { printf("Hello, world!\n"); } - - - - - - Note that in the function definition, - the dependency - (input file) is the first argument, - and then the ⌖. - Both of these are passed to the functions as - SCons &Node; objects, - which we convert to strings using the Python - str(). - - - - - - The third argument, prev_ni, - is an object that holds the - signature or timestamp information - that was recorded about the dependency - the last time the target was built. - A prev_ni object can hold - different information, - depending on the type of thing that the - dependency argument represents. - For normal files, - the prev_ni object - has the following attributes: - - - - - - - .csig - - - - The content signature, - or MD5 checksum, of the contents of the - dependency - file the list time the ⌖ was built. - - - - - - - .size - - - - The size in bytes of the dependency - file the list time the target was built. - - - - - - - .timestamp - - - - The modification time of the dependency - file the list time the ⌖ was built. - - - - - - - - - - Note that ignoring some of the arguments - in your custom &Decider; function - is a perfectly normal thing to do, - if they don't impact the way you want to - decide if the dependency file has changed. - - - - - - Another thing to look out for is the fact that the three - attributes above may not be present at the time of the first run. - Without any prior build, no targets have been created and no - .sconsign DB file exists yet. - So, you should always check whether the - prev_ni attribute in question is available. - - - - - - We finally present a small example for a - csig-based decider function. Note how the - signature information for the dependency file - has to get initialized via get_csig - during each function call (this is mandatory!). - - - - - env = Environment() - - def config_file_decider(dependency, target, prev_ni): - import os.path - - # We always have to init the .csig value... - dep_csig = dependency.get_csig() - # .csig may not exist, because no target was built yet... - if 'csig' not in dir(prev_ni): - return True - # Target file may not exist yet - if not os.path.exists(str(target.abspath)): - return True - if dep_csig != prev_ni.csig: - # Some change on source file => update installed one - return True - return False - - def update_file(): - f = open("test.txt","a") - f.write("some line\n") - f.close() - - update_file() - - # Activate our own decider function - env.Decider(config_file_decider) - - env.Install("install","test.txt") - - -
- -
- Mixing Different Ways of Deciding If a File Has Changed - - - - The previous examples have all demonstrated calling - the global &Decider; function - to configure all dependency decisions that &SCons; makes. - Sometimes, however, you want to be able to configure - different decision-making for different targets. - When that's necessary, you can use the - env.Decider - method to affect only the configuration - decisions for targets built with a - specific construction environment. - - - - - - For example, if we arbitrarily want to build - one program using MD5 checkums - and another using file modification times - from the same source - we might configure it this way: - - - - - - env1 = Environment(CPPPATH = ['.']) - env2 = env1.Clone() - env2.Decider('timestamp-match') - env1.Program('prog-MD5', 'program1.c') - env2.Program('prog-timestamp', 'program2.c') - - - #include "inc.h" - int main() { printf("Hello, world!\n"); } - - - #include "inc.h" - int main() { printf("Hello, world!\n"); } - - - #define INC 1 - - - - - - If both of the programs include the same - inc.h file, - then updating the modification time of - inc.h - (using the &touch; command) - will cause only prog-timestamp - to be rebuilt: - - - - - scons -Q - touch inc.h - scons -Q - - -
- -
- -
- Older Functions for Deciding When an Input File Has Changed - - - - &SCons; still supports two functions that used to be the - primary methods for configuring the - decision about whether or not an input file has changed. - These functions have been officially deprecated - as &SCons; version 2.0, - and their use is discouraged, - mainly because they rely on a somewhat - confusing distinction between how - source files and target files are handled. - These functions are documented here mainly in case you - encounter them in older &SConscript; files. - - - -
- The &SourceSignatures; Function - - - - The &SourceSignatures; function is fairly straightforward, - and supports two different argument values - to configure whether source file changes should be decided - using MD5 signatures: - - - - - Program('hello.c') - SourceSignatures('MD5') - - - - - Or using time stamps: - - - - - Program('hello.c') - SourceSignatures('timestamp') - - - - - These are roughly equivalent to specifying - Decider('MD5') - or - Decider('timestamp-match'), - respectively, - although it only affects how SCons makes - decisions about dependencies on - source files--that is, - files that are not built from any other files. - - - -
- -
- The &TargetSignatures; Function - - - - The &TargetSignatures; function - specifies how &SCons; decides - when a target file has changed - when it is used as a - dependency of (input to) another target--that is, - the &TargetSignatures; function configures - how the signatures of "intermediate" target files - are used when deciding if a "downstream" target file - must be rebuilt. - - This easily-overlooked distinction between - how &SCons; decides if the target itself must be rebuilt - and how the target is then used to decide if a different - target must be rebuilt is one of the confusing - things that has led to the &TargetSignatures; - and &SourceSignatures; functions being - replaced by the simpler &Decider; function. - - - - - - - The &TargetSignatures; function supports the same - 'MD5' and 'timestamp' - argument values that are supported by the &SourceSignatures;, - with the same meanings, but applied to target files. - That is, in the example: - - - - - Program('hello.c') - TargetSignatures('MD5') - - - - - The MD5 checksum of the &hello_o; target file - will be used to decide if it has changed since the last - time the "downstream" &hello; target file was built. - And in the example: - - - - - Program('hello.c') - TargetSignatures('timestamp') - - - - - The modification time of the &hello_o; target file - will be used to decide if it has changed since the last - time the "downstream" &hello; target file was built. - - - - - - The &TargetSignatures; function supports - two additional argument values: - 'source' and 'build'. - The 'source' argument - specifies that decisions involving - whether target files have changed - since a previous build - should use the same behavior - for the decisions configured for source files - (using the &SourceSignatures; function). - So in the example: - - - - - Program('hello.c') - TargetSignatures('source') - SourceSignatures('timestamp') - - - - - All files, both targets and sources, - will use modification times - when deciding if an input file - has changed since the last - time a target was built. - - - - - - Lastly, the 'build' argument - specifies that &SCons; should examine - the build status of a target file - and always rebuild a "downstream" target - if the target file was itself rebuilt, - without re-examining the contents or timestamp - of the newly-built target file. - If the target file was not rebuilt during - this &scons; invocation, - then the target file will be examined - the same way as configured by - the &SourceSignature; call - to decide if it has changed. - - - - - - This mimics the behavior of - build signatures - in earlier versions of &SCons;. - A &buildsignature; re-combined - signatures of all the input files - that went into making the target file, - so that the target file itself - did not need to have its contents read - to compute an MD5 signature. - This can improve performance for some configurations, - but is generally not as effective as using - Decider('MD5-timestamp'). - - - -
- -
- -
- Implicit Dependencies: The &cv-CPPPATH; Construction Variable - - - - Now suppose that our "Hello, World!" program - actually has an #include line - to include the &hello_h; file in the compilation: - - - - - - Program('hello.c', CPPPATH = '.') - - - #include <hello.h> - int - main() - { - printf("Hello, %s!\n", string); - } - - - #define string "world" - - - - - - And, for completeness, the &hello_h; file looks like this: - - - - - - - - - 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: - - - - - - - - - The &cv-link-CPPPATH; value - tells &SCons; to look in the current directory - ('.') - for any files included by C source files - (.c or .h files). - With this assignment in the &SConstruct; file: - - - - - scons -Q hello - scons -Q hello - edit hello.h - scons -Q hello - - - - - First, notice that &SCons; - added the -I. argument - from the &cv-CPPPATH; variable - so that the compilation would find the - &hello_h; file in the local directory. - - - - - - Second, realize that &SCons; knows that the &hello; - program must be rebuilt - because it scans the contents of - the &hello_c; file - for the #include lines that indicate - another file is being included in the compilation. - &SCons; records these as - implicit dependencies - 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. - - - - - - Like the &cv-link-LIBPATH; variable, - the &cv-CPPPATH; variable - may be a list of directories, - or a string separated by - the system-specific path separation character - (':' on POSIX/Linux, ';' on Windows). - Either way, &SCons; creates the - right command-line options - so that the following example: - - - - - - Program('hello.c', CPPPATH = ['include', '/home/project/inc']) - - - int main() { printf("Hello, world!\n"); } - - - - - - Will look like this on POSIX or Linux: - - - - - scons -Q hello - - - - - And like this on Windows: - - - - - scons -Q hello.exe - - -
- -
- Caching Implicit Dependencies - - - - Scanning each file for #include lines - does take some extra processing time. - When you're doing a full build of a large system, - the scanning time is usually a very small percentage - of the overall time spent on the build. - You're most likely to notice the scanning time, - however, when you rebuild - all or part of a large system: - &SCons; will likely take some extra time to "think about" - what must be built before it issues the - first build command - (or decides that everything is up to date - and nothing must be rebuilt). - - - - - - - - In practice, having &SCons; scan files saves time - relative to the amount of potential time - lost to tracking down subtle problems - introduced by incorrect dependencies. - Nevertheless, the "waiting time" - while &SCons; scans files can annoy - individual developers waiting for their builds to finish. - Consequently, &SCons; lets you cache - the implicit dependencies - that its scanners find, - for use by later builds. - You can do this by specifying the - &implicit-cache; option on the command line: - - - - - scons -Q --implicit-cache hello - scons -Q hello - - - - - If you don't want to specify &implicit-cache; - on the command line each time, - you can make it the default behavior for your build - by setting the &implicit_cache; option - in an &SConscript; file: - - - - - SetOption('implicit_cache', 1) - - - - - &SCons; does not cache implicit dependencies like this by default - because the &implicit-cache; causes &SCons; to simply use the implicit - dependencies stored during the last run, without any checking - for whether or not those dependencies are still correct. - Specifically, this means &implicit-cache; instructs &SCons; - to not rebuild "correctly" in the - following cases: - - - - - - - - - - When &implicit-cache; is used, &SCons; will ignore any changes that - may have been made to search paths - (like &cv-CPPPATH; or &cv-LIBPATH;,). - This can lead to &SCons; not rebuilding a file if a change to - &cv-CPPPATH; would normally cause a different, same-named file from - a different directory to be used. - - - - - - - - When &implicit-cache; is used, &SCons; will not detect if a - same-named file has been added to a directory that is earlier in - the search path than the directory in which the file was found - last time. - - - - - - -
- The &implicit-deps-changed; Option - - - - When using cached implicit dependencies, - sometimes you want to "start fresh" - and have &SCons; re-scan the files - for which it previously cached the dependencies. - For example, - if you have recently installed a new version of - external code that you use for compilation, - the external header files will have changed - and the previously-cached implicit dependencies - will be out of date. - You can update them by - running &SCons; with the &implicit-deps-changed; option: - - - - - scons -Q --implicit-deps-changed hello - scons -Q hello - - - - - In this case, &SCons; will re-scan all of the implicit dependencies - and cache updated copies of the information. - - - -
- -
- The &implicit-deps-unchanged; Option - - - - By default when caching dependencies, - &SCons; notices when a file has been modified - and re-scans the file for any updated - implicit dependency information. - Sometimes, however, you may want - to force &SCons; to use the cached implicit dependencies, - even if the source files changed. - This can speed up a build for example, - when you have changed your source files - but know that you haven't changed - any #include lines. - In this case, - you can use the &implicit-deps-unchanged; option: - - - - - scons -Q --implicit-deps-unchanged hello - scons -Q hello - - - - - In this case, - &SCons; will assume that the cached implicit - dependencies are correct and - will not bother to re-scan changed files. - For typical builds after small, - incremental changes to source files, - the savings may not be very big, - but sometimes every bit of - improved performance counts. - - - -
- - - -
- -
- Explicit Dependencies: the &Depends; Function - - - - Sometimes a file depends on another file - that is not detected by an &SCons; scanner. - For this situation, - &SCons; allows you to specific explicitly that one file - depends on another file, - and must be rebuilt whenever that file changes. - This is specified using the &Depends; method: - - - - - hello = Program('hello.c') - Depends(hello, 'other_file') - - - - - - % scons -Q hello - cc -c hello.c -o hello.o - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - % edit other_file - [CHANGE THE CONTENTS OF other_file] - % scons -Q hello - cc -c hello.c -o hello.o - cc -o hello hello.o - - - - - Note that the dependency - (the second argument to &Depends;) - may also be a list of Node objects - (for example, as returned by a call to a Builder): - - - - - hello = Program('hello.c') - goodbye = Program('goodbye.c') - Depends(hello, goodbye) - - - - - in which case the dependency or dependencies - will be built before the target(s): - - - - - % scons -Q hello - cc -c goodbye.c -o goodbye.o - cc -o goodbye goodbye.o - cc -c hello.c -o hello.o - cc -o hello hello.o - - -
- -
- Dependencies From External Files: the &ParseDepends; - Function - - - - &SCons; has built-in scanners for a number of languages. Sometimes - these scanners fail to extract certain implicit dependencies due - to limitations of the scanner implementation. - - - - - - The following example illustrates a case where the built-in C - scanner is unable to extract the implicit dependency on a header - file. - - - - - - #define FOO_HEADER <foo.h> - #include FOO_HEADER - - int main() { - return FOO; - } - - - Program('hello', 'hello.c', CPPPATH='.') - - - #define FOO 42 - - - - - scons -Q - edit foo.h - scons -Q - - - - - Apparently, the scanner does not know about the header dependency. - Being not a full-fledged C preprocessor, the scanner does not - expand the macro. - - - - - - In these cases, you may also use the compiler to extract the - implicit dependencies. &ParseDepends; can parse the contents of - the compiler output in the style of &Make;, and explicitly - establish all of the listed dependencies. - - - - - - The following example uses &ParseDepends; to process a compiler - generated dependency file which is generated as a side effect - during compilation of the object file: - - - - - - - - #define FOO_HEADER <foo.h> - #include FOO_HEADER - - int main() { - return FOO; - } - - - obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') - SideEffect('hello.d', obj) - ParseDepends('hello.d') - Program('hello', obj) - - - #define FOO 42 - - - hello.o: hello.c foo.h - - - - - scons -Q - edit foo.h - scons -Q - - - - - Parsing dependencies from a compiler-generated - .d file has a chicken-and-egg problem, that - causes unnecessary rebuilds: - - - - - - #define FOO_HEADER <foo.h> - #include FOO_HEADER - - int main() { - return FOO; - } - - - obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') - SideEffect('hello.d', obj) - ParseDepends('hello.d') - Program('hello', obj) - - - #define FOO 42 - - - - - - - % scons -Q - cc -o hello.o -c -MD -MF hello.d -I. hello.c - cc -o hello hello.o - % scons -Q --debug=explain - scons: rebuilding `hello.o' because `foo.h' is a new dependency - cc -o hello.o -c -MD -MF hello.d -I. hello.c - % scons -Q - scons: `.' is up to date. - - - - - In the first pass, the dependency file is generated while the - object file is compiled. At that time, &SCons; does not know about - the dependency on foo.h. In the second pass, - the object file is regenerated because foo.h - is detected as a new dependency. - - - - - - &ParseDepends; immediately reads the specified file at invocation - time and just returns if the file does not exist. A dependency - file generated during the build process is not automatically - parsed again. Hence, the compiler-extracted dependencies are not - stored in the signature database during the same build pass. This - limitation of &ParseDepends; leads to unnecessary recompilations. - Therefore, &ParseDepends; should only be used if scanners are not - available for the employed language or not powerful enough for the - specific task. - - - -
- -
- Ignoring Dependencies: the &Ignore; Function - - - - 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: - - - - - - hello_obj=Object('hello.c') - hello = Program(hello_obj) - Ignore(hello_obj, 'hello.h') - - - #include "hello.h" - int main() { printf("Hello, %s!\n", string); } - - - #define string "world" - - - - - - - - - % scons -Q hello - cc -c -o hello.o hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - % edit hello.h - [CHANGE THE CONTENTS OF hello.h] - % scons -Q hello - scons: `hello' is up to date. - - - - - Now, the above example is a little contrived, - because it's hard to imagine a real-world situation - where you wouldn't want 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: - - - - - hello = Program('hello.c', CPPPATH=['/usr/include']) - Ignore(hello, '/usr/include/stdio.h') - - - - &Ignore; can also be used to prevent a generated file from being built - by default. This is due to the fact that directories depend on - their contents. So to ignore a generated file from the default build, - you specify that the directory should ignore the generated file. - Note that the file will still be built if the user specifically - requests the target on scons command line, or if the file is - a dependency of another file which is requested and/or is built - by default. - - - - - hello_obj=Object('hello.c') - hello = Program(hello_obj) - Ignore('.',[hello,hello_obj]) - - - #include "stdio.h" - int main() { printf("Hello!\n"); } - - - - - scons -Q - scons -Q hello - scons -Q hello - -
- -
- Order-Only Dependencies: the &Requires; Function - - - - Occasionally, - it may be useful to specify that a certain - file or directory must, if necessary, - be built or created before some other target is built, - but that changes to that file or directory - do not - require that the target itself be rebuilt. - Such a relationship is called an - order-only dependency - because it only affects the order in which - things must be built--the dependency before the target--but - it is not a strict dependency relationship - because the target should not - change in response to changes in the dependent file. - - - - - - For example, suppose that you want to create a file - every time you run a build - that identifies the time the build was performed, - the version number, etc., - and which is included in every program that you build. - The version file's contents will change every build. - If you specify a normal dependency relationship, - then every program that depends on - that file would be rebuilt every time you ran &SCons;. - For example, we could use some Python code in - a &SConstruct; file to create a new version.c file - with a string containing the current date every time - we run &SCons;, - and then link a program with the resulting object file - by listing version.c in the sources: - - - - - - import time - - version_c_text = """ - char *date = "%s"; - """ % time.ctime(time.time()) - open('version.c', 'w').write(version_c_text) - - hello = Program(['hello.c', 'version.c']) - - - extern char *date; - int main() { printf("Hello, %s! I was built: %s\n", date); } - - - - - - If we list version.c as an actual source file, - though, then the version.o file - will get rebuilt every time we run &SCons; - (because the &SConstruct; file itself changes - the contents of version.c) - and the hello executable - will get re-linked every time - (because the version.o file changes): - - - - - scons -Q hello - sleep 1 - scons -Q hello - sleep 1 - scons -Q hello - - - - - (Note that for the above example to work, - we &sleep; for one second in between each run, - so that the &SConstruct; file will create a - version.c file with a time string - that's one second later than the previous run.) - - - - - - One solution is to use the &Requires; function - to specify that the version.o - must be rebuilt before it is used by the link step, - but that changes to version.o - should not actually cause the hello - executable to be re-linked: - - - - - - import time - - version_c_text = """ - char *date = "%s"; - """ % time.ctime(time.time()) - open('version.c', 'w').write(version_c_text) - - version_obj = Object('version.c') - - hello = Program('hello.c', - LINKFLAGS = str(version_obj[0])) - - Requires(hello, version_obj) - - - extern char *date; - int main() { printf("Hello, %s! I was built: %s\n", date); } - - - - - - Notice that because we can no longer list version.c - as one of the sources for the hello program, - we have to find some other way to get it into the link command line. - For this example, we're cheating a bit and stuffing the - object file name (extracted from version_obj - list returned by the &b-Object; call) - into the &cv-link-LINKFLAGS; variable, - because &cv-LINKFLAGS; is already included - in the &cv-link-LINKCOM; command line. - - - - - - With these changes, - we get the desired behavior of only - re-linking the hello executable - when the hello.c has changed, - even though the version.o is rebuilt - (because the &SConstruct; file still changes the - version.c contents directly each run): - - - - - scons -Q hello - sleep 1 - scons -Q hello - sleep 1 - edit hello.c - scons -Q hello - sleep 1 - scons -Q hello - - -
- -
- The &AlwaysBuild; Function - - - - How &SCons; handles dependencies can also be affected - by the &AlwaysBuild; method. - When a file is passed to the &AlwaysBuild; method, - like so: - - - - - - hello = Program('hello.c') - AlwaysBuild(hello) - - - int main() { printf("Hello, %s!\n", string); } - - - - - - Then the specified target file (&hello; in our example) - will always be considered out-of-date and - rebuilt whenever that target file is evaluated - while walking the dependency graph: - - - - - scons -Q - scons -Q - - - - - The &AlwaysBuild; function has a somewhat misleading name, - because it does not actually mean the target file will - be rebuilt every single time &SCons; is invoked. - Instead, it means that the target will, in fact, - be rebuilt whenever the target file is encountered - while evaluating the targets specified on - the command line (and their dependencies). - So specifying some other target on the command line, - a target that does not - itself depend on the &AlwaysBuild; target, - will still be rebuilt only if it's out-of-date - with respect to its dependencies: - - - - - scons -Q - scons -Q hello.o - - - - -
- - diff --git a/doc/user/depends.xml b/doc/user/depends.xml index df2a911..f601312 100644 --- a/doc/user/depends.xml +++ b/doc/user/depends.xml @@ -36,15 +36,19 @@ - - - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q - scons: `.' is up to date. - + + + Program('hello.c') + + + int main() { printf("Hello, world!\n"); } + + + + + scons -Q + scons -Q + @@ -57,13 +61,10 @@ - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - + + scons -Q hello + scons -Q hello + @@ -112,14 +113,11 @@ - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % touch hello.c - % scons -Q hello - scons: `hello' is up to date. - + + scons -Q hello + touch hello.c + scons -Q hello + @@ -137,16 +135,11 @@ - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % edit hello.c - [CHANGE THE CONTENTS OF hello.c] - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q hello + edit hello.c + scons -Q hello + @@ -157,10 +150,10 @@ - + Program('hello.c') Decider('MD5') - + @@ -201,16 +194,11 @@ - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % edit hello.c - [CHANGE A COMMENT IN hello.c] - % scons -Q hello - cc -o hello.o -c hello.c - scons: `hello' is up to date. - + + scons -Q hello + edit hello.c + scons -Q hello + @@ -258,10 +246,15 @@ - + + Object('hello.c') Decider('timestamp-newer') - + + + int main() { printf("Hello, world!\n"); } + + @@ -271,13 +264,11 @@ - - % scons -Q hello.o - cc -o hello.o -c hello.c - % touch hello.c - % scons -Q hello.o - cc -o hello.o -c hello.c - + + scons -Q hello.o + touch hello.c + scons -Q hello.o + @@ -289,10 +280,10 @@ - + Object('hello.c') Decider('make') - + @@ -324,10 +315,15 @@ - + + Object('hello.c') Decider('timestamp-match') - + + + int main() { printf("Hello, world!\n"); } + + @@ -341,13 +337,11 @@ - - % scons -Q hello.o - cc -o hello.o -c hello.c - % touch -t 198901010000 hello.c - % scons -Q hello.o - cc -o hello.o -c hello.c - + + scons -Q hello.o + touch -t 198901010000 hello.c + scons -Q hello.o + @@ -380,10 +374,15 @@ - + + Program('hello.c') Decider('MD5-timestamp') - + + + int main() { printf("Hello, world!\n"); } + + @@ -493,7 +492,8 @@ - + + Program('hello.c') def decide_if_changed(dependency, target, prev_ni): if self.get_timestamp() != prev_ni.timestamp: @@ -503,7 +503,11 @@ return True return False Decider(decide_if_changed) - + + + int main() { printf("Hello, world!\n"); } + + @@ -608,7 +612,7 @@ - + env = Environment() def config_file_decider(dependency, target, prev_ni): @@ -623,7 +627,7 @@ if not os.path.exists(str(target.abspath)): return True if dep_csig != prev_ni.csig: - # Some change on source file => update installed one + # Some change on source file => update installed one return True return False @@ -638,7 +642,7 @@ env.Decider(config_file_decider) env.Install("install","test.txt") - + @@ -670,13 +674,26 @@ - + + env1 = Environment(CPPPATH = ['.']) env2 = env1.Clone() env2.Decider('timestamp-match') env1.Program('prog-MD5', 'program1.c') env2.Program('prog-timestamp', 'program2.c') - + + + #include "inc.h" + int main() { printf("Hello, world!\n"); } + + + #include "inc.h" + int main() { printf("Hello, world!\n"); } + + + #define INC 1 + + @@ -690,17 +707,11 @@ - - % scons -Q - cc -o program1.o -c -I. program1.c - cc -o prog-MD5 program1.o - cc -o program2.o -c -I. program2.c - cc -o prog-timestamp program2.o - % touch inc.h - % scons -Q - cc -o program2.o -c -I. program2.c - cc -o prog-timestamp program2.o - + + scons -Q + touch inc.h + scons -Q + @@ -737,10 +748,10 @@ - + Program('hello.c') SourceSignatures('MD5') - + @@ -748,10 +759,10 @@ - + Program('hello.c') SourceSignatures('timestamp') - + @@ -805,10 +816,10 @@ - + Program('hello.c') TargetSignatures('MD5') - + @@ -819,10 +830,10 @@ - + Program('hello.c') TargetSignatures('timestamp') - + @@ -848,11 +859,11 @@ - + Program('hello.c') TargetSignatures('source') SourceSignatures('timestamp') - + @@ -914,14 +925,22 @@ - + + + Program('hello.c', CPPPATH = '.') + + #include <hello.h> int main() { printf("Hello, %s!\n", string); } - + + + #define string "world" + + @@ -929,10 +948,8 @@ - - - #define string "world" - + + @@ -944,10 +961,8 @@ - - - Program('hello.c', CPPPATH = '.') - + + @@ -960,18 +975,12 @@ - - % scons -Q hello - cc -o hello.o -c -I. hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - % edit hello.h - [CHANGE THE CONTENTS OF hello.h] - % scons -Q hello - cc -o hello.o -c -I. hello.c - cc -o hello hello.o - + + scons -Q hello + scons -Q hello + edit hello.h + scons -Q hello + @@ -1016,9 +1025,14 @@ - + + Program('hello.c', CPPPATH = ['include', '/home/project/inc']) - + + + int main() { printf("Hello, world!\n"); } + + @@ -1026,11 +1040,9 @@ - - % scons -Q hello - cc -o hello.o -c -Iinclude -I/home/project/inc hello.c - cc -o hello hello.o - + + scons -Q hello + @@ -1038,12 +1050,9 @@ - - C:\>scons -Q hello.exe - cl /Fohello.obj /c hello.c /nologo /Iinclude /I\home\project\inc - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - + + scons -Q hello.exe + @@ -1095,13 +1104,10 @@ - - % scons -Q --implicit-cache hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - + + scons -Q --implicit-cache hello + scons -Q hello + @@ -1113,9 +1119,9 @@ - + SetOption('implicit_cache', 1) - + @@ -1178,13 +1184,10 @@ - - % scons -Q --implicit-deps-changed hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - + + scons -Q --implicit-deps-changed hello + scons -Q hello + @@ -1216,13 +1219,10 @@ - - % scons -Q --implicit-deps-unchanged hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - + + scons -Q --implicit-deps-unchanged hello + scons -Q hello + @@ -1340,24 +1340,29 @@ - + + #define FOO_HEADER <foo.h> #include FOO_HEADER int main() { return FOO; } - - - - % scons -Q - cc -o hello.o -c -I. hello.c - cc -o hello hello.o - % edit foo.h - [CHANGE CONTENTS OF foo.h] - % scons -Q - scons: `.' is up to date. - + + + Program('hello', 'hello.c', CPPPATH='.') + + + #define FOO 42 + + + + + scons -Q + edit foo.h + scons -Q + @@ -1388,22 +1393,35 @@ priori specification of the dependency file. The produced hello.d file is not found (or used) for unknown reasons. --> - + + + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') SideEffect('hello.d', obj) ParseDepends('hello.d') Program('hello', obj) - - - - % scons -Q - cc -o hello.o -c -MD -MF hello.d -I. hello.c - cc -o hello hello.o - % edit foo.h - [CHANGE CONTENTS OF foo.h] - % scons -Q - cc -o hello.o -c -MD -MF hello.d -I. hello.c - + + + #define FOO 42 + + + hello.o: hello.c foo.h + + + + + scons -Q + edit foo.h + scons -Q + @@ -1413,7 +1431,25 @@ - + + + #define FOO_HEADER <foo.h> + #include FOO_HEADER + + int main() { + return FOO; + } + + + obj = Object('hello.c', CCFLAGS='-MD -MF hello.d', CPPPATH='.') + SideEffect('hello.d', obj) + ParseDepends('hello.d') + Program('hello', obj) + + + #define FOO 42 + + @@ -1541,21 +1586,23 @@ by default. - + + hello_obj=Object('hello.c') hello = Program(hello_obj) Ignore('.',[hello,hello_obj]) - - - - % scons -Q - scons: `.' is up to date. - % scons -Q hello - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello - scons: `hello' is up to date. - + + + #include "stdio.h" + int main() { printf("Hello!\n"); } + + + + + scons -Q + scons -Q hello + scons -Q hello +
@@ -1600,7 +1647,8 @@ - + + import time version_c_text = """ @@ -1609,7 +1657,12 @@ open('version.c', 'w').write(version_c_text) hello = Program(['hello.c', 'version.c']) - + + + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + + @@ -1624,20 +1677,13 @@ - - % scons -Q hello - cc -o hello.o -c hello.c - cc -o version.o -c version.c - cc -o hello hello.o version.o - % sleep 1 - % scons -Q hello - cc -o version.o -c version.c - cc -o hello hello.o version.o - % sleep 1 - % scons -Q hello - cc -o version.o -c version.c - cc -o hello hello.o version.o - + + scons -Q hello + sleep 1 + scons -Q hello + sleep 1 + scons -Q hello + @@ -1660,7 +1706,8 @@ - + + import time version_c_text = """ @@ -1674,7 +1721,12 @@ LINKFLAGS = str(version_obj[0])) Requires(hello, version_obj) - + + + extern char *date; + int main() { printf("Hello, %s! I was built: %s\n", date); } + + @@ -1702,27 +1754,16 @@ - - % scons -Q hello - cc -o version.o -c version.c - cc -o hello.o -c hello.c - cc -o hello version.o hello.o - % sleep 1 - % scons -Q hello - cc -o version.o -c version.c - scons: `hello' is up to date. - % sleep 1 - % edit hello.c - [CHANGE THE CONTENTS OF hello.c] - % scons -Q hello - cc -o version.o -c version.c - cc -o hello.o -c hello.c - cc -o hello version.o hello.o - % sleep 1 - % scons -Q hello - cc -o version.o -c version.c - scons: `hello' is up to date. - + + scons -Q hello + sleep 1 + scons -Q hello + sleep 1 + edit hello.c + scons -Q hello + sleep 1 + scons -Q hello +
@@ -1738,10 +1779,15 @@ - + + hello = Program('hello.c') AlwaysBuild(hello) - + + + int main() { printf("Hello, %s!\n", string); } + + @@ -1752,13 +1798,10 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q - cc -o hello hello.o - + + scons -Q + scons -Q + @@ -1777,13 +1820,10 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q hello.o - scons: `hello.o' is up to date. - + + scons -Q + scons -Q hello.o + - - - - - - An environment - 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: - - - - - - - External Environment - - - - - The external environment - 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 os.environ dictionary. - See , below. - - - - - - - &ConsEnv; - - - - - 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 , below. - - - - - - - Execution Environment - - - - - An execution environment - 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 external environment - (see above). - See , below. - - - - - - - - - - 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 compiler or build option to be used, - but the checked-in change breaks the official build - because it uses different environment variable settings. - - - - - - 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 not - 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. - - - -
- Using Values From the External Environment - - - - The external environment - variable settings that - the user has in force - when executing &SCons; - are available through the normal Python - os.environ - dictionary. - This means that you must add an - import os statement - to any &SConscript; file - in which you want to use - values from the user's external environment. - - - - - - import os - - - int main() { } - - - - - - More usefully, you can use the - os.environ - dictionary in your &SConscript; - files to initialize &consenvs; - with values from the user's external environment. - See the next section, - , - for information on how to do this. - - - -
- -
- Construction Environments - - - - 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.) - - - -
- Creating a &ConsEnv;: the &Environment; Function - - - - A &consenv; is created by the &Environment; method: - - - - - env = Environment() - - - - - 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. - - - - - - 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: - - - - - - env = Environment(CC = 'gcc', - CCFLAGS = '-O2') - - env.Program('foo.c') - - - int main() { } - - - - - - 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 -O2 - (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: - - - - - scons -Q - - -
- -
- Fetching Values From a &ConsEnv; - - - - You can fetch individual construction variables - using the normal syntax - for accessing individual named items in a Python dictionary: - - - - - - env = Environment() - print "CC is:", env['CC'] - - - - - - 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: - - - - - scons -Q - - - - - 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: - - - - - - env = Environment(FOO = 'foo', BAR = 'bar') - dict = env.Dictionary() - for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: - print "key = %s, value = %s" % (key, dict[key]) - - - - - - This &SConstruct; file - will print the specified dictionary items for us on POSIX - systems as follows: - - - - - scons -Q - - - - - And on Windows: - - - - - scons -Q - - - - - 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: - - - - - env = Environment() - for item in sorted(env.Dictionary().items()): - print "construction variable = '%s', value = '%s'" % item - - -
- -
- Expanding Values From a &ConsEnv;: the &subst; Method - - - - 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 - env['CC'] - to fetch the value of &cv-link-CC; - could also be written as: - - - - - env = Environment() - print "CC is:", env.subst('$CC') - - - - - 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;: - - - - - env = Environment(CCFLAGS = '-DFOO') - print "CCCOM is:", env['CCCOM'] - - - - - Will print the unexpanded value of &cv-CCCOM;, - showing us the construction - variables that still need to be expanded: - - - - - % scons -Q - CCCOM is: $CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES - scons: `.' is up to date. - - - - - Calling the &subst; method on $CCOM, - however: - - - - - env = Environment(CCFLAGS = '-DFOO') - print "CCCOM is:", env.subst('$CCCOM') - - - - - Will recursively expand all of - the construction variables prefixed - with $ (dollar signs), - showing us the final output: - - - - - % scons -Q - CCCOM is: gcc -DFOO -c -o - scons: `.' is up to date. - - - - - 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. - - - -
- -
- Handling Problems With Value Expansion - - - - If a problem occurs when expanding a construction variable, - by default it is expanded to '' - (a null string), and will not cause scons to fail. - - - - - env = Environment() - print "value is:", env.subst( '->$MISSING<-' ) - - - - - scons -Q - - - - This default behaviour can be changed using the &AllowSubstExceptions; - function. - When a problem occurs with a variable expansion it generates - an exception, and the &AllowSubstExceptions; function controls - which of these exceptions are actually fatal and which are - allowed to occur safely. By default, &NameError; and &IndexError; - are the two exceptions that are allowed to occur: so instead of - causing scons to fail, these are caught, the variable expanded to - '' - and scons execution continues. - To require that all construction variable names exist, and that - indexes out of range are not allowed, call &AllowSubstExceptions; - with no extra arguments. - - - - - AllowSubstExceptions() - env = Environment() - print "value is:", env.subst( '->$MISSING<-' ) - - - - - scons -Q - - - - This can also be used to allow other exceptions that might occur, - most usefully with the ${...} construction - variable syntax. For example, this would allow zero-division to - occur in a variable expansion in addition to the default exceptions - allowed - - - - - AllowSubstExceptions(IndexError, NameError, ZeroDivisionError) - env = Environment() - print "value is:", env.subst( '->${1 / 0}<-' ) - - - - - scons -Q - - - - - - If &AllowSubstExceptions; is called multiple times, each call - completely overwrites the previous list of allowed exceptions. - - -
- -
- Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function - - - - 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. - - - - - - You can, however, control the settings - in the default construction environment - by using the &DefaultEnvironment; function - to initialize various settings: - - - - - - DefaultEnvironment(CC = '/usr/local/bin/gcc') - - - - - - When configured as above, - all calls to the &Program; - or &Object; Builder - will build object files with the - /usr/local/bin/gcc - compiler. - - - - - - 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 /usr/local/bin/gcc - but as a separate step after - the default construction environment has been initialized: - - - - - - env = DefaultEnvironment() - env['CC'] = '/usr/local/bin/gcc' - - - - - - 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: - - - - - - env = DefaultEnvironment(tools = ['gcc', 'gnulink'], - CC = '/usr/local/bin/gcc') - - - - - - 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 - /usr/local/bin/gcc. - - - -
- -
- Multiple &ConsEnvs; - - - - 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 -O2 flag - and another with the -g (debug) flag, - we would do this like so: - - - - - - opt = Environment(CCFLAGS = '-O2') - dbg = Environment(CCFLAGS = '-g') - - opt.Program('foo', 'foo.c') - - dbg.Program('bar', 'bar.c') - - - int main() { } - - - int main() { } - - - - - scons -Q - - - - - 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: - - - - - - opt = Environment(CCFLAGS = '-O2') - dbg = Environment(CCFLAGS = '-g') - - opt.Program('foo', 'foo.c') - - dbg.Program('foo', 'foo.c') - - - int main() { } - - - - - - Then &SCons; generates the following error: - - - - - scons -Q - - - - - This is because the two &b-Program; calls have - each implicitly told &SCons; to generate an object file named - foo.o, - one with a &cv-link-CCFLAGS; value of - -O2 - and one with a &cv-link-CCFLAGS; value of - -g. - &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 - foo.c - to a separately-named object file - using the &b-link-Object; builder, like so: - - - - - - 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) - - - int main() { } - - - - - - 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: - - - - - scons -Q - - -
- -
- Making Copies of &ConsEnvs;: the &Clone; Method - - - - 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. - - - - - - 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: - - - - - - 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) - - - int main() { } - - - - - - Then our output would look like: - - - - - scons -Q - - -
- -
- Replacing Values: the &Replace; Method - - - - You can replace existing construction variable values - using the &Replace; method: - - - - - - env = Environment(CCFLAGS = '-DDEFINE1') - env.Replace(CCFLAGS = '-DDEFINE2') - env.Program('foo.c') - - - int main() { } - - - - - - The replacing value - (-DDEFINE2 in the above example) - completely replaces the value in the - construction environment: - - - - - scons -Q - - - - - You can safely call &Replace; - for construction variables that - don't exist in the construction environment: - - - - - - env = Environment() - env.Replace(NEW_VARIABLE = 'xyzzy') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - - - - - - In this case, - the construction variable simply - gets added to the construction environment: - - - - - scons -Q - - - - - 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: - - - - - - env = Environment(CCFLAGS = '-DDEFINE1') - print "CCFLAGS =", env['CCFLAGS'] - env.Program('foo.c') - - env.Replace(CCFLAGS = '-DDEFINE2') - print "CCFLAGS =", env['CCFLAGS'] - env.Program('bar.c') - - - int main() { } - - - int main() { } - - - - - - The timing of when the replacement - actually occurs relative - to when the targets get built - becomes apparent - if we run &scons; without the -Q - option: - - - - - scons - - - - - Because the replacement occurs while - the &SConscript; files are being read, - the &cv-link-CCFLAGS; - variable has already been set to - -DDEFINE2 - 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. - - - -
- -
- Setting Values Only If They're Not Already Defined: the &SetDefault; Method - - - - 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 set_default - method of Python dictionary objects: - - - - - env.SetDefault(SPECIAL_FLAG = '-extra-option') - - - - - This is especially useful - when writing your own Tool modules - to apply variables to construction environments. - - - - -
- -
- Appending to the End of Values: the &Append; Method - - - - You can append a value to - an existing construction variable - using the &Append; method: - - - - - - env = Environment(CCFLAGS = ['-DMY_VALUE']) - env.Append(CCFLAGS = ['-DLAST']) - env.Program('foo.c') - - - int main() { } - - - - - - &SCons; then supplies both the -DMY_VALUE and - -DLAST flags when compiling the object file: - - - - - scons -Q - - - - - If the construction variable doesn't already exist, - the &Append; method will create it: - - - - - - env = Environment() - env.Append(NEW_VARIABLE = 'added') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - - - - - - Which yields: - - - - - scons -Q - - - - - 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. - - - -
- -
- Appending Unique Values: the &AppendUnique; 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: - - - - - env.AppendUnique(CCFLAGS=['-g']) - - - - - In the above example, - the -g would be added - only if the &cv-CCFLAGS; variable - does not already contain a -g value. - - - -
- -
- Appending to the Beginning of Values: the &Prepend; Method - - - - You can append a value to the beginning of - an existing construction variable - using the &Prepend; method: - - - - - - env = Environment(CCFLAGS = ['-DMY_VALUE']) - env.Prepend(CCFLAGS = ['-DFIRST']) - env.Program('foo.c') - - - int main() { } - - - - - - &SCons; then supplies both the -DFIRST and - -DMY_VALUE flags when compiling the object file: - - - - - scons -Q - - - - - If the construction variable doesn't already exist, - the &Prepend; method will create it: - - - - - - env = Environment() - env.Prepend(NEW_VARIABLE = 'added') - print "NEW_VARIABLE =", env['NEW_VARIABLE'] - - - - - - Which yields: - - - - - scons -Q - - - - - 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. - - - -
- -
- Prepending Unique Values: the &PrependUnique; Method - - - - 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: - - - - - env.PrependUnique(CCFLAGS=['-g']) - - - - - In the above example, - the -g would be added - only if the &cv-CCFLAGS; variable - does not already contain a -g value. - - - -
- -
- -
- Controlling the Execution Environment for Issued Commands - - - - 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. - - - - - - 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. - - - - - - The default value of the &PATH; environment variable - on a POSIX system - is /usr/local/bin:/bin:/usr/bin. - 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. - - - - - - 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: - - - - - path = ['/usr/local/bin', '/bin', '/usr/bin'] - env = Environment(ENV = {'PATH' : path}) - - - - - 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: - - - - - env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin'] - - - - - 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): - - - - - env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' - - - - - 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). - - - - - -
- Propagating &PATH; From the External Environment - - - - 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 os.environ - dictionary, - which is Python's way of letting you - get at the external environment: - - - - - import os - env = Environment(ENV = {'PATH' : os.environ['PATH']}) - - - - - 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: - - - - - import os - env = Environment(ENV = os.environ) - - - - - 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 /bin and - /usr/local/bin 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. - - - -
- -
- Adding to <varname>PATH</varname> Values in the Execution Environment - - - - 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 $PATH variable on Linux or POSIX systems, - or the %PATH% 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 /usr/local directories - to the $PATH and $LIB variables, - you might: - - - - - env = Environment(ENV = os.environ) - env.PrependENVPath('PATH', '/usr/local/bin') - env.AppendENVPath('LIB', '/usr/local/lib') - - - - - Note that the added values are strings, - and if you want to add multiple directories to - a variable like $PATH, - you must include the path separate character - (: on Linux or POSIX, - ; on Windows) - in the string. - - - -
- -
diff --git a/doc/user/environments.xml b/doc/user/environments.xml index eaf4ba3..9f39347 100644 --- a/doc/user/environments.xml +++ b/doc/user/environments.xml @@ -466,9 +466,14 @@ environment, of directory names, suffixes, etc. - + + import os - + + + int main() { } + + @@ -518,9 +523,9 @@ environment, of directory names, suffixes, etc. - + env = Environment() - + @@ -550,14 +555,17 @@ environment, of directory names, suffixes, etc. - - import os - + + env = Environment(CC = 'gcc', CCFLAGS = '-O2') env.Program('foo.c') - + + + int main() { } + + @@ -577,11 +585,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - gcc -o foo.o -c -O2 foo.c - gcc -o foo foo.o - + + scons -Q + @@ -596,10 +602,12 @@ environment, of directory names, suffixes, etc. - + + env = Environment() print "CC is:", env['CC'] - + + @@ -609,11 +617,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - CC is: cc - scons: `.' is up to date. - + + scons -Q + @@ -625,12 +631,14 @@ environment, of directory names, suffixes, etc. - + + env = Environment(FOO = 'foo', BAR = 'bar') dict = env.Dictionary() for key in ['OBJSUFFIX', 'LIBSUFFIX', 'PROGSUFFIX']: print "key = %s, value = %s" % (key, dict[key]) - + + @@ -640,13 +648,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - key = OBJSUFFIX, value = .o - key = LIBSUFFIX, value = .a - key = PROGSUFFIX, value = - scons: `.' is up to date. - + + scons -Q + @@ -654,13 +658,9 @@ environment, of directory names, suffixes, etc. - - C:\>scons -Q - key = OBJSUFFIX, value = .obj - key = LIBSUFFIX, value = .lib - key = PROGSUFFIX, value = .exe - scons: `.' is up to date. - + + scons -Q + @@ -670,11 +670,11 @@ environment, of directory names, suffixes, etc. - + env = Environment() for item in sorted(env.Dictionary().items()): print "construction variable = '%s', value = '%s'" % item - + @@ -697,10 +697,10 @@ environment, of directory names, suffixes, etc. - + env = Environment() print "CC is:", env.subst('$CC') - + @@ -714,10 +714,10 @@ environment, of directory names, suffixes, etc. - + env = Environment(CCFLAGS = '-DFOO') print "CCCOM is:", env['CCCOM'] - + @@ -740,10 +740,10 @@ environment, of directory names, suffixes, etc. - + env = Environment(CCFLAGS = '-DFOO') print "CCCOM is:", env.subst('$CCCOM') - + @@ -781,16 +781,16 @@ environment, of directory names, suffixes, etc. (a null string), and will not cause scons to fail. - + + env = Environment() - print "value is:", env.subst( '->$MISSING<-' ) - + print "value is:", env.subst( '->$MISSING<-' ) + + - - % scons -Q - value is: -><- - scons: `.' is up to date. - + + scons -Q + This default behaviour can be changed using the &AllowSubstExceptions; @@ -808,18 +808,17 @@ environment, of directory names, suffixes, etc. with no extra arguments. - + + AllowSubstExceptions() env = Environment() - print "value is:", env.subst( '->$MISSING<-' ) - + print "value is:", env.subst( '->$MISSING<-' ) + + - - % scons -Q - value is: - scons: *** NameError `MISSING' trying to evaluate `$MISSING' - File "/home/my/project/SConstruct", line 3, in <module> - + + scons -Q + This can also be used to allow other exceptions that might occur, @@ -829,19 +828,19 @@ environment, of directory names, suffixes, etc. allowed - + + AllowSubstExceptions(IndexError, NameError, ZeroDivisionError) env = Environment() - print "value is:", env.subst( '->${1 / 0}<-' ) - + print "value is:", env.subst( '->${1 / 0}<-' ) + + - - % scons -Q - value is: -><- - scons: `.' is up to date. - - - + + scons -Q + + + If &AllowSubstExceptions; is called multiple times, each call @@ -881,11 +880,11 @@ environment, of directory names, suffixes, etc. - + DefaultEnvironment(CC = '/usr/local/bin/gcc') - + @@ -915,12 +914,12 @@ environment, of directory names, suffixes, etc. - + env = DefaultEnvironment() env['CC'] = '/usr/local/bin/gcc' - + @@ -944,12 +943,12 @@ environment, of directory names, suffixes, etc. - + env = DefaultEnvironment(tools = ['gcc', 'gnulink'], CC = '/usr/local/bin/gcc') - + @@ -982,22 +981,26 @@ environment, of directory names, suffixes, etc. - + + opt = Environment(CCFLAGS = '-O2') dbg = Environment(CCFLAGS = '-g') opt.Program('foo', 'foo.c') dbg.Program('bar', 'bar.c') - - - - % scons -Q - 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 - + + + int main() { } + + + int main() { } + + + + + scons -Q + @@ -1009,14 +1012,19 @@ environment, of directory names, suffixes, etc. - + + opt = Environment(CCFLAGS = '-O2') dbg = Environment(CCFLAGS = '-g') opt.Program('foo', 'foo.c') dbg.Program('foo', 'foo.c') - + + + int main() { } + + @@ -1024,12 +1032,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - - scons: *** Two environments with different actions were specified for the same target: foo.o - File "/home/my/project/SConstruct", line 6, in <module> - + + scons -Q + @@ -1052,7 +1057,8 @@ environment, of directory names, suffixes, etc. - + + opt = Environment(CCFLAGS = '-O2') dbg = Environment(CCFLAGS = '-g') @@ -1061,7 +1067,11 @@ environment, of directory names, suffixes, etc. d = dbg.Object('foo-dbg', 'foo.c') dbg.Program(d) - + + + int main() { } + + @@ -1079,13 +1089,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - 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 - + + scons -Q + @@ -1119,7 +1125,8 @@ environment, of directory names, suffixes, etc. - + + env = Environment(CC = 'gcc') opt = env.Clone(CCFLAGS = '-O2') dbg = env.Clone(CCFLAGS = '-g') @@ -1131,7 +1138,11 @@ environment, of directory names, suffixes, etc. d = dbg.Object('foo-dbg', 'foo.c') dbg.Program(d) - + + + int main() { } + + @@ -1139,15 +1150,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - 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 - + + scons -Q + @@ -1161,11 +1166,16 @@ environment, of directory names, suffixes, etc. - + + env = Environment(CCFLAGS = '-DDEFINE1') env.Replace(CCFLAGS = '-DDEFINE2') env.Program('foo.c') - + + + int main() { } + + @@ -1176,11 +1186,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - cc -o foo.o -c -DDEFINE2 foo.c - cc -o foo foo.o - + + scons -Q + @@ -1190,11 +1198,13 @@ environment, of directory names, suffixes, etc. - + + env = Environment() env.Replace(NEW_VARIABLE = 'xyzzy') print "NEW_VARIABLE =", env['NEW_VARIABLE'] - + + @@ -1204,11 +1214,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - NEW_VARIABLE = xyzzy - scons: `.' is up to date. - + + scons -Q + @@ -1226,7 +1234,8 @@ environment, of directory names, suffixes, etc. - + + env = Environment(CCFLAGS = '-DDEFINE1') print "CCFLAGS =", env['CCFLAGS'] env.Program('foo.c') @@ -1234,7 +1243,14 @@ environment, of directory names, suffixes, etc. env.Replace(CCFLAGS = '-DDEFINE2') print "CCFLAGS =", env['CCFLAGS'] env.Program('bar.c') - + + + int main() { } + + + int main() { } + + @@ -1247,19 +1263,9 @@ environment, of directory names, suffixes, etc. - - % scons - 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. - + + scons + @@ -1292,9 +1298,9 @@ environment, of directory names, suffixes, etc. - + env.SetDefault(SPECIAL_FLAG = '-extra-option') - + @@ -1322,11 +1328,16 @@ environment, of directory names, suffixes, etc. - + + env = Environment(CCFLAGS = ['-DMY_VALUE']) env.Append(CCFLAGS = ['-DLAST']) env.Program('foo.c') - + + + int main() { } + + @@ -1335,11 +1346,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - cc -o foo.o -c -DMY_VALUE -DLAST foo.c - cc -o foo foo.o - + + scons -Q + @@ -1348,11 +1357,13 @@ environment, of directory names, suffixes, etc. - + + env = Environment() env.Append(NEW_VARIABLE = 'added') print "NEW_VARIABLE =", env['NEW_VARIABLE'] - + + @@ -1360,11 +1371,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - NEW_VARIABLE = added - scons: `.' is up to date. - + + scons -Q + @@ -1393,9 +1402,9 @@ environment, of directory names, suffixes, etc. - + env.AppendUnique(CCFLAGS=['-g']) - + @@ -1419,11 +1428,16 @@ environment, of directory names, suffixes, etc. - + + env = Environment(CCFLAGS = ['-DMY_VALUE']) env.Prepend(CCFLAGS = ['-DFIRST']) env.Program('foo.c') - + + + int main() { } + + @@ -1432,11 +1446,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - cc -o foo.o -c -DFIRST -DMY_VALUE foo.c - cc -o foo foo.o - + + scons -Q + @@ -1445,11 +1457,13 @@ environment, of directory names, suffixes, etc. - + + env = Environment() env.Prepend(NEW_VARIABLE = 'added') print "NEW_VARIABLE =", env['NEW_VARIABLE'] - + + @@ -1457,11 +1471,9 @@ environment, of directory names, suffixes, etc. - - % scons -Q - NEW_VARIABLE = added - scons: `.' is up to date. - + + scons -Q + @@ -1492,9 +1504,9 @@ environment, of directory names, suffixes, etc. - + env.PrependUnique(CCFLAGS=['-g']) - + @@ -1563,10 +1575,10 @@ environment, of directory names, suffixes, etc. - + path = ['/usr/local/bin', '/bin', '/usr/bin'] env = Environment(ENV = {'PATH' : path}) - + @@ -1583,9 +1595,9 @@ environment, of directory names, suffixes, etc. - + env['ENV']['PATH'] = ['/usr/local/bin', '/bin', '/usr/bin'] - + @@ -1596,9 +1608,9 @@ environment, of directory names, suffixes, etc. - + env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' - + @@ -1654,10 +1666,10 @@ environment, of directory names, suffixes, etc. - + import os env = Environment(ENV = {'PATH' : os.environ['PATH']}) - + @@ -1670,10 +1682,10 @@ environment, of directory names, suffixes, etc. - + import os env = Environment(ENV = os.environ) - + @@ -1717,11 +1729,11 @@ environment, of directory names, suffixes, etc. - + env = Environment(ENV = os.environ) env.PrependENVPath('PATH', '/usr/local/bin') env.AppendENVPath('LIB', '/usr/local/lib') - + diff --git a/doc/user/errors.in b/doc/user/errors.in deleted file mode 100644 index 0891bf8..0000000 --- a/doc/user/errors.in +++ /dev/null @@ -1,41 +0,0 @@ - - - - - XXX - - - -
- XXX - - - - XXX - - - -
diff --git a/doc/user/example.in b/doc/user/example.in deleted file mode 100644 index 0891bf8..0000000 --- a/doc/user/example.in +++ /dev/null @@ -1,41 +0,0 @@ - - - - - XXX - - - -
- XXX - - - - XXX - - - -
diff --git a/doc/user/factories.in b/doc/user/factories.in deleted file mode 100644 index cbe313a..0000000 --- a/doc/user/factories.in +++ /dev/null @@ -1,507 +0,0 @@ - - - - - &SCons; provides a number of platform-independent functions, - called factories, - that perform common file system manipulations - like copying, moving or deleting files and directories, - or making directories. - These functions are factories - because they don't perform the action - at the time they're called, - they each return an &Action; object - that can be executed at the appropriate time. - - - -
- Copying Files or Directories: The &Copy; Factory - - - - Suppose you want to arrange to make a copy of a file, - and don't have a suitable pre-existing builder. - - - Unfortunately, in the early days of SCons design, - we used the name &Copy; for the function that - returns a copy of the environment, - otherwise that would be the logical choice for - a Builder that copies a file or directory tree - to a target location. - - - One way would be to use the &Copy; action factory - in conjunction with the &Command; builder: - - - - - - Command("file.out", "file.in", Copy("$TARGET", "$SOURCE")) - - file.in - - - - - Notice that the action returned by the &Copy; factory - will expand the &cv-link-TARGET; and &cv-link-SOURCE; strings - at the time &file_out; is built, - and that the order of the arguments - is the same as that of a builder itself--that is, - target first, followed by source: - - - - - scons -Q - - - - - You can, of course, name a file explicitly - instead of using &cv-TARGET; or &cv-SOURCE;: - - - - - - Command("file.out", [], Copy("$TARGET", "file.in")) - - file.in - - - - - Which executes as: - - - - - scons -Q - - - - - The usefulness of the &Copy; factory - becomes more apparent when - you use it in a list of actions - passed to the &Command; builder. - For example, suppose you needed to run a - file through a utility that only modifies files in-place, - and can't "pipe" input to output. - One solution is to copy the source file - to a temporary file name, - run the utility, - and then copy the modified temporary file to the target, - which the &Copy; factory makes extremely easy: - - - - - - Command("file.out", "file.in", - [ - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Copy("$TARGET", "tempfile"), - ]) - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - file.in - - touch $* - - - - - - The output then looks like: - - - - - scons -Q - - -
- -
- Deleting Files or Directories: The &Delete; Factory - - - - If you need to delete a file, - then the &Delete; factory - can be used in much the same way as - the &Copy; factory. - For example, if we want to make sure that - the temporary file - in our last example doesn't exist before - we copy to it, - we could add &Delete; to the beginning - of the command list: - - - - - - Command("file.out", "file.in", - [ - Delete("tempfile"), - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Copy("$TARGET", "tempfile"), - ]) - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - file.in - - touch $* - - - - - - Which then executes as follows: - - - - - scons -Q - - - - - Of course, like all of these &Action; factories, - the &Delete; factory also expands - &cv-link-TARGET; and &cv-link-SOURCE; variables appropriately. - For example: - - - - - - Command("file.out", "file.in", - [ - Delete("$TARGET"), - Copy("$TARGET", "$SOURCE") - ]) - - file.in - - - - - Executes as: - - - - - scons -Q - - - - - Note, however, that you typically don't need to - call the &Delete; factory explicitly in this way; - by default, &SCons; deletes its target(s) - for you before executing any action. - - - - - - One word of caution about using the &Delete; factory: - it has the same variable expansions available - as any other factory, including the &cv-SOURCE; variable. - Specifying Delete("$SOURCE") - is not something you usually want to do! - - - -
- -
- Moving (Renaming) Files or Directories: The &Move; Factory - - - - The &Move; factory - allows you to rename a file or directory. - For example, if we don't want to copy the temporary file, - we could use: - - - - - - Command("file.out", "file.in", - [ - Copy("tempfile", "$SOURCE"), - "modify tempfile", - Move("$TARGET", "tempfile"), - ]) - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - file.in - - touch $* - - - - - - Which would execute as: - - - - - scons -Q - - -
- -
- Updating the Modification Time of a File: The &Touch; Factory - - - - If you just need to update the - recorded modification time for a file, - use the &Touch; factory: - - - - - - Command("file.out", "file.in", - [ - Copy("$TARGET", "$SOURCE"), - Touch("$TARGET"), - ]) - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - file.in - - - - - Which executes as: - - - - - scons -Q - - -
- -
- Creating a Directory: The &Mkdir; Factory - - - - If you need to create a directory, - use the &Mkdir; factory. - For example, if we need to process - a file in a temporary directory - in which the processing tool - will create other files that we don't care about, - you could use: - - - - - - Command("file.out", "file.in", - [ - Delete("tempdir"), - Mkdir("tempdir"), - Copy("tempdir/${SOURCE.file}", "$SOURCE"), - "process tempdir", - Move("$TARGET", "tempdir/output_file"), - Delete("tempdir"), - ]) - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - file.in - - touch $* - - - - - - Which executes as: - - - - - scons -Q - - -
- -
- Changing File or Directory Permissions: The &Chmod; Factory - - - - To change permissions on a file or directory, - use the &Chmod; factory. - The permission argument uses POSIX-style - permission bits and should typically - be expressed as an octal, - not decimal, number: - - - - - - Command("file.out", "file.in", - [ - Copy("$TARGET", "$SOURCE"), - Chmod("$TARGET", 0755), - ]) - - file.in - - - - - Which executes: - - - - - scons -Q - - -
- -
- Executing an action immediately: the &Execute; Function - - - - We've been showing you how to use &Action; factories - in the &Command; function. - You can also execute an &Action; returned by a factory - (or actually, any &Action;) - at the time the &SConscript; file is read - by using the &Execute; function. - For example, if we need to make sure that - a directory exists before we build any targets, - - - - - - Execute(Mkdir('__ROOT__/tmp/my_temp_directory')) - - - - - - Notice that this will - create the directory while - the &SConscript; file is being read: - - - - - scons - - - - - If you're familiar with Python, - you may wonder why you would want to use this - instead of just calling the native Python - os.mkdir() function. - The advantage here is that the &Mkdir; - action will behave appropriately if the user - specifies the &SCons; or - options--that is, - it will print the action but not actually - make the directory when is specified, - or make the directory but not print the action - when is specified. - - - - - - The &Execute; function returns the exit status - or return value of the underlying action being executed. - It will also print an error message if the action - fails and returns a non-zero value. - &SCons; will not, however, - actually stop the build if the action fails. - If you want the build to stop - in response to a failure in an action called by &Execute;, - you must do so by explicitly - checking the return value - and calling the &Exit; function - (or a Python equivalent): - - - - - if Execute(Mkdir('__ROOT__/tmp/my_temp_directory')): - # A problem occurred while making the temp directory. - Exit(1) - - -
diff --git a/doc/user/factories.xml b/doc/user/factories.xml index f6ea89d..cbe313a 100644 --- a/doc/user/factories.xml +++ b/doc/user/factories.xml @@ -60,9 +60,12 @@
- + + Command("file.out", "file.in", Copy("$TARGET", "$SOURCE")) - + + file.in + @@ -75,10 +78,9 @@ - - % scons -Q - Copy("file.out", "file.in") - + + scons -Q + @@ -87,9 +89,12 @@ - + + Command("file.out", [], Copy("$TARGET", "file.in")) - + + file.in + @@ -97,10 +102,9 @@ - - % scons -Q - Copy("file.out", "file.in") - + + scons -Q + @@ -119,14 +123,26 @@ - + + Command("file.out", "file.in", [ Copy("tempfile", "$SOURCE"), "modify tempfile", Copy("$TARGET", "tempfile"), ]) - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + file.in + + touch $* + + @@ -134,12 +150,9 @@ - - % scons -Q - Copy("tempfile", "file.in") - modify tempfile - Copy("file.out", "tempfile") - + + scons -Q + @@ -161,7 +174,8 @@ - + + Command("file.out", "file.in", [ Delete("tempfile"), @@ -169,7 +183,18 @@ "modify tempfile", Copy("$TARGET", "tempfile"), ]) - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + file.in + + touch $* + + @@ -177,13 +202,9 @@ - - % scons -Q - Delete("tempfile") - Copy("tempfile", "file.in") - modify tempfile - Copy("file.out", "tempfile") - + + scons -Q + @@ -194,13 +215,16 @@ - + + Command("file.out", "file.in", [ Delete("$TARGET"), Copy("$TARGET", "$SOURCE") ]) - + + file.in + @@ -208,11 +232,9 @@ - - % scons -Q - Delete("file.out") - Copy("file.out", "file.in") - + + scons -Q + @@ -247,14 +269,26 @@ - + + Command("file.out", "file.in", [ Copy("tempfile", "$SOURCE"), "modify tempfile", Move("$TARGET", "tempfile"), ]) - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + file.in + + touch $* + + @@ -262,12 +296,9 @@ - - % scons -Q - Copy("tempfile", "file.in") - modify tempfile - Move("file.out", "tempfile") - + + scons -Q + @@ -282,13 +313,22 @@ - + + Command("file.out", "file.in", [ Copy("$TARGET", "$SOURCE"), Touch("$TARGET"), ]) - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + file.in + @@ -296,11 +336,9 @@ - - % scons -Q - Copy("file.out", "file.in") - Touch("file.out") - + + scons -Q + @@ -319,7 +357,8 @@ - + + Command("file.out", "file.in", [ Delete("tempdir"), @@ -329,7 +368,18 @@ Move("$TARGET", "tempdir/output_file"), Delete("tempdir"), ]) - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + file.in + + touch $* + + @@ -337,15 +387,9 @@ - - % scons -Q - Delete("tempdir") - Mkdir("tempdir") - Copy("tempdir/file.in", "file.in") - process tempdir - Move("file.out", "tempdir/output_file") - scons: *** [file.out] tempdir/output_file: No such file or directory - + + scons -Q + @@ -363,13 +407,16 @@ - + + Command("file.out", "file.in", [ Copy("$TARGET", "$SOURCE"), Chmod("$TARGET", 0755), ]) - + + file.in + @@ -377,11 +424,9 @@ - - % scons -Q - Copy("file.out", "file.in") - Chmod("file.out", 0755) - + + scons -Q + @@ -401,9 +446,11 @@ - - Execute(Mkdir('/tmp/my_temp_directory')) - + + + Execute(Mkdir('__ROOT__/tmp/my_temp_directory')) + + @@ -413,15 +460,9 @@ - - % scons - scons: Reading SConscript files ... - Mkdir("/tmp/my_temp_directory") - scons: done reading SConscript files. - scons: Building targets ... - scons: `.' is up to date. - scons: done building targets. - + + scons + @@ -457,10 +498,10 @@ - - if Execute(Mkdir('/tmp/my_temp_directory')): + + if Execute(Mkdir('__ROOT__/tmp/my_temp_directory')): # A problem occurred while making the temp directory. Exit(1) - + diff --git a/doc/user/file-removal.in b/doc/user/file-removal.in deleted file mode 100644 index 1d1b604..0000000 --- a/doc/user/file-removal.in +++ /dev/null @@ -1,223 +0,0 @@ - - - - - There are two occasions when &SCons; will, - by default, remove target files. - The first is when &SCons; determines that - an target file needs to be rebuilt - and removes the existing version of the target - before executing - The second is when &SCons; is invoked with the - -c option to "clean" - a tree of its built targets. - - These behaviours can be suppressed with the - &Precious; and &NoClean; functions, respectively. - - - -
- Preventing target removal during build: the &Precious; Function - - - - 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: - - - - - - env = Environment(RANLIBCOM='') - lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) - env.Precious(lib) - - - int f1() { } - - - int f2() { } - - - int f3() { } - - - - - - Although the output doesn't look any different, - &SCons; does not, in fact, - delete the target library before rebuilding it: - - - - - scons -Q - - - - - &SCons; will, however, still delete files marked as &Precious; - when the -c option is used. - - - -
- -
- Preventing target removal during clean: the &NoClean; Function - - - - By default, &SCons; removes all built targets when invoked - with the -c option to clean a source tree - of built targets. - Sometimes, however, this is not what you want. - For example, you may want to remove only intermediate generated files - (such as object files), - but leave the final targets - (the libraries) - untouched. - - In such cases, you can use the &NoClean; method to prevent &SCons; - from removing a target during a clean: - - - - - - env = Environment(RANLIBCOM='') - lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) - env.NoClean(lib) - - - int f1() { } - - - int f2() { } - - - int f3() { } - - - - - - Notice that the libfoo.a - is not listed as a removed file: - - - - - scons -Q - scons -c - - -
- -
- Removing additional files during clean: the &Clean; Function - - - - There may be additional files that you want removed - when the -c option is used, - but which &SCons; doesn't know about - because they're not normal target files. - For example, perhaps a command you invoke - creates a log file as - part of building the target file you want. - You would like the log file cleaned, - but you don't want to have to teach - SCons that the command - "builds" two files. - - - - - - You can use the &Clean; function to arrange for additional files - to be removed when the -c option is used. - Notice, however, that the &Clean; function takes two arguments, - and the second argument - is the name of the additional file you want cleaned - (foo.log in this example): - - - - - - t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE') - Clean(t, 'foo.log') - - - env = DefaultEnvironment() - import os - env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() - SConscript('S') - - - foo.in - - - foo.log - - - cat $3 > $2 - - - - - - The first argument is the target with which you want - the cleaning of this additional file associated. - In the above example, - we've used the return value from the - &Command; function, - which represents the - foo.out - target. - Now whenever the - foo.out target is cleaned - by the -c option, - the foo.log file - will be removed as well: - - - - - scons -Q - scons -Q -c - - -
diff --git a/doc/user/file-removal.xml b/doc/user/file-removal.xml index bfec7ac..1d1b604 100644 --- a/doc/user/file-removal.xml +++ b/doc/user/file-removal.xml @@ -56,11 +56,22 @@ - + + env = Environment(RANLIBCOM='') lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) env.Precious(lib) - + + + int f1() { } + + + int f2() { } + + + int f3() { } + + @@ -70,13 +81,9 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f2.o -c f2.c - cc -o f3.o -c f3.c - ar rc libfoo.a f1.o f2.o f3.o - + + scons -Q + @@ -107,11 +114,22 @@ - + + env = Environment(RANLIBCOM='') lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) env.NoClean(lib) - + + + int f1() { } + + + int f2() { } + + + int f3() { } + + @@ -120,21 +138,10 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f2.o -c f2.c - cc -o f3.o -c f3.c - ar rc libfoo.a f1.o f2.o f3.o - % scons -c - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Cleaning targets ... - Removed f1.o - Removed f2.o - Removed f3.o - scons: done cleaning targets. - + + scons -Q + scons -c + @@ -168,10 +175,27 @@ - + + t = Command('foo.out', 'foo.in', 'build -o $TARGET $SOURCE') Clean(t, 'foo.log') - + + + env = DefaultEnvironment() + import os + env['ENV']['PATH'] = env['ENV']['PATH'] + os.pathsep + os.getcwd() + SConscript('S') + + + foo.in + + + foo.log + + + cat $3 > $2 + + @@ -191,12 +215,9 @@ - - % scons -Q - build -o foo.out foo.in - % scons -Q -c - Removed foo.out - Removed foo.log - + + scons -Q + scons -Q -c + diff --git a/doc/user/functions.in b/doc/user/functions.in deleted file mode 100644 index 1b1b280..0000000 --- a/doc/user/functions.in +++ /dev/null @@ -1,38 +0,0 @@ - - - - -This appendix contains descriptions of all of the -function and construction environment methods -in this version of &SCons; - - - - - -&functions-gen; - - diff --git a/doc/user/gettext.in b/doc/user/gettext.in deleted file mode 100644 index ba09071..0000000 --- a/doc/user/gettext.in +++ /dev/null @@ -1,351 +0,0 @@ - - - - The &t-link-gettext; toolset supports internationalization and localization - of SCons-based projects. Builders provided by &t-link-gettext; automatize - generation and updates of translation files. You can manage translations and - translation templates similarly to how it's done with autotools. - - -
- Prerequisites - - To follow examples provided in this chapter set up your operating system to - support two or more languages. In following examples we use locales - en_US, de_DE, and - pl_PL. - - - - Ensure, that you have GNU gettext - utilities installed on your system. - - - - To edit translation files you may wish to install poedit editor. - -
- -
- Simple project - - Let's start with a very simple project, the "Hello world" program - for example - - - /* hello.c */ - #include <stdio.h> - int main(int argc, char* argv[]) - { - printf("Hello world\n"); - return 0; - } - - - - Prepare a SConstruct to compile the program - as usual. - - - # SConstruct - env = Environment() - hello = Program(["hello.c"]) - - - - - - Now we'll convert the project to a multi-lingual one. If you don't - already have GNU gettext - utilities installed, install them from your preffered - package repository, or download from - http://ftp.gnu.org/gnu/gettext/. For the purpose of this example, - you should have following three locales installed on your system: - en_US, de_DE and - pl_PL. On debian, for example, you may enable certain - locales through dpkg-reconfigure locales. - - - - First prepare the hello.c program for - internationalization. Change the previous code so it reads as follows: - - - /* hello.c */ - #include <stdio.h> - #include <libintl.h> - #include <locale.h> - int main(int argc, char* argv[]) - { - bindtextdomain("hello", "locale"); - setlocale(LC_ALL, ""); - textdomain("hello"); - printf(gettext("Hello world\n")); - return 0; - } - - - Detailed recipes for such conversion can - be found at - http://www.gnu.org/software/gettext/manual/gettext.html#Sources. - The gettext("...") has two purposes. - First, it marks messages for the xgettext(1) program, which - we will use to extract from the sources the messages for localization. - Second, it calls the gettext library internals to - translate the message at runtime. - - - - Now we shall instruct SCons how to generate and maintain translation files. - For that, use the &b-link-Translate; builder and &b-link-MOFiles; builder. - The first one takes source files, extracts internationalized - messages from them, creates so-called POT file - (translation template), and then creates PO translation - files, one for each requested language. Later, during the development - lifecycle, the builder keeps all these files up-to date. The - &b-link-MOFiles; builder compiles the PO files to binary - form. Then install the MO files under directory - called locale. - - - The completed - SConstruct is as follows: - - - # SConstruct - env = Environment( tools = ['default', 'gettext'] ) - hello = env.Program(["hello.c"]) - env['XGETTEXTFLAGS'] = [ - '--package-name=%s' % 'hello', - '--package-version=%s' % '1.0', - ] - po = env.Translate(["pl","en", "de"], ["hello.c"], POAUTOINIT = 1) - mo = env.MOFiles(po) - InstallAs(["locale/en/LC_MESSAGES/hello.mo"], ["en.mo"]) - InstallAs(["locale/pl/LC_MESSAGES/hello.mo"], ["pl.mo"]) - InstallAs(["locale/de/LC_MESSAGES/hello.mo"], ["de.mo"]) - - - - - Generate the translation files with scons po-update. - You should see the output from SCons simillar to this: - - user@host:$ scons po-update - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - Entering '/home/ptomulik/projects/tmp' - xgettext --package-name=hello --package-version=1.0 -o - hello.c - Leaving '/home/ptomulik/projects/tmp' - Writting 'messages.pot' (new file) - msginit --no-translator -l pl -i messages.pot -o pl.po - Created pl.po. - msginit --no-translator -l en -i messages.pot -o en.po - Created en.po. - msginit --no-translator -l de -i messages.pot -o de.po - Created de.po. - scons: done building targets. - - - - - If everything is right, you should see following new files. - - user@host:$ ls *.po* - de.po en.po messages.pot pl.po - - - - - Open en.po in poedit and provide - the English translation to message "Hello world\n". Do the - same for de.po (deutsch) and - pl.po (polish). Let the translations be, for example: - - - en: "Welcome to beautiful world!\n" - - - de: "Hallo Welt!\n" - - - pl: "Witaj swiecie!\n" - - - - - Now compile the project by executing scons. The - output should be similar to this: - - user@host:$ scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - msgfmt -c -o de.mo de.po - msgfmt -c -o en.mo en.po - gcc -o hello.o -c hello.c - gcc -o hello hello.o - Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo" - Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo" - msgfmt -c -o pl.mo pl.po - Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo" - scons: done building targets. - - SCons automatically compiled the PO files to binary format - MO, and the InstallAs lines installed - these files under locale folder. - - - Your program should be now ready. You may try it as follows (linux): - - user@host:$ LANG=en_US.UTF-8 ./hello - Welcome to beautiful world - - - user@host:$ LANG=de_DE.UTF-8 ./hello - Hallo Welt - - - user@host:$ LANG=pl_PL.UTF-8 ./hello - Witaj swiecie - - - - To demonstrate the further life of translation files, let's change Polish - translation (poedit pl.po) to "Witaj drogi - swiecie\n". Run scons to see how scons - reacts to this - - user@host:$scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - msgfmt -c -o pl.mo pl.po - Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo" - scons: done building targets. - - - - Now, open hello.c and add another one - printf line with new message. - - - /* hello.c */ - #include <stdio.h> - #include <libintl.h> - #include <locale.h> - int main(int argc, char* argv[]) - { - bindtextdomain("hello", "locale"); - setlocale(LC_ALL, ""); - textdomain("hello"); - printf(gettext("Hello world\n")); - printf(gettext("and good bye\n")); - return 0; - } - - - - - Compile project with scons. This time, the - msgmerge(1) program is used by SCons to update - PO file. The output from compilation is like: - - user@host:$scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - Entering '/home/ptomulik/projects/tmp' - xgettext --package-name=hello --package-version=1.0 -o - hello.c - Leaving '/home/ptomulik/projects/tmp' - Writting 'messages.pot' (messages in file were outdated) - msgmerge --update de.po messages.pot - ... done. - msgfmt -c -o de.mo de.po - msgmerge --update en.po messages.pot - ... done. - msgfmt -c -o en.mo en.po - gcc -o hello.o -c hello.c - gcc -o hello hello.o - Install file: "de.mo" as "locale/de/LC_MESSAGES/hello.mo" - Install file: "en.mo" as "locale/en/LC_MESSAGES/hello.mo" - msgmerge --update pl.po messages.pot - ... done. - msgfmt -c -o pl.mo pl.po - Install file: "pl.mo" as "locale/pl/LC_MESSAGES/hello.mo" - scons: done building targets. - - - - The next example demonstrates what happens if we change the source code - in such way that the internationalized messages do not change. The answer - is that none of translation files (POT, - PO) are touched (i.e. no content changes, no - creation/modification time changed and so on). Let's append another - line to the program (after the last printf), so its code becomes: - - - /* hello.c */ - #include <stdio.h> - #include <libintl.h> - #include <locale.h> - int main(int argc, char* argv[]) - { - bindtextdomain("hello", "locale"); - setlocale(LC_ALL, ""); - textdomain("hello"); - printf(gettext("Hello world\n")); - printf(gettext("and good bye\n")); - printf("----------------\n"); - return a; - } - - - Compile the project. You'll see on your screen - - user@host:$scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - Entering '/home/ptomulik/projects/tmp' - xgettext --package-name=hello --package-version=1.0 -o - hello.c - Leaving '/home/ptomulik/projects/tmp' - Not writting 'messages.pot' (messages in file found to be up-to-date) - gcc -o hello.o -c hello.c - gcc -o hello hello.o - scons: done building targets. - - As you see, the internationalized messages ditn't change, so the - POT and the rest of translation files have not - even been touched. - -
diff --git a/doc/user/gettext.xml b/doc/user/gettext.xml index d929203..ba09071 100644 --- a/doc/user/gettext.xml +++ b/doc/user/gettext.xml @@ -40,12 +40,14 @@ - Ensure, that you have GNU gettext + Ensure, that you have GNU gettext utilities installed on your system. - To edit translation files you may wish to install poedit editor. + To edit translation files you may wish to install poedit editor. @@ -54,7 +56,8 @@ Let's start with a very simple project, the "Hello world" program for example - + + /* hello.c */ #include <stdio.h> int main(int argc, char* argv[]) @@ -62,22 +65,27 @@ printf("Hello world\n"); return 0; } - + + Prepare a SConstruct to compile the program as usual. - + + # SConstruct env = Environment() hello = Program(["hello.c"]) - + + Now we'll convert the project to a multi-lingual one. If you don't - already have GNU gettext + already have GNU gettext utilities installed, install them from your preffered - package repository, or download from + package repository, or download from http://ftp.gnu.org/gnu/gettext/. For the purpose of this example, you should have following three locales installed on your system: en_US, de_DE and @@ -88,7 +96,8 @@ First prepare the hello.c program for internationalization. Change the previous code so it reads as follows: - + + /* hello.c */ #include <stdio.h> #include <libintl.h> @@ -101,9 +110,11 @@ printf(gettext("Hello world\n")); return 0; } - + + Detailed recipes for such conversion can - be found at + be found at http://www.gnu.org/software/gettext/manual/gettext.html#Sources. The gettext("...") has two purposes. First, it marks messages for the xgettext(1) program, which @@ -127,7 +138,8 @@ The completed SConstruct is as follows: - + + # SConstruct env = Environment( tools = ['default', 'gettext'] ) hello = env.Program(["hello.c"]) @@ -140,7 +152,8 @@ InstallAs(["locale/en/LC_MESSAGES/hello.mo"], ["en.mo"]) InstallAs(["locale/pl/LC_MESSAGES/hello.mo"], ["pl.mo"]) InstallAs(["locale/de/LC_MESSAGES/hello.mo"], ["de.mo"]) - + + Generate the translation files with scons po-update. @@ -244,7 +257,8 @@ Now, open hello.c and add another one printf line with new message. - + + /* hello.c */ #include <stdio.h> #include <libintl.h> @@ -258,7 +272,8 @@ printf(gettext("and good bye\n")); return 0; } - + + Compile project with scons. This time, the @@ -297,7 +312,8 @@ PO) are touched (i.e. no content changes, no creation/modification time changed and so on). Let's append another line to the program (after the last printf), so its code becomes: - + + /* hello.c */ #include <stdio.h> #include <libintl.h> @@ -312,7 +328,8 @@ printf("----------------\n"); return a; } - + + Compile the project. You'll see on your screen user@host:$scons diff --git a/doc/user/hierarchy.in b/doc/user/hierarchy.in deleted file mode 100644 index d70633d..0000000 --- a/doc/user/hierarchy.in +++ /dev/null @@ -1,794 +0,0 @@ - - - - - - - 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. - - - -
- &SConscript; Files - - - - 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: - - - - - SConscript(['drivers/display/SConscript', - 'drivers/mouse/SConscript', - 'parser/SConscript', - 'utilities/SConscript']) - - - - - 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 drivers - subdirectory might contain an intermediate - &SConscript; file, - in which case the &SConscript; call in - the top-level &SConstruct; file - would look like: - - - - - SConscript(['drivers/SConscript', - 'parser/SConscript', - 'utilities/SConscript']) - - - - - And the subsidiary &SConscript; file in the - drivers subdirectory - would look like: - - - - - SConscript(['display/SConscript', - 'mouse/SConscript']) - - - - - 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. - - - -
- -
- Path Names Are Relative to the &SConscript; Directory - - - - Subsidiary &SConscript; files make it easy to create a build - hierarchy because all of the file and directory names - in a subsidiary &SConscript; files are interpreted - relative to the directory in which the &SConscript; file lives. - Typically, this allows the &SConscript; file containing the - instructions to build a target file - to live in the same directory as the source files - from which the target will be built, - making it easy to update how the software is built - whenever files are added or deleted - (or other changes are made). - - - - - - For example, suppose we want to build two programs - &prog1; and &prog2; in two separate directories - with the same names as the programs. - One typical way to do this would be - with a top-level &SConstruct; file like this: - - - - - - SConscript(['prog1/SConscript', - 'prog2/SConscript']) - - - env = Environment() - env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) - - - env = Environment() - env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) - - - - x - - - x - - - x - - - - x - - - x - - - x - - - - - - And subsidiary &SConscript; files that look like this: - - - - - - - - - And this: - - - - - - - - - Then, when we run &SCons; in the top-level directory, - our build looks like: - - - - - scons -Q - - - - - Notice the following: - - First, you can have files with the same names - in multiple directories, like main.c in the above example. - - Second, unlike standard recursive use of &Make;, - &SCons; stays in the top-level directory - (where the &SConstruct; file lives) - and issues commands that use the path names - from the top-level directory to the - target and source files within the hierarchy. - - - -
- -
- Top-Level Path Names in Subsidiary &SConscript; Files - - - - If you need to use a file from another directory, - it's sometimes more convenient to specify - the path to a file in another directory - from the top-level &SConstruct; directory, - even when you're using that file in - a subsidiary &SConscript; file in a subdirectory. - You can tell &SCons; to interpret a path name - as relative to the top-level &SConstruct; directory, - not the local directory of the &SConscript; file, - by appending a &hash; (hash mark) - to the beginning of the path name: - - - - - - SConscript('src/prog/SConscript') - - - env = Environment() - env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c']) - - - x - - - x - - - x - - - - - - In this example, - the lib directory is - directly underneath the top-level &SConstruct; directory. - If the above &SConscript; file is in a subdirectory - named src/prog, - the output would look like: - - - - - scons -Q - - - - - (Notice that the lib/foo1.o object file - is built in the same directory as its source file. - See , below, - for information about - how to build the object file in a different subdirectory.) - - - -
- -
- Absolute Path Names - - - - Of course, you can always specify - an absolute path name for a file--for example: - - - - - - SConscript('src/prog/SConscript') - - - env = Environment() - env.Program('prog', ['main.c', '__ROOT__/usr/joe/lib/foo1.c', 'foo2.c']) - - - x - - - x - - - x - - - - - - Which, when executed, would yield: - - - - - scons -Q - - - - - (As was the case with top-relative path names, - notice that the /usr/joe/lib/foo1.o object file - is built in the same directory as its source file. - See , below, - for information about - how to build the object file in a different subdirectory.) - - - -
- -
- Sharing Environments (and Other Variables) Between &SConscript; Files - - - - In the previous example, - each of the subsidiary &SConscript; files - created its own construction environment - by calling &Environment; separately. - This obviously works fine, - but if each program must be built - with the same construction variables, - it's cumbersome and error-prone to initialize - separate construction environments - in the same way over and over in each subsidiary - &SConscript; file. - - - - - - &SCons; supports the ability to export variables - from a parent &SConscript; file - to its subsidiary &SConscript; files, - which allows you to share common initialized - values throughout your build hierarchy. - - - -
- Exporting Variables - - - - There are two ways to export a variable, - such as a construction environment, - from an &SConscript; file, - so that it may be used by other &SConscript; files. - First, you can call the &Export; - function with a list of variables, - or a string of white-space separated variable names. - Each call to &Export; adds one - or more variables to a global list - of variables that are available for import - by other &SConscript; files. - - - - - env = Environment() - Export('env') - - - - - You may export more than one variable name at a time: - - - - - env = Environment() - debug = ARGUMENTS['debug'] - Export('env', 'debug') - - - - - Because white space is not legal in Python variable names, - the &Export; function will even automatically split - a string into separate names for you: - - - - - Export('env debug') - - - - - Second, you can specify a list of - variables to export as a second argument - to the &SConscript; function call: - - - - - SConscript('src/SConscript', 'env') - - - - - Or as the &exports; keyword argument: - - - - - SConscript('src/SConscript', exports='env') - - - - - These calls export the specified variables - to only the listed &SConscript; files. - You may, however, specify more than one - &SConscript; file in a list: - - - - - SConscript(['src1/SConscript', - 'src2/SConscript'], exports='env') - - - - - This is functionally equivalent to - calling the &SConscript; function - multiple times with the same &exports; argument, - one per &SConscript; file. - - - -
- -
- Importing Variables - - - - Once a variable has been exported from a calling - &SConscript; file, - it may be used in other &SConscript; files - by calling the &Import; function: - - - - - Import('env') - env.Program('prog', ['prog.c']) - - - - - The &Import; call makes the env construction - environment available to the &SConscript; file, - after which the variable can be used to build - programs, libraries, etc. - - - - - - Like the &Export; function, - the &Import; function can be used - with multiple variable names: - - - - - Import('env', 'debug') - env = env.Clone(DEBUG = debug) - env.Program('prog', ['prog.c']) - - - - - And the &Import; function will similarly - split a string along white-space - into separate variable names: - - - - - Import('env debug') - env = env.Clone(DEBUG = debug) - env.Program('prog', ['prog.c']) - - - - - Lastly, as a special case, - you may import all of the variables that - have been exported by supplying an asterisk - to the &Import; function: - - - - - Import('*') - env = env.Clone(DEBUG = debug) - env.Program('prog', ['prog.c']) - - - - - If you're dealing with a lot of &SConscript; files, - this can be a lot simpler than keeping - arbitrary lists of imported variables in each file. - - - -
- -
- Returning Values From an &SConscript; File - - - - Sometimes, you would like to be able to - use information from a subsidiary - &SConscript; file in some way. - For example, - suppose that you want to create one - library from source files - scattered throughout a number - of subsidiary &SConscript; files. - You can do this by using the &Return; - function to return values - from the subsidiary &SConscript; files - to the calling file. - - - - - - If, for example, we have two subdirectories - &foo; and &bar; - that should each contribute a source - file to a Library, - what we'd like to be able to do is - collect the object files - from the subsidiary &SConscript; calls - like this: - - - - - - env = Environment() - Export('env') - objs = [] - for subdir in ['foo', 'bar']: - o = SConscript('%s/SConscript' % subdir) - objs.append(o) - env.Library('prog', objs) - - - - - Import('env') - obj = env.Object('foo.c') - Return('obj') - - - Import('env') - obj = env.Object('bar.c') - Return('obj') - - - void foo(void) { printf("foo/foo.c\n"); } - - - void bar(void) { printf("bar/bar.c\n"); } - - - - - - We can do this by using the &Return; - function in the - foo/SConscript file like this: - - - - - - - - - (The corresponding - bar/SConscript - file should be pretty obvious.) - Then when we run &SCons;, - the object files from the subsidiary subdirectories - are all correctly archived in the desired library: - - - - - scons -Q - - - - -
- -
- - diff --git a/doc/user/hierarchy.xml b/doc/user/hierarchy.xml index 2e2941c..d70633d 100644 --- a/doc/user/hierarchy.xml +++ b/doc/user/hierarchy.xml @@ -196,12 +196,12 @@ make no difference to the build.
- + SConscript(['drivers/display/SConscript', 'drivers/mouse/SConscript', 'parser/SConscript', 'utilities/SConscript']) - + @@ -218,11 +218,11 @@ make no difference to the build. - + SConscript(['drivers/SConscript', 'parser/SConscript', 'utilities/SConscript']) - + @@ -232,10 +232,10 @@ make no difference to the build. - + SConscript(['display/SConscript', 'mouse/SConscript']) - + @@ -279,10 +279,40 @@ make no difference to the build. - + + SConscript(['prog1/SConscript', 'prog2/SConscript']) - + + + env = Environment() + env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) + + + env = Environment() + env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) + + + + x + + + x + + + x + + + + x + + + x + + + x + + @@ -290,11 +320,8 @@ make no difference to the build. - - - env = Environment() - env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) - + + @@ -302,11 +329,8 @@ make no difference to the build. - - - env = Environment() - env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) - + + @@ -315,17 +339,9 @@ make no difference to the build. - - % scons -Q - cc -o prog1/foo1.o -c prog1/foo1.c - cc -o prog1/foo2.o -c prog1/foo2.c - cc -o prog1/main.o -c prog1/main.c - cc -o prog1/prog1 prog1/main.o prog1/foo1.o prog1/foo2.o - cc -o prog2/bar1.o -c prog2/bar1.c - cc -o prog2/bar2.o -c prog2/bar2.c - cc -o prog2/main.o -c prog2/main.c - cc -o prog2/prog2 prog2/main.o prog2/bar1.o prog2/bar2.o - + + scons -Q + @@ -364,10 +380,24 @@ make no difference to the build. - + + + SConscript('src/prog/SConscript') + + env = Environment() env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c']) - + + + x + + + x + + + x + + @@ -380,13 +410,9 @@ make no difference to the build. - - % scons -Q - cc -o lib/foo1.o -c lib/foo1.c - cc -o src/prog/foo2.o -c src/prog/foo2.c - cc -o src/prog/main.o -c src/prog/main.c - cc -o src/prog/prog src/prog/main.o lib/foo1.o src/prog/foo2.o - + + scons -Q + @@ -410,10 +436,24 @@ make no difference to the build. - + + + SConscript('src/prog/SConscript') + + env = Environment() - env.Program('prog', ['main.c', '/usr/joe/lib/foo1.c', 'foo2.c']) - + env.Program('prog', ['main.c', '__ROOT__/usr/joe/lib/foo1.c', 'foo2.c']) + + + x + + + x + + + x + + @@ -421,13 +461,9 @@ make no difference to the build. - - % scons -Q - cc -o src/prog/foo2.o -c src/prog/foo2.c - cc -o src/prog/main.o -c src/prog/main.c - cc -o /usr/joe/lib/foo1.o -c /usr/joe/lib/foo1.c - cc -o src/prog/prog src/prog/main.o /usr/joe/lib/foo1.o src/prog/foo2.o - + + scons -Q + @@ -490,10 +526,10 @@ make no difference to the build. - + env = Environment() Export('env') - + @@ -501,11 +537,11 @@ make no difference to the build. - + env = Environment() debug = ARGUMENTS['debug'] Export('env', 'debug') - + @@ -515,9 +551,9 @@ make no difference to the build. - + Export('env debug') - + @@ -527,9 +563,9 @@ make no difference to the build. - + SConscript('src/SConscript', 'env') - + @@ -537,9 +573,9 @@ make no difference to the build. - + SConscript('src/SConscript', exports='env') - + @@ -550,10 +586,10 @@ make no difference to the build. - + SConscript(['src1/SConscript', 'src2/SConscript'], exports='env') - + @@ -578,10 +614,10 @@ make no difference to the build. - + Import('env') env.Program('prog', ['prog.c']) - + @@ -600,11 +636,11 @@ make no difference to the build. - + Import('env', 'debug') env = env.Clone(DEBUG = debug) env.Program('prog', ['prog.c']) - + @@ -614,11 +650,11 @@ make no difference to the build. - + Import('env debug') env = env.Clone(DEBUG = debug) env.Program('prog', ['prog.c']) - + @@ -629,11 +665,11 @@ make no difference to the build. - + Import('*') env = env.Clone(DEBUG = debug) env.Program('prog', ['prog.c']) - + @@ -678,7 +714,8 @@ make no difference to the build. - + + env = Environment() Export('env') objs = [] @@ -686,7 +723,26 @@ make no difference to the build. o = SConscript('%s/SConscript' % subdir) objs.append(o) env.Library('prog', objs) - + + + + + Import('env') + obj = env.Object('foo.c') + Return('obj') + + + Import('env') + obj = env.Object('bar.c') + Return('obj') + + + void foo(void) { printf("foo/foo.c\n"); } + + + void bar(void) { printf("bar/bar.c\n"); } + + @@ -696,12 +752,8 @@ make no difference to the build. - - - Import('env') - obj = env.Object('foo.c') - Return('obj') - + + @@ -714,13 +766,9 @@ make no difference to the build. - - % scons -Q - cc -o bar/bar.o -c bar/bar.c - cc -o foo/foo.o -c foo/foo.c - ar rc libprog.a foo/foo.o bar/bar.o - ranlib libprog.a - + + scons -Q + - - - - 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: - - - - - - env = Environment() - hello = env.Program('hello.c') - env.Install('__ROOT__/usr/bin', hello) - - - int main() { printf("Hello, world!\n"); } - - - - - - 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 /) - for it to install anything there: - - - - - scons -Q - scons -Q __ROOT__/usr/bin - - - - - 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, for example, - to create a pseudo-target named install - that can expand to the specified destination directory: - - - - - - env = Environment() - hello = env.Program('hello.c') - env.Install('__ROOT__/usr/bin', hello) - env.Alias('install', '__ROOT__/usr/bin') - - - int main() { printf("Hello, world!\n"); } - - - - - - This then yields the more natural - ability to install the program - in its destination as follows: - - - - - scons -Q - scons -Q install - - -
- Installing Multiple Files in a Directory - - - - You can install multiple files into a directory - simply by calling the &Install; function multiple times: - - - - - - env = Environment() - hello = env.Program('hello.c') - goodbye = env.Program('goodbye.c') - env.Install('__ROOT__/usr/bin', hello) - env.Install('__ROOT__/usr/bin', goodbye) - env.Alias('install', '__ROOT__/usr/bin') - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Goodbye, world!\n"); } - - - - - - Or, more succinctly, listing the multiple input - files in a list - (just like you can do with any other builder): - - - - - env = Environment() - hello = env.Program('hello.c') - goodbye = env.Program('goodbye.c') - env.Install('__ROOT__/usr/bin', [hello, goodbye]) - env.Alias('install', '__ROOT__/usr/bin') - - - - - Either of these two examples yields: - - - - - scons -Q install - - -
- -
- Installing a File Under a Different Name - - - - 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: - - - - - - env = Environment() - hello = env.Program('hello.c') - env.InstallAs('__ROOT__/usr/bin/hello-new', hello) - env.Alias('install', '__ROOT__/usr/bin') - - - int main() { printf("Hello, world!\n"); } - - - - - - This installs the hello - program with the name hello-new - as follows: - - - - - scons -Q install - - -
- -
- Installing Multiple Files Under Different Names - - - - 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 both the target and source arguments: - - - - - - env = Environment() - hello = env.Program('hello.c') - goodbye = env.Program('goodbye.c') - env.InstallAs(['__ROOT__/usr/bin/hello-new', - '__ROOT__/usr/bin/goodbye-new'], - [hello, goodbye]) - env.Alias('install', '__ROOT__/usr/bin') - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Goodbye, world!\n"); } - - - - - - In this case, the &InstallAs; function - loops through both lists simultaneously, - and copies each source file into its corresponding - target file name: - - - - - scons -Q install - - -
diff --git a/doc/user/install.xml b/doc/user/install.xml index dd79153..ba179e7 100644 --- a/doc/user/install.xml +++ b/doc/user/install.xml @@ -34,11 +34,16 @@
- + + env = Environment() hello = env.Program('hello.c') - env.Install('/usr/bin', hello) - + env.Install('__ROOT__/usr/bin', hello) + + + int main() { printf("Hello, world!\n"); } + + @@ -56,13 +61,10 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q /usr/bin - Install file: "hello" as "/usr/bin/hello" - + + scons -Q + scons -Q __ROOT__/usr/bin + @@ -78,12 +80,17 @@ - + + env = Environment() hello = env.Program('hello.c') - env.Install('/usr/bin', hello) - env.Alias('install', '/usr/bin') - + env.Install('__ROOT__/usr/bin', hello) + env.Alias('install', '__ROOT__/usr/bin') + + + int main() { printf("Hello, world!\n"); } + + @@ -93,13 +100,10 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - % scons -Q install - Install file: "hello" as "/usr/bin/hello" - + + scons -Q + scons -Q install +
Installing Multiple Files in a Directory @@ -111,14 +115,22 @@ - + + 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') - + env.Install('__ROOT__/usr/bin', hello) + env.Install('__ROOT__/usr/bin', goodbye) + env.Alias('install', '__ROOT__/usr/bin') + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Goodbye, world!\n"); } + + @@ -128,13 +140,13 @@ - + env = Environment() hello = env.Program('hello.c') goodbye = env.Program('goodbye.c') - env.Install('/usr/bin', [hello, goodbye]) - env.Alias('install', '/usr/bin') - + env.Install('__ROOT__/usr/bin', [hello, goodbye]) + env.Alias('install', '__ROOT__/usr/bin') + @@ -142,15 +154,9 @@ - - % scons -Q install - cc -o goodbye.o -c goodbye.c - cc -o goodbye goodbye.o - Install file: "goodbye" as "/usr/bin/goodbye" - cc -o hello.o -c hello.c - cc -o hello hello.o - Install file: "hello" as "/usr/bin/hello" - + + scons -Q install +
@@ -167,12 +173,17 @@
- + + env = Environment() hello = env.Program('hello.c') - env.InstallAs('/usr/bin/hello-new', hello) - env.Alias('install', '/usr/bin') - + env.InstallAs('__ROOT__/usr/bin/hello-new', hello) + env.Alias('install', '__ROOT__/usr/bin') + + + int main() { printf("Hello, world!\n"); } + + @@ -182,12 +193,9 @@ - - % scons -Q install - cc -o hello.o -c hello.c - cc -o hello hello.o - Install file: "hello" as "/usr/bin/hello-new" - + + scons -Q install + @@ -205,15 +213,23 @@
- + + env = Environment() hello = env.Program('hello.c') goodbye = env.Program('goodbye.c') - env.InstallAs(['/usr/bin/hello-new', - '/usr/bin/goodbye-new'], + env.InstallAs(['__ROOT__/usr/bin/hello-new', + '__ROOT__/usr/bin/goodbye-new'], [hello, goodbye]) - env.Alias('install', '/usr/bin') - + env.Alias('install', '__ROOT__/usr/bin') + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Goodbye, world!\n"); } + + @@ -224,14 +240,8 @@ - - % scons -Q install - cc -o goodbye.o -c goodbye.c - cc -o goodbye goodbye.o - Install file: "goodbye" as "/usr/bin/goodbye-new" - cc -o hello.o -c hello.c - cc -o hello hello.o - Install file: "hello" as "/usr/bin/hello-new" - + + scons -Q install + diff --git a/doc/user/java.in b/doc/user/java.in deleted file mode 100644 index 4561a4c..0000000 --- a/doc/user/java.in +++ /dev/null @@ -1,657 +0,0 @@ - - - - - So far, we've been using examples of - building C and C++ programs - to demonstrate the features of &SCons;. - &SCons; also supports building Java programs, - but Java builds are handled slightly differently, - which reflects the ways in which - the Java compiler and tools - build programs differently than - other languages' tool chains. - - - -
- Building Java Class Files: the &b-Java; Builder - - - - The basic activity when programming in Java, - of course, is to take one or more .java files - containing Java source code - and to call the Java compiler - to turn them into one or more - .class files. - In &SCons;, you do this - by giving the &b-link-Java; Builder - a target directory in which - to put the .class files, - and a source directory that contains - the .java files: - - - - - - Java('classes', 'src') - - - public class Example1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example2 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example3 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - - - - If the src directory contains - three .java source files, - then running &SCons; might look like this: - - - - - scons -Q - - - - - &SCons; will actually search the src - directory tree for all of the .java files. - The Java compiler will then create the - necessary class files in the classes subdirectory, - based on the class names found in the .java files. - - - -
- -
- How &SCons; Handles Java Dependencies - - - - In addition to searching the source directory for - .java files, - &SCons; actually runs the .java files - through a stripped-down Java parser that figures out - what classes are defined. - In other words, &SCons; knows, - without you having to tell it, - what .class files - will be produced by the &javac; call. - So our one-liner example from the preceding section: - - - - - - Java('classes', 'src') - - - public class Example1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - public class AdditionalClass1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example2 - { - class Inner2 { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - } - - - public class Example3 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - public class AdditionalClass3 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - - - - Will not only tell you reliably - that the .class files - in the classes subdirectory - are up-to-date: - - - - - scons -Q - scons -Q classes - - - - - But it will also remove all of the generated - .class files, - even for inner classes, - without you having to specify them manually. - For example, if our - Example1.java - and - Example3.java - files both define additional classes, - and the class defined in Example2.java - has an inner class, - running scons -c - will clean up all of those .class files - as well: - - - - - scons -Q - scons -Q -c classes - - - - - To ensure correct handling of .class - dependencies in all cases, you need to tell &SCons; which Java - version is being used. This is needed because Java 1.5 changed - the .class file names for nested anonymous - inner classes. Use the JAVAVERSION construction - variable to specify the version in use. With Java 1.6, the - one-liner example can then be defined like this: - - - - - Java('classes', 'src', JAVAVERSION='1.6') - - - - See JAVAVERSION in the man page for more information. - - -
- -
- Building Java Archive (<filename>.jar</filename>) Files: the &b-Jar; Builder - - - - After building the class files, - it's common to collect them into - a Java archive (.jar) file, - which you do by calling the &b-link-Jar; Builder method. - If you want to just collect all of the - class files within a subdirectory, - you can just specify that subdirectory - as the &b-Jar; source: - - - - - - Java(target = 'classes', source = 'src') - Jar(target = 'test.jar', source = 'classes') - - - public class Example1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example2 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example3 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - - - - &SCons; will then pass that directory - to the &jar; command, - which will collect all of the underlying - .class files: - - - - - scons -Q - - - - - If you want to keep all of the - .class files - for multiple programs in one location, - and only archive some of them in - each .jar file, - you can pass the &b-Jar; builder a - list of files as its source. - It's extremely simple to create multiple - .jar files this way, - using the lists of target class files created - by calls to the &b-link-Java; builder - as sources to the various &b-Jar; calls: - - - - - - prog1_class_files = Java(target = 'classes', source = 'prog1') - prog2_class_files = Java(target = 'classes', source = 'prog2') - Jar(target = 'prog1.jar', source = prog1_class_files) - Jar(target = 'prog2.jar', source = prog2_class_files) - - - public class Example1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example2 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example3 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - public class Example4 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - - - - This will then create - prog1.jar - and prog2.jar - next to the subdirectories - that contain their .java files: - - - - - scons -Q - - -
- -
- Building C Header and Stub Files: the &b-JavaH; Builder - - - - You can generate C header and source files - for implementing native methods, - by using the &b-link-JavaH; Builder. - There are several ways of using the &JavaH; Builder. - One typical invocation might look like: - - - - - - classes = Java(target = 'classes', source = 'src/pkg/sub') - JavaH(target = 'native', source = classes) - - - package pkg.sub; - public class Example1 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example2 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example3 - { - public static void main(String[] args) - { - } - } - - - - - - The source is a list of class files generated by the - call to the &b-link-Java; Builder, - and the target is the output directory in - which we want the C header files placed. - The target - gets converted into the - when &SCons; runs &javah;: - - - - - scons -Q - - - - - In this case, - the call to &javah; - will generate the header files - native/pkg_sub_Example1.h, - native/pkg_sub_Example2.h - and - native/pkg_sub_Example3.h. - Notice that &SCons; remembered that the class - files were generated with a target directory of - classes, - and that it then specified that target directory - as the option - to the call to &javah;. - - - - - - Although it's more convenient to use - the list of class files returned by - the &b-Java; Builder - as the source of a call to the &b-JavaH; Builder, - you can - specify the list of class files - by hand, if you prefer. - If you do, - you need to set the - &cv-link-JAVACLASSDIR; construction variable - when calling &b-JavaH;: - - - - - - Java(target = 'classes', source = 'src/pkg/sub') - class_file_list = ['classes/pkg/sub/Example1.class', - 'classes/pkg/sub/Example2.class', - 'classes/pkg/sub/Example3.class'] - JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes') - - - package pkg.sub; - public class Example1 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example2 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example3 - { - public static void main(String[] args) - { - } - } - - - - - - The &cv-JAVACLASSDIR; value then - gets converted into the - when &SCons; runs &javah;: - - - - - scons -Q - - - - - Lastly, if you don't want a separate header file - generated for each source file, - you can specify an explicit File Node - as the target of the &b-JavaH; Builder: - - - - - - classes = Java(target = 'classes', source = 'src/pkg/sub') - JavaH(target = File('native.h'), source = classes) - - - package pkg.sub; - public class Example1 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example2 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example3 - { - public static void main(String[] args) - { - } - } - - - - - - Because &SCons; assumes by default - that the target of the &b-JavaH; builder is a directory, - you need to use the &File; function - to make sure that &SCons; doesn't - create a directory named native.h. - When a file is used, though, - &SCons; correctly converts the file name - into the &javah; option: - - - - - scons -Q - - -
- -
- Building RMI Stub and Skeleton Class Files: the &b-RMIC; Builder - - - - You can generate Remote Method Invocation stubs - by using the &b-link-RMIC; Builder. - The source is a list of directories, - typically returned by a call to the &b-link-Java; Builder, - and the target is an output directory - where the _Stub.class - and _Skel.class files will - be placed: - - - - - - classes = Java(target = 'classes', source = 'src/pkg/sub') - RMIC(target = 'outdir', source = classes) - - - package pkg.sub; - public class Example1 - { - public static void main(String[] args) - { - } - } - - - package pkg.sub; - public class Example2 - { - public static void main(String[] args) - { - } - } - - - - - - As it did with the &b-link-JavaH; Builder, - &SCons; remembers the class directory - and passes it as the option - to &rmic;: - - - - - scons -Q - - - - - This example would generate the files - outdir/pkg/sub/Example1_Skel.class, - outdir/pkg/sub/Example1_Stub.class, - outdir/pkg/sub/Example2_Skel.class and - outdir/pkg/sub/Example2_Stub.class. - - - -
diff --git a/doc/user/java.xml b/doc/user/java.xml index fddc646..4561a4c 100644 --- a/doc/user/java.xml +++ b/doc/user/java.xml @@ -57,9 +57,38 @@ - + + Java('classes', 'src') - + + + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + @@ -69,10 +98,9 @@ - - % scons -Q - javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java - + + scons -Q + @@ -104,9 +132,54 @@ - + + Java('classes', 'src') - + + + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + public class AdditionalClass1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example2 + { + class Inner2 { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + } + + + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + public class AdditionalClass3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + @@ -117,12 +190,10 @@ - - % scons -Q - javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java - % scons -Q classes - scons: `classes' is up to date. - + + scons -Q + scons -Q classes + @@ -143,17 +214,10 @@ - - % scons -Q - javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java - % scons -Q -c classes - Removed classes/Example1.class - Removed classes/AdditionalClass1.class - Removed classes/Example2$Inner2.class - Removed classes/Example2.class - Removed classes/Example3.class - Removed classes/AdditionalClass3.class - + + scons -Q + scons -Q -c classes + @@ -167,9 +231,9 @@ - + Java('classes', 'src', JAVAVERSION='1.6') - + See JAVAVERSION in the man page for more information. @@ -193,10 +257,39 @@ - + + Java(target = 'classes', source = 'src') Jar(target = 'test.jar', source = 'classes') - + + + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + @@ -207,11 +300,9 @@ - - % scons -Q - javac -d classes -sourcepath src src/Example1.java src/Example2.java src/Example3.java - jar cf test.jar classes - + + scons -Q + @@ -230,12 +321,50 @@ - + + prog1_class_files = Java(target = 'classes', source = 'prog1') prog2_class_files = Java(target = 'classes', source = 'prog2') Jar(target = 'prog1.jar', source = prog1_class_files) Jar(target = 'prog2.jar', source = prog2_class_files) - + + + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example2 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example3 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + + public class Example4 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + @@ -247,13 +376,9 @@ - - % scons -Q - javac -d classes -sourcepath prog1 prog1/Example1.java prog1/Example2.java - javac -d classes -sourcepath prog2 prog2/Example3.java prog2/Example4.java - jar cf prog1.jar -C classes Example1.class -C classes Example2.class - jar cf prog2.jar -C classes Example3.class -C classes Example4.class - + + scons -Q + @@ -270,10 +395,39 @@ - + + classes = Java(target = 'classes', source = 'src/pkg/sub') JavaH(target = 'native', source = classes) - + + + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + + @@ -287,11 +441,9 @@ - - % scons -Q - javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java - javah -d native -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 - + + scons -Q + @@ -327,13 +479,42 @@ - + + Java(target = 'classes', source = 'src/pkg/sub') class_file_list = ['classes/pkg/sub/Example1.class', 'classes/pkg/sub/Example2.class', 'classes/pkg/sub/Example3.class'] JavaH(target = 'native', source = class_file_list, JAVACLASSDIR = 'classes') - + + + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + + @@ -343,11 +524,9 @@ - - % scons -Q - javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java - javah -d native -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 - + + scons -Q + @@ -358,10 +537,39 @@ - + + classes = Java(target = 'classes', source = 'src/pkg/sub') JavaH(target = File('native.h'), source = classes) - + + + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example3 + { + public static void main(String[] args) + { + } + } + + @@ -376,11 +584,9 @@ - - % scons -Q - javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java src/pkg/sub/Example3.java - javah -o native.h -classpath classes pkg.sub.Example1 pkg.sub.Example2 pkg.sub.Example3 - + + scons -Q + @@ -400,10 +606,30 @@ - + + classes = Java(target = 'classes', source = 'src/pkg/sub') RMIC(target = 'outdir', source = classes) - + + + package pkg.sub; + public class Example1 + { + public static void main(String[] args) + { + } + } + + + package pkg.sub; + public class Example2 + { + public static void main(String[] args) + { + } + } + + @@ -414,11 +640,9 @@ - - % scons -Q - javac -d classes -sourcepath src/pkg/sub src/pkg/sub/Example1.java src/pkg/sub/Example2.java - rmic -d outdir -classpath classes pkg.sub.Example1 pkg.sub.Example2 - + + scons -Q + diff --git a/doc/user/less-simple.in b/doc/user/less-simple.in deleted file mode 100644 index fcffa5e..0000000 --- a/doc/user/less-simple.in +++ /dev/null @@ -1,623 +0,0 @@ - - - - - In this chapter, - you will see several examples of - very simple build configurations using &SCons;, - which will demonstrate how easy - it is to use &SCons; to - build programs from several different programming languages - on different types of systems. - - - -
- Specifying the Name of the Target (Output) File - - - - You've seen that when you call the &b-link-Program; builder method, - it builds the resulting program with the same - base name as the source file. - That is, the following call to build an - executable program from the &hello_c; source file - will build an executable program named &hello; on POSIX systems, - and an executable program named &hello_exe; on Windows systems: - - - - - Program('hello.c') - - - - - If you want to build a program with - a different name than the base of the source file name, - you simply put the target file name - to the left of the source file name: - - - - - - Program('new_hello', 'hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - (&SCons; requires the target file name first, - followed by the source file name, - so that the order mimics that of an - assignment statement in most programming languages, - including Python: - "program = source files".) - - - - - - Now &SCons; will build an executable program - named &new_hello; when run on a POSIX system: - - - - - scons -Q - - - - - And &SCons; will build an executable program - named &new_hello_exe; when run on a Windows system: - - - - - scons -Q - - -
- -
- Compiling Multiple Source Files - - - - You've just seen how to configure &SCons; - to compile a program from a single source file. - It's more common, of course, - that you'll need to build a program from - many input source files, not just one. - To do this, you need to put the - source files in a Python list - (enclosed in square brackets), - like so: - - - - - - Program(['prog.c', 'file1.c', 'file2.c']) - - - int main() { printf("prog.c\n"); } - - - void file1() { printf("file1.c\n"); } - - - void file2() { printf("file2.c\n"); } - - - - - - A build of the above example would look like: - - - - - scons -Q - - - - - Notice that &SCons; - deduces the output program name - from the first source file specified - in the list--that is, - because the first source file was &prog_c;, - &SCons; will name the resulting program &prog; - (or &prog_exe; on a Windows system). - If you want to specify a different program name, - then (as we've seen in the previous section) - you slide the list of source files - over to the right - to make room for the output program file name. - (&SCons; puts the output file name to the left - of the source file names - so that the order mimics that of an - assignment statement: "program = source files".) - This makes our example: - - - - - - Program('program', ['prog.c', 'file1.c', 'file2.c']) - - - int main() { printf("prog.c\n"); } - - - void file1() { printf("file1.c\n"); } - - - void file2() { printf("file2.c\n"); } - - - - - - On Linux, a build of this example would look like: - - - - - scons -Q - - - - - Or on Windows: - - - - - scons -Q - - -
- -
- Making a list of files with &Glob; - - - - You can also use the &Glob; function to find all files matching a - certain template, using the standard shell pattern matching - characters *, ? - and [abc] to match any of - a, b or c. - [!abc] is also supported, - to match any character except - a, b or c. - This makes many multi-source-file builds quite easy: - - - - - Program('program', Glob('*.c')) - - - - - The SCons man page has more details on using &Glob; - with variant directories - (see , below) - and repositories - (see , below), - and returning strings rather than Nodes. - - - -
- -
- Specifying Single Files Vs. Lists of Files - - - - We've now shown you two ways to specify - the source for a program, - one with a list of files: - - - - - Program('hello', ['file1.c', 'file2.c']) - - - - - And one with a single file: - - - - - Program('hello', 'hello.c') - - - - - You could actually put a single file name in a list, too, - which you might prefer just for the sake of consistency: - - - - - Program('hello', ['hello.c']) - - - - - &SCons; functions will accept a single file name in either form. - In fact, internally, &SCons; treats all input as lists of files, - but allows you to omit the square brackets - to cut down a little on the typing - when there's only a single file name. - - - - - - - - Although &SCons; functions - are forgiving about whether or not you - use a string vs. a list for a single file name, - Python itself is more strict about - treating lists and strings differently. - So where &SCons; allows either - a string or list: - - - - - # The following two calls both work correctly: - Program('program1', 'program1.c') - Program('program2', ['program2.c']) - - - - - Trying to do "Python things" that mix strings and - lists will cause errors or lead to incorrect results: - - - - - common_sources = ['file1.c', 'file2.c'] - - # THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR - # BECAUSE IT TRIES TO ADD A STRING TO A LIST: - Program('program1', common_sources + 'program1.c') - - # The following works correctly, because it's adding two - # lists together to make another list. - Program('program2', common_sources + ['program2.c']) - - - - -
- -
- Making Lists of Files Easier to Read - - - - 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). - This can get cumbersome and difficult to read - when the list of file names is long. - Fortunately, &SCons; and Python provide a number of ways - to make sure that - the &SConstruct; file stays easy to read. - - - - - - To make long lists of file names - easier to deal with, &SCons; provides a - &Split; function - that takes a quoted list of file names, - with the names separated by spaces or other white-space characters, - and turns it into a list of separate file names. - Using the &Split; function turns the - previous example into: - - - - - Program('program', Split('main.c file1.c file2.c')) - - - - - (If you're already familiar with Python, - you'll have realized that this is similar to the - split() method - in the Python standard string module. - Unlike the split() member function of strings, - however, the &Split; function - does not require a string as input - and will wrap up a single non-string object in a list, - or return its argument untouched if it's already a list. - This comes in handy as a way to make sure - arbitrary values can be passed to &SCons; functions - without having to check the type of the variable by hand.) - - - - - - Putting the call to the &Split; function - inside the &b-Program; call - can also be a little unwieldy. - A more readable alternative is to - assign the output from the &Split; call - to a variable name, - and then use the variable when calling the - &b-Program; function: - - - - - src_files = Split('main.c file1.c file2.c') - Program('program', src_files) - - - - - Lastly, the &Split; function - doesn't care how much white space separates - the file names in the quoted string. - This allows you to create lists of file - names that span multiple lines, - which often makes for easier editing: - - - - - src_files = Split("""main.c - file1.c - file2.c""") - Program('program', src_files) - - - - - (Note in this example that we used - the Python "triple-quote" syntax, - which allows a string to contain - multiple lines. - The three quotes can be either - single or double quotes.) - - - -
- -
- Keyword Arguments - - - - &SCons; also allows you to identify - the output file and input source files - using Python keyword arguments. - The output file is known as the - target, - and the source file(s) are known (logically enough) as the - source. - The Python syntax for this is: - - - - - src_files = Split('main.c file1.c file2.c') - Program(target = 'program', source = src_files) - - - - - Because the keywords explicitly identify - what each argument is, - you can actually reverse the order if you prefer: - - - - - src_files = Split('main.c file1.c file2.c') - Program(source = src_files, target = 'program') - - - - - Whether or not you choose to use keyword arguments - to identify the target and source files, - and the order in which you specify them - when using keywords, - are purely personal choices; - &SCons; functions the same regardless. - - - -
- -
- Compiling Multiple Programs - - - - In order to compile multiple programs - within the same &SConstruct; file, - simply call the &Program; method - multiple times, - once for each program you need to build: - - - - - - Program('foo.c') - Program('bar', ['bar1.c', 'bar2.c']) - - - int main() { printf("foo.c\n"); } - - - int main() { printf("bar1.c\n"); } - - - void bar2() { printf("bar2.c\n"); } - - - - - - &SCons; would then build the programs as follows: - - - - - scons -Q - - - - - Notice that &SCons; does not necessarily build the - programs in the same order in which you specify - them in the &SConstruct; file. - &SCons; does, however, recognize that - the individual object files must be built - before the resulting program can be built. - We'll discuss this in greater detail in - the "Dependencies" section, below. - - - -
- -
- Sharing Source Files Between Multiple Programs - - - - It's common to re-use code by sharing source files - between multiple programs. - One way to do this is to create a library - from the common source files, - which can then be linked into resulting programs. - (Creating libraries is discussed in - , below.) - - - - - - A more straightforward, but perhaps less convenient, - way to share source files between multiple programs - is simply to include the common files - in the lists of source files for each program: - - - - - - Program(Split('foo.c common1.c common2.c')) - Program('bar', Split('bar1.c bar2.c common1.c common2.c')) - - - int main() { printf("foo.c\n"); } - - - int main() { printf("bar1.c\n"); } - - - int bar2() { printf("bar2.c\n"); } - - - void common1() { printf("common1.c\n"); } - - - void common22() { printf("common2.c\n"); } - - - - - - &SCons; recognizes that the object files for - the &common1_c; and &common2_c; source files - each need to be built only once, - even though the resulting object files are - each linked in to both of the resulting executable programs: - - - - - scons -Q - - - - - If two or more programs - share a lot of common source files, - repeating the common files in the list for each program - can be a maintenance problem when you need to change the - list of common files. - You can simplify this by creating a separate Python list - to hold the common file names, - and concatenating it with other lists - using the Python + operator: - - - - - common = ['common1.c', 'common2.c'] - foo_files = ['foo.c'] + common - bar_files = ['bar1.c', 'bar2.c'] + common - Program('foo', foo_files) - Program('bar', bar_files) - - - - - This is functionally equivalent to the previous example. - - - -
diff --git a/doc/user/less-simple.xml b/doc/user/less-simple.xml index a2b5cf6..fcffa5e 100644 --- a/doc/user/less-simple.xml +++ b/doc/user/less-simple.xml @@ -63,9 +63,14 @@
- + + Program('new_hello', 'hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -85,11 +90,9 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o new_hello hello.o - + + scons -Q + @@ -98,12 +101,9 @@ - - C:\>scons -Q - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:new_hello.exe hello.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -124,9 +124,20 @@ - + + Program(['prog.c', 'file1.c', 'file2.c']) - + + + int main() { printf("prog.c\n"); } + + + void file1() { printf("file1.c\n"); } + + + void file2() { printf("file2.c\n"); } + + @@ -134,13 +145,9 @@ - - % scons -Q - cc -o file1.o -c file1.c - cc -o file2.o -c file2.c - cc -o prog.o -c prog.c - cc -o prog prog.o file1.o file2.o - + + scons -Q + @@ -164,9 +171,20 @@ - + + Program('program', ['prog.c', 'file1.c', 'file2.c']) - + + + int main() { printf("prog.c\n"); } + + + void file1() { printf("file1.c\n"); } + + + void file2() { printf("file2.c\n"); } + + @@ -174,13 +192,9 @@ - - % scons -Q - cc -o file1.o -c file1.c - cc -o file2.o -c file2.c - cc -o prog.o -c prog.c - cc -o program prog.o file1.o file2.o - + + scons -Q + @@ -188,14 +202,9 @@ - - C:\>scons -Q - cl /Fofile1.obj /c file1.c /nologo - cl /Fofile2.obj /c file2.c /nologo - cl /Foprog.obj /c prog.c /nologo - link /nologo /OUT:program.exe prog.obj file1.obj file2.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -216,9 +225,9 @@ - + Program('program', Glob('*.c')) - + @@ -244,9 +253,9 @@ - + Program('hello', ['file1.c', 'file2.c']) - + @@ -254,9 +263,9 @@ - + Program('hello', 'hello.c') - + @@ -265,9 +274,9 @@ - + Program('hello', ['hello.c']) - + @@ -293,11 +302,11 @@ - + # The following two calls both work correctly: Program('program1', 'program1.c') Program('program2', ['program2.c']) - + @@ -306,7 +315,7 @@ - + common_sources = ['file1.c', 'file2.c'] # THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR @@ -316,7 +325,7 @@ # The following works correctly, because it's adding two # lists together to make another list. Program('program2', common_sources + ['program2.c']) - + @@ -482,10 +491,21 @@ - + + Program('foo.c') Program('bar', ['bar1.c', 'bar2.c']) - + + + int main() { printf("foo.c\n"); } + + + int main() { printf("bar1.c\n"); } + + + void bar2() { printf("bar2.c\n"); } + + @@ -493,14 +513,9 @@ - - % scons -Q - cc -o bar1.o -c bar1.c - cc -o bar2.o -c bar2.c - cc -o bar bar1.o bar2.o - cc -o foo.o -c foo.c - cc -o foo foo.o - + + scons -Q + @@ -541,10 +556,27 @@ - + + Program(Split('foo.c common1.c common2.c')) Program('bar', Split('bar1.c bar2.c common1.c common2.c')) - + + + int main() { printf("foo.c\n"); } + + + int main() { printf("bar1.c\n"); } + + + int bar2() { printf("bar2.c\n"); } + + + void common1() { printf("common1.c\n"); } + + + void common22() { printf("common2.c\n"); } + + @@ -556,16 +588,9 @@ - - % scons -Q - cc -o bar1.o -c bar1.c - cc -o bar2.o -c bar2.c - cc -o common1.o -c common1.c - cc -o common2.o -c common2.c - cc -o bar bar1.o bar2.o common1.o common2.o - cc -o foo.o -c foo.c - cc -o foo foo.o common1.o common2.o - + + scons -Q + diff --git a/doc/user/libraries.in b/doc/user/libraries.in deleted file mode 100644 index e219e21..0000000 --- a/doc/user/libraries.in +++ /dev/null @@ -1,445 +0,0 @@ - - - - - It's often useful to organize large software projects - by collecting parts of the software into one or more libraries. - &SCons; makes it easy to create libraries - and to use them in the programs. - - - -
- Building Libraries - - - - You build your own libraries by specifying &b-link-Library; - instead of &b-link-Program;: - - - - - - Library('foo', ['f1.c', 'f2.c', 'f3.c']) - - - void f1() { printf("f1.c\n"); } - - - void f2() { printf("f2.c\n"); } - - - void f3() { printf("f3.c\n"); } - - - - - - &SCons; uses the appropriate library prefix and suffix for your system. - So on POSIX or Linux systems, - the above example would build as follows - (although &ranlib; may not be called on all systems): - - - - - scons -Q - - - - - On a Windows system, - a build of the above example would look like: - - - - - scons -Q - - - - - The rules for the target name of the library - are similar to those for programs: - if you don't explicitly specify a target library name, - &SCons; will deduce one from the - name of the first source file specified, - and &SCons; will add an appropriate - file prefix and suffix if you leave them off. - - - -
- Building Libraries From Source Code or Object Files - - - - The previous example shows building a library from a - list of source files. - You can, however, also give the &b-link-Library; call - object files, - and it will correctly realize - In fact, you can arbitrarily mix source code files - and object files in the source list: - - - - - - Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o']) - - - void f1() { printf("f1.c\n"); } - - - object file - - - void f3() { printf("f3.c\n"); } - - - object file - - - - - - And SCons realizes that only the source code files - must be compiled into object files - before creating the final library: - - - - - scons -Q - - - - - Of course, in this example, the object files - must already exist for the build to succeed. - See , below, - for information about how you can - build object files explicitly - and include the built files in a library. - - - -
- -
- Building Static Libraries Explicitly: the &b-StaticLibrary; Builder - - - - The &b-link-Library; function builds a traditional static library. - If you want to be explicit about the type of library being built, - you can use the synonym &b-link-StaticLibrary; function - instead of &b-Library;: - - - - - - StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) - - - - - - There is no functional difference between the - &b-link-StaticLibrary; and &b-Library; functions. - - - -
- -
- Building Shared (DLL) Libraries: the &b-SharedLibrary; Builder - - - - If you want to build a shared library (on POSIX systems) - or a DLL file (on Windows systems), - you use the &b-link-SharedLibrary; function: - - - - - - SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) - - - void f1() { printf("f1.c\n"); } - - - void f2() { printf("f2.c\n"); } - - - void f3() { printf("f3.c\n"); } - - - - - - The output on POSIX: - - - - - scons -Q - - - - - And the output on Windows: - - - - - scons -Q - - - - - Notice again that &SCons; takes care of - building the output file correctly, - adding the -shared option - for a POSIX compilation, - and the /dll option on Windows. - - - -
- -
- -
- Linking with Libraries - - - - Usually, you build a library - because you want to link it with one or more programs. - You link libraries with a program by specifying - the libraries in the &cv-link-LIBS; construction variable, - and by specifying the directory in which - the library will be found in the - &cv-link-LIBPATH; construction variable: - - - - - - - - Library('foo', ['f1.c', 'f2.c', 'f3.c']) - Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Hello, world!\n"); } - - - - - - Notice, of course, that you don't need to specify a library - prefix (like lib) - or suffix (like .a or .lib). - &SCons; uses the correct prefix or suffix for the current system. - - - - - - On a POSIX or Linux system, - a build of the above example would look like: - - - - - scons -Q - - - - - On a Windows system, - a build of the above example would look like: - - - - - scons -Q - - - - - As usual, notice that &SCons; has taken care - of constructing the correct command lines - to link with the specified library on each system. - - - - - - Note also that, - if you only have a single library to link with, - you can specify the library name in single string, - instead of a Python list, - so that: - - - - - Program('prog.c', LIBS='foo', LIBPATH='.') - - - - - is equivalent to: - - - - - Program('prog.c', LIBS=['foo'], LIBPATH='.') - - - - - This is similar to the way that &SCons; - handles either a string or a list to - specify a single source file. - - - -
- -
- Finding Libraries: the &cv-LIBPATH; Construction Variable - - - - By default, the linker will only look in - certain system-defined directories for libraries. - &SCons; knows how to look for libraries - in directories that you specify with the - &cv-link-LIBPATH; construction variable. - &cv-LIBPATH; consists of a list of - directory names, like so: - - - - - - Program('prog.c', LIBS = 'm', - LIBPATH = ['/usr/lib', '/usr/local/lib']) - - - int main() { printf("prog.c\n"); } - - - - - - Using a Python list is preferred because it's portable - across systems. Alternatively, you could put all of - the directory names in a single string, separated by the - system-specific path separator character: - a colon on POSIX systems: - - - - - LIBPATH = '/usr/lib:/usr/local/lib' - - - - - or a semi-colon on Windows systems: - - - - - LIBPATH = 'C:\\lib;D:\\lib' - - - - - (Note that Python requires that the backslash - separators in a Windows path name - be escaped within strings.) - - - - - - When the linker is executed, - &SCons; will create appropriate flags - so that the linker will look for - libraries in the same directories as &SCons;. - So on a POSIX or Linux system, - a build of the above example would look like: - - - - - scons -Q - - - - - On a Windows system, - a build of the above example would look like: - - - - - scons -Q - - - - - - Note again that &SCons; has taken care of - the system-specific details of creating - the right command-line options. - - - -
diff --git a/doc/user/libraries.xml b/doc/user/libraries.xml index 9347668..e219e21 100644 --- a/doc/user/libraries.xml +++ b/doc/user/libraries.xml @@ -42,9 +42,20 @@
- + + Library('foo', ['f1.c', 'f2.c', 'f3.c']) - + + + void f1() { printf("f1.c\n"); } + + + void f2() { printf("f2.c\n"); } + + + void f3() { printf("f3.c\n"); } + + @@ -55,14 +66,9 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f2.o -c f2.c - cc -o f3.o -c f3.c - ar rc libfoo.a f1.o f2.o f3.o - ranlib libfoo.a - + + scons -Q + @@ -71,13 +77,9 @@ - - C:\>scons -Q - cl /Fof1.obj /c f1.c /nologo - cl /Fof2.obj /c f2.c /nologo - cl /Fof3.obj /c f3.c /nologo - lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj - + + scons -Q + @@ -106,9 +108,23 @@ - + + Library('foo', ['f1.c', 'f2.o', 'f3.c', 'f4.o']) - + + + void f1() { printf("f1.c\n"); } + + + object file + + + void f3() { printf("f3.c\n"); } + + + object file + + @@ -118,13 +134,9 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f3.o -c f3.c - ar rc libfoo.a f1.o f2.o f3.o f4.o - ranlib libfoo.a - + + scons -Q + @@ -151,9 +163,11 @@ - + + StaticLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) - + + @@ -175,9 +189,20 @@ - + + SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) - + + + void f1() { printf("f1.c\n"); } + + + void f2() { printf("f2.c\n"); } + + + void f3() { printf("f3.c\n"); } + + @@ -185,13 +210,9 @@ - - % scons -Q - cc -o f1.os -c f1.c - cc -o f2.os -c f2.c - cc -o f3.os -c f3.c - cc -o libfoo.so -shared f1.os f2.os f3.os - + + scons -Q + @@ -199,15 +220,9 @@ - - C:\>scons -Q - cl /Fof1.obj /c f1.c /nologo - cl /Fof2.obj /c f2.c /nologo - cl /Fof3.obj /c f3.c /nologo - link /nologo /dll /out:foo.dll /implib:foo.lib f1.obj f2.obj f3.obj - RegServerFunc(target, source, env) - embedManifestDllCheck(target, source, env) - + + scons -Q + @@ -242,10 +257,24 @@ - + + Library('foo', ['f1.c', 'f2.c', 'f3.c']) Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') - + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Hello, world!\n"); } + + @@ -263,16 +292,9 @@ - - % scons -Q - cc -o f1.o -c f1.c - cc -o f2.o -c f2.c - cc -o f3.o -c f3.c - ar rc libfoo.a f1.o f2.o f3.o - ranlib libfoo.a - cc -o prog.o -c prog.c - cc -o prog prog.o -L. -lfoo -lbar - + + scons -Q + @@ -281,16 +303,9 @@ - - C:\>scons -Q - cl /Fof1.obj /c f1.c /nologo - cl /Fof2.obj /c f2.c /nologo - cl /Fof3.obj /c f3.c /nologo - lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj - cl /Foprog.obj /c prog.c /nologo - link /nologo /OUT:prog.exe /LIBPATH:. foo.lib bar.lib prog.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -310,9 +325,9 @@ - + Program('prog.c', LIBS='foo', LIBPATH='.') - + @@ -320,9 +335,9 @@ - + Program('prog.c', LIBS=['foo'], LIBPATH='.') - + @@ -349,10 +364,15 @@ - + + Program('prog.c', LIBS = 'm', LIBPATH = ['/usr/lib', '/usr/local/lib']) - + + + int main() { printf("prog.c\n"); } + + @@ -364,9 +384,9 @@ - + LIBPATH = '/usr/lib:/usr/local/lib' - + @@ -374,9 +394,9 @@ - + LIBPATH = 'C:\\lib;D:\\lib' - + @@ -397,11 +417,9 @@ - - % scons -Q - cc -o prog.o -c prog.c - cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm - + + scons -Q + @@ -410,12 +428,9 @@ - - C:\>scons -Q - cl /Foprog.obj /c prog.c /nologo - link /nologo /OUT:prog.exe /LIBPATH:\usr\lib /LIBPATH:\usr\local\lib m.lib prog.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + diff --git a/doc/user/main.in b/doc/user/main.in deleted file mode 100644 index 61b544f..0000000 --- a/doc/user/main.in +++ /dev/null @@ -1,411 +0,0 @@ - - - - - %version; - - - %scons; - - - %builders-mod; - - - %functions-mod; - - - %tools-mod; - - - %variables-mod; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]> - - - - - - SCons User Guide &buildversion; - - - Steven - Knight - - - Revision &buildrevision; (&builddate;) - - 2004, 2005, 2006, 2007, 2008, 2009, 2010 - - - 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Steven Knight - - - - ©right; - - - version &buildversion; - - - - - Preface - &preface; - - - - Building and Installing &SCons; - &build-install; - - - - Simple Builds - &simple; - - - - Less Simple Things to Do With Builds - &less-simple; - - - - Building and Linking with Libraries - &libraries; - - - - Node Objects - &nodes; - - - - Dependencies - &depends; - - - - Environments - &environments; - - - - Automatically Putting Command-line Options into their Construction Variables - - - This chapter describes the &MergeFlags;, &ParseFlags;, and &ParseConfig; methods of a &consenv;. - -
- Merging Options into the Environment: the &MergeFlags; Function - &mergeflags; -
-
- Separating Compile Arguments into their Variables: the &ParseFlags; Function - &parseflags; -
-
- Finding Installed Library Information: the &ParseConfig; Function - &parseconfig; -
- -
- - - Controlling Build Output - &output; - - - - Controlling a Build From the Command Line - &command-line; - - - - Installing Files in Other Directories: the &Install; Builder - &install; - - - - Platform-Independent File System Manipulation - &factories; - - - - Controlling Removal of Targets - &file-removal; - - - - Hierarchical Builds - &hierarchy; - - - - Separating Source and Build Directories - &separate; - - - - Variant Builds - &variants; - - - - Internationalization and localization with gettext - &gettext; - - - - - - Writing Your Own Builders - &builders-writing; - - - - Not Writing a Builder: the &Command; Builder - &builders-commands; - - - - Pseudo-Builders: the AddMethod function - &add-method; - - - - - - Writing Scanners - &scanners; - - - - Building From Code Repositories - &repositories; - - - - Multi-Platform Configuration (&Autoconf; Functionality) - &sconf; - - - - - - Caching Built Files - &caching; - - - - Alias Targets - &alias; - - - - Java Builds - &java; - - - - - - Miscellaneous Functionality - &misc; - - - - Troubleshooting - &troubleshoot; - - - - Construction Variables - &variables-xml; - - - - Builders - &builders; - - - - Tools - &tools; - - - - Functions and Environment Methods - &functions; - - - - Handling Common Tasks - &tasks; - - - - -
diff --git a/doc/user/make.in b/doc/user/make.in deleted file mode 100644 index 72b2df1..0000000 --- a/doc/user/make.in +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - XXX - - - -
- Differences Between &Make; and &SCons; - - - - XXX - - - -
- -
- Advantages of &SCons; Over &Make; - - - - XXX - - - -
diff --git a/doc/user/mergeflags.in b/doc/user/mergeflags.in deleted file mode 100644 index a148409..0000000 --- a/doc/user/mergeflags.in +++ /dev/null @@ -1,137 +0,0 @@ - - - - - &SCons; construction environments have a &MergeFlags; method - that merges a dictionary of values into the construction environment. - &MergeFlags; treats each value in the dictionary - as a list of options such as one might pass to a command - (such as a compiler or linker). - &MergeFlags; will not duplicate an option - if it already exists in the construction environment variable. - - - - - - &MergeFlags; tries to be intelligent about merging options. - When merging options to any variable - whose name ends in PATH, - &MergeFlags; keeps the leftmost occurrence of the option, - because in typical lists of directory paths, - the first occurrence "wins." - When merging options to any other variable name, - &MergeFlags; keeps the rightmost occurrence of the option, - because in a list of typical command-line options, - the last occurrence "wins." - - - - - - env = Environment() - env.Append(CCFLAGS = '-option -O3 -O1') - flags = { 'CCFLAGS' : '-whatever -O3' } - env.MergeFlags(flags) - print env['CCFLAGS'] - - - - - scons -Q - - - - - Note that the default value for &cv-link-CCFLAGS; - - is an internal &SCons; object - which automatically converts - the options we specified as a string into a list. - - - - - - env = Environment() - env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) - flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] } - env.MergeFlags(flags) - print env['CPPPATH'] - - - - - scons -Q - - - - - Note that the default value for &cv-link-CPPPATH; - - is a normal Python list, - so we must specify its values as a list - in the dictionary we pass to the &MergeFlags; function. - - - - - - If &MergeFlags; is passed anything other than a dictionary, - it calls the &ParseFlags; method to convert it into a dictionary. - - - - - - env = Environment() - env.Append(CCFLAGS = '-option -O3 -O1') - env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) - env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include') - print env['CCFLAGS'] - print env['CPPPATH'] - - - - - scons -Q - - - - - In the combined example above, - &ParseFlags; has sorted the options into their corresponding variables - and returned a dictionary for &MergeFlags; to apply - to the construction variables - in the specified construction environment. - - diff --git a/doc/user/mergeflags.xml b/doc/user/mergeflags.xml index 723ab74..a148409 100644 --- a/doc/user/mergeflags.xml +++ b/doc/user/mergeflags.xml @@ -50,19 +50,19 @@ - + + env = Environment() env.Append(CCFLAGS = '-option -O3 -O1') flags = { 'CCFLAGS' : '-whatever -O3' } env.MergeFlags(flags) print env['CCFLAGS'] - + + - - % scons -Q - ['-option', '-O1', '-whatever', '-O3'] - scons: `.' is up to date. - + + scons -Q + @@ -77,19 +77,19 @@ - + + env = Environment() env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) flags = { 'CPPPATH' : ['/usr/opt/include', '/usr/local/include'] } env.MergeFlags(flags) print env['CPPPATH'] - + + - - % scons -Q - ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] - scons: `.' is up to date. - + + scons -Q + @@ -111,21 +111,20 @@ - + + env = Environment() env.Append(CCFLAGS = '-option -O3 -O1') env.Append(CPPPATH = ['/include', '/usr/local/include', '/usr/include']) env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include') print env['CCFLAGS'] print env['CPPPATH'] - - - - % scons -Q - ['-option', '-O1', '-whatever', '-O3'] - ['/include', '/usr/local/include', '/usr/include', '/usr/opt/include'] - scons: `.' is up to date. - + + + + + scons -Q + diff --git a/doc/user/misc.in b/doc/user/misc.in deleted file mode 100644 index dde75bf..0000000 --- a/doc/user/misc.in +++ /dev/null @@ -1,606 +0,0 @@ - - - - - &SCons; supports a lot of additional functionality - that doesn't readily fit into the other chapters. - - - -
- Verifying the Python Version: the &EnsurePythonVersion; Function - - - - Although the &SCons; code itself will run - on any 2.x Python version 2.4 or later, - you are perfectly free to make use of - Python syntax and modules from more modern versions - (for example, Python 2.5 or 2.6) - when writing your &SConscript; files - or your own local modules. - If you do this, it's usually helpful to - configure &SCons; to exit gracefully with an error message - if it's being run with a version of Python - that simply won't work with your code. - This is especially true if you're going to use &SCons; - to build source code that you plan to distribute publicly, - where you can't be sure of the Python version - that an anonymous remote user might use - to try to build your software. - - - - - - &SCons; provides an &EnsurePythonVersion; function for this. - You simply pass it the major and minor versions - numbers of the version of Python you require: - - - - - - - EnsurePythonVersion(2, 5) - - - - - And then &SCons; will exit with the following error - message when a user runs it with an unsupported - earlier version of Python: - - - - - - - % scons -Q - Python 2.5 or greater required, but you have Python 2.3.6 - - -
- -
- Verifying the SCons Version: the &EnsureSConsVersion; Function - - - - You may, of course, write your &SConscript; files - to use features that were only added in - recent versions of &SCons;. - When you publicly distribute software that is built using &SCons;, - it's helpful to have &SCons; - verify the version being used and - exit gracefully with an error message - if the user's version of &SCons; won't work - with your &SConscript; files. - &SCons; provides an &EnsureSConsVersion; function - that verifies the version of &SCons; - in the same - the &EnsurePythonVersion; function - verifies the version of Python, - by passing in the major and minor versions - numbers of the version of SCons you require: - - - - - - - EnsureSConsVersion(1, 0) - - - - - And then &SCons; will exit with the following error - message when a user runs it with an unsupported - earlier version of &SCons;: - - - - - - - % scons -Q - SCons 1.0 or greater required, but you have SCons 0.98.5 - - -
- -
- Explicitly Terminating &SCons; While Reading &SConscript; Files: the &Exit; Function - - - - &SCons; supports an &Exit; function - which can be used to terminate &SCons; - while reading the &SConscript; files, - usually because you've detected a condition - under which it doesn't make sense to proceed: - - - - - - if ARGUMENTS.get('FUTURE'): - print "The FUTURE option is not supported yet!" - Exit(2) - env = Environment() - env.Program('hello.c') - - - hello.c - - - - - scons -Q FUTURE=1 - scons -Q - - - - - The &Exit; function takes as an argument - the (numeric) exit status that you want &SCons; to exit with. - If you don't specify a value, - the default is to exit with 0, - which indicates successful execution. - - - - - - Note that the &Exit; function - is equivalent to calling the Python - sys.exit function - (which the it actually calls), - but because &Exit; is a &SCons; function, - you don't have to import the Python - sys module to use it. - - - -
- -
- Searching for Files: the &FindFile; Function - - - - The &FindFile; function searches for a file in a list of directories. - If there is only one directory, it can be given as a simple string. - The function returns a File node if a matching file exists, - or None if no file is found. - (See the documentation for the &Glob; function for an alternative way - of searching for entries in a directory.) - - - - - - # one directory - print FindFile('missing', '.') - t = FindFile('exists', '.') - print t.__class__, t - - - exists - - - - - scons -Q - - - - - # several directories - includes = [ '.', 'include', 'src/include'] - headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] - for hdr in headers: - print '%-12s' % ('%s:' % hdr), FindFile(hdr, includes) - - - exists - - - - - exists - - - - exists - - - - - scons -Q - - - - - - - If the file exists in more than one directory, - only the first occurrence is returned. - - - - - - print FindFile('multiple', ['sub1', 'sub2', 'sub3']) - print FindFile('multiple', ['sub2', 'sub3', 'sub1']) - print FindFile('multiple', ['sub3', 'sub1', 'sub2']) - - - - exists - - - - exists - - - - exists - - - - - scons -Q - - - - - - - In addition to existing files, &FindFile; will also find derived files - (that is, non-leaf files) that haven't been built yet. - (Leaf files should already exist, or the build will fail!) - - - - - - # Neither file exists, so build will fail - Command('derived', 'leaf', 'cat >$TARGET $SOURCE') - print FindFile('leaf', '.') - print FindFile('derived', '.') - - - - - scons -Q - - - - - # Only 'leaf' exists - Command('derived', 'leaf', 'cat >$TARGET $SOURCE') - print FindFile('leaf', '.') - print FindFile('derived', '.') - - - leaf - - - - - scons -Q - - - - - If a source file exists, &FindFile; will correctly return the name - in the build directory. - - - - - - # Only 'src/leaf' exists - VariantDir('build', 'src') - print FindFile('leaf', 'build') - - - - leaf - - - - - scons -Q - - -
- -
- Handling Nested Lists: the &Flatten; Function - - - - &SCons; supports a &Flatten; function - which takes an input Python sequence - (list or tuple) - and returns a flattened list - containing just the individual elements of - the sequence. - This can be handy when trying to examine - a list composed of the lists - returned by calls to various Builders. - For example, you might collect - object files built in different ways - into one call to the &Program; Builder - by just enclosing them in a list, as follows: - - - - - - objects = [ - Object('prog1.c'), - Object('prog2.c', CCFLAGS='-DFOO'), - ] - Program(objects) - - - prog1.c - - - prog2.c - - - - - - Because the Builder calls in &SCons; - flatten their input lists, - this works just fine to build the program: - - - - - scons -Q - - - - - But if you were debugging your build - and wanted to print the absolute path - of each object file in the - objects list, - you might try the following simple approach, - trying to print each Node's - abspath - attribute: - - - - - - objects = [ - Object('prog1.c'), - Object('prog2.c', CCFLAGS='-DFOO'), - ] - Program(objects) - - for object_file in objects: - print object_file.abspath - - - prog1.c - - - prog2.c - - - - - - This does not work as expected - because each call to str - is operating an embedded list returned by - each &Object; call, - not on the underlying Nodes within those lists: - - - - - scons -Q - - - - - The solution is to use the &Flatten; function - so that you can pass each Node to - the str separately: - - - - - - objects = [ - Object('prog1.c'), - Object('prog2.c', CCFLAGS='-DFOO'), - ] - Program(objects) - - for object_file in Flatten(objects): - print object_file.abspath - - - prog1.c - - - prog2.c - - - - - - - % scons -Q - /home/me/project/prog1.o - /home/me/project/prog2.o - cc -o prog1.o -c prog1.c - cc -o prog2.o -c -DFOO prog2.c - cc -o prog1 prog1.o prog2.o - - -
- -
- Finding the Invocation Directory: the &GetLaunchDir; Function - - - - If you need to find the directory from - which the user invoked the &scons; command, - you can use the &GetLaunchDir; function: - - - - - env = Environment( - LAUNCHDIR = GetLaunchDir(), - ) - env.Command('directory_build_info', - '$LAUNCHDIR/build_info' - Copy('$TARGET', '$SOURCE')) - - - - - Because &SCons; is usually invoked from the top-level - directory in which the &SConstruct; file lives, - the Python os.getcwd() - is often equivalent. - However, the &SCons; - -u, - -U - and - -D - command-line options, - when invoked from a subdirectory, - will cause &SCons; to change to the directory - in which the &SConstruct; file is found. - When those options are used, - &GetLaunchDir; will still return the path to the - user's invoking subdirectory, - allowing the &SConscript; configuration - to still get at configuration (or other) files - from the originating directory. - - - -
diff --git a/doc/user/misc.xml b/doc/user/misc.xml index a8885d7..dde75bf 100644 --- a/doc/user/misc.xml +++ b/doc/user/misc.xml @@ -76,9 +76,9 @@ --> - + EnsurePythonVersion(2, 5) - + @@ -145,9 +145,9 @@ --> - + EnsureSConsVersion(1, 0) - + @@ -189,21 +189,23 @@ - + + if ARGUMENTS.get('FUTURE'): print "The FUTURE option is not supported yet!" Exit(2) env = Environment() env.Program('hello.c') - + + + hello.c + + - - % scons -Q FUTURE=1 - The FUTURE option is not supported yet! - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q FUTURE=1 + scons -Q + @@ -243,36 +245,47 @@ - + + # one directory print FindFile('missing', '.') t = FindFile('exists', '.') print t.__class__, t - + + + exists + + - - % scons -Q - None - <class 'SCons.Node.FS.File'> exists - scons: `.' is up to date. - + + scons -Q + - + + # several directories includes = [ '.', 'include', 'src/include'] headers = [ 'nonesuch.h', 'config.h', 'private.h', 'dist.h'] for hdr in headers: print '%-12s' % ('%s:' % hdr), FindFile(hdr, includes) - + + + exists + + + + + exists + + + + exists + + - - % scons -Q - nonesuch.h: None - config.h: config.h - private.h: src/include/private.h - dist.h: include/dist.h - scons: `.' is up to date. - + + scons -Q + @@ -339,38 +362,34 @@ - + + # Neither file exists, so build will fail - Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') print FindFile('leaf', '.') print FindFile('derived', '.') - - - - % scons -Q - None - derived - scons: *** [derived] Source `leaf' not found, needed by target `derived'. - + + - - # Neither file exists, so build will fail - Command('derived', 'leaf', 'cat >$TARGET $SOURCE') - print FindFile('leaf', '.') - print FindFile('derived', '.') + + scons -Q + + + # Only 'leaf' exists - Command('derived', 'leaf', 'cat >$TARGET $SOURCE') + Command('derived', 'leaf', 'cat >$TARGET $SOURCE') print FindFile('leaf', '.') print FindFile('derived', '.') - - - - % scons -Q + + leaf - derived - cat > derived leaf - + + + + + scons -Q + @@ -379,17 +398,21 @@ - + + # Only 'src/leaf' exists VariantDir('build', 'src') print FindFile('leaf', 'build') - + + + + leaf + + - - % scons -Q - build/leaf - scons: `.' is up to date. - + + scons -Q + @@ -414,13 +437,21 @@
- + + objects = [ Object('prog1.c'), Object('prog2.c', CCFLAGS='-DFOO'), ] Program(objects) - + + + prog1.c + + + prog2.c + + @@ -430,12 +461,9 @@ - - % scons -Q - cc -o prog1.o -c prog1.c - cc -o prog2.o -c -DFOO prog2.c - cc -o prog1 prog1.o prog2.o - + + scons -Q + @@ -450,7 +478,8 @@ - + + objects = [ Object('prog1.c'), Object('prog2.c', CCFLAGS='-DFOO'), @@ -459,7 +488,14 @@ for object_file in objects: print object_file.abspath - + + + prog1.c + + + prog2.c + + @@ -471,12 +507,9 @@ - - % scons -Q - AttributeError: 'NodeList' object has no attribute 'abspath': - File "/home/my/project/SConstruct", line 8: - print object_file.abspath - + + scons -Q + @@ -486,7 +519,8 @@ - + + objects = [ Object('prog1.c'), Object('prog2.c', CCFLAGS='-DFOO'), @@ -495,7 +529,14 @@ for object_file in Flatten(objects): print object_file.abspath - + + + prog1.c + + + prog2.c + + - - - - Internally, &SCons; represents all of the files - and directories it knows about as &Nodes;. - These internal objects - (not object files) - can be used in a variety of ways - to make your &SConscript; - files portable and easy to read. - - - -
- Builder Methods Return Lists of Target Nodes - - - - All builder methods return a list of - &Node; objects that identify the - target file or files that will be built. - These returned &Nodes; can be passed - as arguments to other builder methods. - - - - - - For example, suppose that we want to build - the two object files that make up a program with different options. - This would mean calling the &b-link-Object; - builder once for each object file, - specifying the desired options: - - - - - Object('hello.c', CCFLAGS='-DHELLO') - Object('goodbye.c', CCFLAGS='-DGOODBYE') - - - - - One way to combine these object files - into the resulting program - would be to call the &b-link-Program; - builder with the names of the object files - listed as sources: - - - - - Object('hello.c', CCFLAGS='-DHELLO') - Object('goodbye.c', CCFLAGS='-DGOODBYE') - Program(['hello.o', 'goodbye.o']) - - - - - The problem with specifying the names as strings - is that our &SConstruct; file is no longer portable - across operating systems. - It won't, for example, work on Windows - because the object files there would be - named &hello_obj; and &goodbye_obj;, - not &hello_o; and &goodbye_o;. - - - - - - A better solution is to assign the lists of targets - returned by the calls to the &b-Object; builder to variables, - which we can then concatenate in our - call to the &b-Program; builder: - - - - - - hello_list = Object('hello.c', CCFLAGS='-DHELLO') - goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE') - Program(hello_list + goodbye_list) - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Goodbye, world!\n"); } - - - - - - This makes our &SConstruct; file portable again, - the build output on Linux looking like: - - - - - scons -Q - - - - - And on Windows: - - - - - scons -Q - - - - - We'll see examples of using the list of nodes - returned by builder methods throughout - the rest of this guide. - - - -
- -
- Explicitly Creating File and Directory Nodes - - - - It's worth mentioning here that - &SCons; maintains a clear distinction - between Nodes that represent files - and Nodes that represent directories. - &SCons; supports &File; and &Dir; - functions that, respectively, - return a file or directory Node: - - - - - - hello_c = File('hello.c') - Program(hello_c) - - classes = Dir('classes') - Java(classes, 'src') - - - - - - Normally, you don't need to call - &File; or &Dir; directly, - because calling a builder method automatically - treats strings as the names of files or directories, - and translates them into - the Node objects for you. - The &File; and &Dir; functions can come in handy - in situations where you need to explicitly - instruct &SCons; about the type of Node being - passed to a builder or other function, - or unambiguously refer to a specific - file in a directory tree. - - - - - - - There are also times when you may need to - refer to an entry in a file system - without knowing in advance - whether it's a file or a directory. - For those situations, - &SCons; also supports an &Entry; function, - which returns a Node - that can represent either a file or a directory. - - - - - xyzzy = Entry('xyzzy') - - - - - The returned xyzzy Node - will be turned into a file or directory Node - the first time it is used by a builder method - or other function that - requires one vs. the other. - - - -
- -
- Printing &Node; File Names - - - - One of the most common things you can do - with a Node is use it to print the - file name that the node represents. - Keep in mind, though, that because the object - returned by a builder call - is a list of Nodes, - you must use Python subscripts - to fetch individual Nodes from the list. - For example, the following &SConstruct; file: - - - - - - object_list = Object('hello.c') - program_list = Program(object_list) - print "The object file is:", object_list[0] - print "The program file is:", program_list[0] - - - int main() { printf("Hello, world!\n"); } - - - - - - Would print the following file names on a POSIX system: - - - - - scons -Q - - - - - And the following file names on a Windows system: - - - - - scons -Q - - - - - Note that in the above example, - the object_list[0] - extracts an actual Node object - from the list, - and the Python print statement - converts the object to a string for printing. - - - -
- -
- Using a &Node;'s File Name as a String - - - - Printing a &Node;'s name - as described in the previous section - works because the string representation of a &Node; object - is the name of the file. - If you want to do something other than - print the name of the file, - you can fetch it by using the builtin Python - &str; function. - For example, if you want to use the Python - os.path.exists - to figure out whether a file - exists while the &SConstruct; file - is being read and executed, - you can fetch the string as follows: - - - - - - import os.path - program_list = Program('hello.c') - program_name = str(program_list[0]) - if not os.path.exists(program_name): - print program_name, "does not exist!" - - - int main() { printf("Hello, world!\n"); } - - - - - - Which executes as follows on a POSIX system: - - - - - scons -Q - - -
- -
- &GetBuildPath;: Getting the Path From a &Node; or String - - - - env.GetBuildPath(file_or_list) - returns the path of a &Node; or a string representing a - path. It can also take a list of &Node;s and/or strings, and - returns the list of paths. If passed a single &Node;, the result - is the same as calling str(node) (see above). - The string(s) can have embedded construction variables, which are - expanded as usual, using the calling environment's set of - variables. The paths can be files or directories, and do not have - to exist. - - - - - - env=Environment(VAR="value") - n=File("foo.c") - print env.GetBuildPath([n, "sub/dir/$VAR"]) - - - - - - Would print the following file names: - - - - - scons -Q - - - - - There is also a function version of &GetBuildPath; which can - be called without an &Environment;; that uses the default SCons - &Environment; to do substitution on any string arguments. - - - -
- - - - diff --git a/doc/user/nodes.xml b/doc/user/nodes.xml index 42d44c6..fb5ce23 100644 --- a/doc/user/nodes.xml +++ b/doc/user/nodes.xml @@ -58,10 +58,10 @@ - + Object('hello.c', CCFLAGS='-DHELLO') Object('goodbye.c', CCFLAGS='-DGOODBYE') - + @@ -73,11 +73,11 @@ - + Object('hello.c', CCFLAGS='-DHELLO') Object('goodbye.c', CCFLAGS='-DGOODBYE') Program(['hello.o', 'goodbye.o']) - + @@ -100,11 +100,19 @@ - + + hello_list = Object('hello.c', CCFLAGS='-DHELLO') goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE') Program(hello_list + goodbye_list) - + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Goodbye, world!\n"); } + + @@ -113,12 +121,9 @@ - - % scons -Q - cc -o goodbye.o -c -DGOODBYE goodbye.c - cc -o hello.o -c -DHELLO hello.c - cc -o hello hello.o goodbye.o - + + scons -Q + @@ -126,13 +131,9 @@ - - C:\>scons -Q - cl /Fogoodbye.obj /c goodbye.c -DGOODBYE - cl /Fohello.obj /c hello.c -DHELLO - link /nologo /OUT:hello.exe hello.obj goodbye.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -159,13 +160,15 @@ - + + hello_c = File('hello.c') Program(hello_c) classes = Dir('classes') Java(classes, 'src') - + + @@ -204,9 +207,9 @@ - + xyzzy = Entry('xyzzy') - + @@ -237,18 +240,17 @@ - - hello_c = File('hello.c') - Program(hello_c) - - classes = Dir('classes') - Java(classes, 'src') - + + object_list = Object('hello.c') program_list = Program(object_list) print "The object file is:", object_list[0] print "The program file is:", program_list[0] - + + + int main() { printf("Hello, world!\n"); } + + @@ -256,13 +258,9 @@ - - % scons -Q - The object file is: hello.o - The program file is: hello - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -270,14 +268,9 @@ - - C:\>scons -Q - The object file is: hello.obj - The program file is: hello.exe - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -314,13 +307,18 @@ - + + import os.path program_list = Program('hello.c') program_name = str(program_list[0]) if not os.path.exists(program_name): print program_name, "does not exist!" - + + + int main() { printf("Hello, world!\n"); } + + @@ -328,12 +326,9 @@ - - % scons -Q - hello does not exist! - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -354,11 +349,13 @@ - + + env=Environment(VAR="value") n=File("foo.c") print env.GetBuildPath([n, "sub/dir/$VAR"]) - + + @@ -366,11 +363,9 @@ - - % scons -Q - ['foo.c', 'sub/dir/value'] - scons: `.' is up to date. - + + scons -Q + diff --git a/doc/user/output.in b/doc/user/output.in deleted file mode 100644 index 1383fc0..0000000 --- a/doc/user/output.in +++ /dev/null @@ -1,681 +0,0 @@ - - - - - A key aspect of creating a usable build configuration - is providing good output from the build - so its users can readily understand - what the build is doing - and get information about how to control the build. - &SCons; provides several ways of - controlling output from the build configuration - to help make the build - more useful and understandable. - - - -
- Providing Build Help: the &Help; Function - - - - It's often very useful to be able to give - users some help that describes the - specific targets, build options, etc., - that can be used for your build. - &SCons; provides the &Help; function - to allow you to specify this help text: - - - - - - Help(""" - Type: 'scons program' to build the production program, - 'scons debug' to build the debug version. - """) - - - - - - (Note the above use of the Python triple-quote syntax, - which comes in very handy for - specifying multi-line strings like help text.) - - - - - - When the &SConstruct; or &SConscript; files - contain such a call to the &Help; function, - the specified help text will be displayed in response to - the &SCons; -h option: - - - - - scons -h - - - - - The &SConscript; files may contain - multiple calls to the &Help; function, - in which case the specified text(s) - will be concatenated when displayed. - This allows you to split up the - help text across multiple &SConscript; files. - In this situation, the order in - which the &SConscript; files are called - will determine the order in which the &Help; functions are called, - which will determine the order in which - the various bits of text will get concatenated. - - - - - - Another use would be to make the help text conditional - on some variable. - For example, suppose you only want to display - a line about building a Windows-only - version of a program when actually - run on Windows. - The following &SConstruct; file: - - - - - - env = Environment() - - Help("\nType: 'scons program' to build the production program.\n") - - if env['PLATFORM'] == 'win32': - Help("\nType: 'scons windebug' to build the Windows debug version.\n") - - - - - - Will display the complete help text on Windows: - - - - - scons -h - - - - - But only show the relevant option on a Linux or UNIX system: - - - - - scons -h - - - - - If there is no &Help; text in the &SConstruct; or - &SConscript; files, - &SCons; will revert to displaying its - standard list that describes the &SCons; command-line - options. - This list is also always displayed whenever - the -H option is used. - - - -
- -
- Controlling How &SCons; Prints Build Commands: the <envar>$*COMSTR</envar> Variables - - - - Sometimes the commands executed - to compile object files or link programs - (or build other targets) - can get very long, - long enough to make it difficult for users - to distinguish error messages or - other important build output - from the commands themselves. - All of the default $*COM variables - that specify the command lines - used to build various types of target files - have a corresponding $*COMSTR variable - that can be set to an alternative - string that will be displayed - when the target is built. - - - - - - For example, suppose you want to - have &SCons; display a - "Compiling" - message whenever it's compiling an object file, - and a - "Linking" - when it's linking an executable. - You could write a &SConstruct; file - that looks like: - - - - - - env = Environment(CCCOMSTR = "Compiling $TARGET", - LINKCOMSTR = "Linking $TARGET") - env.Program('foo.c') - - - foo.c - - - - - - Which would then yield the output: - - - - - - - % scons -Q - Compiling foo.o - Linking foo - - - - - &SCons; performs complete variable substitution - on $*COMSTR variables, - so they have access to all of the - standard variables like &cv-TARGET; &cv-SOURCES;, etc., - as well as any construction variables - that happen to be configured in - the construction environment - used to build a specific target. - - - - - - Of course, sometimes it's still important to - be able to see the exact command - that &SCons; will execute to build a target. - For example, you may simply need to verify - that &SCons; is configured to supply - the right options to the compiler, - or a developer may want to - cut-and-paste a compile command - to add a few options - for a custom test. - - - - - - One common way to give users - control over whether or not - &SCons; should print the actual command line - or a short, configured summary - is to add support for a - VERBOSE - command-line variable to your &SConstruct; file. - A simple configuration for this might look like: - - - - - - env = Environment() - if ARGUMENTS.get('VERBOSE') != "1': - env['CCCOMSTR'] = "Compiling $TARGET" - env['LINKCOMSTR'] = "Linking $TARGET" - env.Program('foo.c') - - - foo.c - - - - - - - By only setting the appropriate - $*COMSTR variables - if the user specifies - VERBOSE=1 - on the command line, - the user has control - over how &SCons; - displays these particular command lines: - - - - - - - % scons -Q - Compiling foo.o - Linking foo - % scons -Q -c - Removed foo.o - Removed foo - % scons -Q VERBOSE=1 - cc -o foo.o -c foo.c - cc -o foo foo.o - - -
- -
- Providing Build Progress Output: the &Progress; Function - - - - Another aspect of providing good build output - is to give the user feedback - about what &SCons; is doing - even when nothing is being built at the moment. - This can be especially true for large builds - when most of the targets are already up-to-date. - Because &SCons; can take a long time - making absolutely sure that every - target is, in fact, up-to-date - with respect to a lot of dependency files, - it can be easy for users to mistakenly - conclude that &SCons; is hung - or that there is some other problem with the build. - - - - - - One way to deal with this perception - is to configure &SCons; to print something to - let the user know what it's "thinking about." - The &Progress; function - allows you to specify a string - that will be printed for every file - that &SCons; is "considering" - while it is traversing the dependency graph - to decide what targets are or are not up-to-date. - - - - - - Progress('Evaluating $TARGET\n') - Program('f1.c') - Program('f2.c') - - - f1.c - - - f2.c - - - - - - Note that the &Progress; function does not - arrange for a newline to be printed automatically - at the end of the string (as does the Python - print statement), - and we must specify the - \n - that we want printed at the end of the configured string. - This configuration, then, - will have &SCons; - print that it is Evaluating - each file that it encounters - in turn as it traverses the dependency graph: - - - - - scons -Q - - - - - Of course, normally you don't want to add - all of these additional lines to your build output, - as that can make it difficult for the user - to find errors or other important messages. - A more useful way to display - this progress might be - to have the file names printed - directly to the user's screen, - not to the same standard output - stream where build output is printed, - and to use a carriage return character - (\r) - so that each file name gets re-printed on the same line. - Such a configuration would look like: - - - - - Progress('$TARGET\r', - file=open('/dev/tty', 'w'), - overwrite=True) - Program('f1.c') - Program('f2.c') - - - - - Note that we also specified the - overwrite=True argument - to the &Progress; function, - which causes &SCons; to - "wipe out" the previous string with space characters - before printing the next &Progress; string. - Without the - overwrite=True argument, - a shorter file name would not overwrite - all of the charactes in a longer file name that - precedes it, - making it difficult to tell what the - actual file name is on the output. - Also note that we opened up the - /dev/tty file - for direct access (on POSIX) to - the user's screen. - On Windows, the equivalent would be to open - the con: file name. - - - - - - Also, it's important to know that although you can use - $TARGET to substitute the name of - the node in the string, - the &Progress; function does not - perform general variable substitution - (because there's not necessarily a construction - environment involved in evaluating a node - like a source file, for example). - - - - - - You can also specify a list of strings - to the &Progress; function, - in which case &SCons; will - display each string in turn. - This can be used to implement a "spinner" - by having &SCons; cycle through a - sequence of strings: - - - - - Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5) - Program('f1.c') - Program('f2.c') - - - - - Note that here we have also used the - interval= - keyword argument to have &SCons; - only print a new "spinner" string - once every five evaluated nodes. - Using an interval= count, - even with strings that use $TARGET like - our examples above, - can be a good way to lessen the - work that &SCons; expends printing &Progress; strings, - while still giving the user feedback - that indicates &SCons; is still - working on evaluating the build. - - - - - - Lastly, you can have direct control - over how to print each evaluated node - by passing a Python function - (or other Python callable) - to the &Progress; function. - Your function will be called - for each evaluated node, - allowing you to - implement more sophisticated logic - like adding a counter: - - - - - - screen = open('/dev/tty', 'w') - count = 0 - def progress_function(node) - count += 1 - screen.write('Node %4d: %s\r' % (count, node)) - - Progress(progress_function) - - - - - - Of course, if you choose, - you could completely ignore the - node argument to the function, - and just print a count, - or anything else you wish. - - - - - - (Note that there's an obvious follow-on question here: - how would you find the total number of nodes - that will be - evaluated so you can tell the user how - close the build is to finishing? - Unfortunately, in the general case, - there isn't a good way to do that, - short of having &SCons; evaluate its - dependency graph twice, - first to count the total and - the second time to actually build the targets. - This would be necessary because - you can't know in advance which - target(s) the user actually requested - to be built. - The entire build may consist of thousands of Nodes, - for example, - but maybe the user specifically requested - that only a single object file be built.) - - - -
- -
- Printing Detailed Build Status: the &GetBuildFailures; Function - - - - SCons, like most build tools, returns zero status to - the shell on success and nonzero status on failure. - Sometimes it's useful to give more information about - the build status at the end of the run, for instance - to print an informative message, send an email, or - page the poor slob who broke the build. - - - - - - SCons provides a &GetBuildFailures; method that - you can use in a python atexit function - to get a list of objects describing the actions that failed - while attempting to build targets. There can be more - than one if you're using -j. Here's a - simple example: - - - - - - import atexit - - def print_build_failures(): - from SCons.Script import GetBuildFailures - for bf in GetBuildFailures(): - print "%s failed: %s" % (bf.node, bf.errstr) - atexit.register(print_build_failures) - - - - - - The atexit.register call - registers print_build_failures - as an atexit callback, to be called - before &SCons; exits. When that function is called, - it calls &GetBuildFailures; to fetch the list of failed objects. - See the man page - for the detailed contents of the returned objects; - some of the more useful attributes are - .node, - .errstr, - .filename, and - .command. - The filename is not necessarily - the same file as the node; the - node is the target that was - being built when the error occurred, while the - filenameis the file or dir that - actually caused the error. - Note: only call &GetBuildFailures; at the end of the - build; calling it at any other time is undefined. - - - - - - Here is a more complete example showing how to - turn each element of &GetBuildFailures; into a string: - - - - - - # Make the build fail if we pass fail=1 on the command line - if ARGUMENTS.get('fail', 0): - Command('target', 'source', ['/bin/false']) - - def bf_to_str(bf): - """Convert an element of GetBuildFailures() to a string - in a useful way.""" - import SCons.Errors - if bf is None: # unknown targets product None in list - return '(unknown tgt)' - elif isinstance(bf, SCons.Errors.StopError): - return str(bf) - elif bf.node: - return str(bf.node) + ': ' + bf.errstr - elif bf.filename: - return bf.filename + ': ' + bf.errstr - return 'unknown failure: ' + bf.errstr - import atexit - - def build_status(): - """Convert the build status to a 2-tuple, (status, msg).""" - from SCons.Script import GetBuildFailures - bf = GetBuildFailures() - if bf: - # bf is normally a list of build failures; if an element is None, - # it's because of a target that scons doesn't know anything about. - status = 'failed' - failures_message = "\n".join(["Failed building %s" % bf_to_str(x) - for x in bf if x is not None]) - else: - # if bf is None, the build completed successfully. - status = 'ok' - failures_message = '' - return (status, failures_message) - - def display_build_status(): - """Display the build status. Called by atexit. - Here you could do all kinds of complicated things.""" - status, failures_message = build_status() - if status == 'failed': - print "FAILED!!!!" # could display alert, ring bell, etc. - elif status == 'ok': - print "Build succeeded." - print failures_message - - atexit.register(display_build_status) - - - - - - When this runs, you'll see the appropriate output: - - - - - scons -Q - scons -Q fail=1 - - -
diff --git a/doc/user/output.xml b/doc/user/output.xml index ff39fca..1383fc0 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -51,12 +51,14 @@
- + + Help(""" Type: 'scons program' to build the production program, 'scons debug' to build the debug version. """) - + + @@ -75,16 +77,9 @@ - - % scons -h - scons: Reading SConscript files ... - scons: done reading SConscript files. - - Type: 'scons program' to build the production program, - 'scons debug' to build the debug version. - - Use scons -H for help about command-line options. - + + scons -h + @@ -114,14 +109,16 @@ - + + env = Environment() Help("\nType: 'scons program' to build the production program.\n") if env['PLATFORM'] == 'win32': Help("\nType: 'scons windebug' to build the Windows debug version.\n") - + + @@ -129,17 +126,9 @@ - - C:\>scons -h - scons: Reading SConscript files ... - scons: done reading SConscript files. - - Type: 'scons program' to build the production program. - - Type: 'scons windebug' to build the Windows debug version. - - Use scons -H for help about command-line options. - + + scons -h + @@ -147,15 +136,9 @@ - - % scons -h - scons: Reading SConscript files ... - scons: done reading SConscript files. - - Type: 'scons program' to build the production program. - - Use scons -H for help about command-line options. - + + scons -h + @@ -208,11 +191,16 @@ - + + env = Environment(CCCOMSTR = "Compiling $TARGET", LINKCOMSTR = "Linking $TARGET") env.Program('foo.c') - + + + foo.c + + @@ -275,13 +263,18 @@ - + + env = Environment() if ARGUMENTS.get('VERBOSE') != "1': env['CCCOMSTR'] = "Compiling $TARGET" env['LINKCOMSTR'] = "Linking $TARGET" env.Program('foo.c') - + + + foo.c + + @@ -356,11 +349,19 @@ - + + Progress('Evaluating $TARGET\n') Program('f1.c') Program('f2.c') - + + + f1.c + + + f2.c + + @@ -379,21 +380,9 @@ - - % scons -Q - Evaluating SConstruct - Evaluating f1.c - Evaluating f1.o - cc -o f1.o -c f1.c - Evaluating f1 - cc -o f1 f1.o - Evaluating f2.c - Evaluating f2.o - cc -o f2.o -c f2.c - Evaluating f2 - cc -o f2 f2.o - Evaluating . - + + scons -Q + @@ -414,13 +403,13 @@ - + Progress('$TARGET\r', file=open('/dev/tty', 'w'), overwrite=True) Program('f1.c') Program('f2.c') - + @@ -471,11 +460,11 @@ - + Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5) Program('f1.c') Program('f2.c') - + @@ -510,7 +499,8 @@ - + + screen = open('/dev/tty', 'w') count = 0 def progress_function(node) @@ -518,7 +508,8 @@ screen.write('Node %4d: %s\r' % (count, node)) Progress(progress_function) - + + @@ -581,7 +572,8 @@ - + + import atexit def print_build_failures(): @@ -589,7 +581,8 @@ for bf in GetBuildFailures(): print "%s failed: %s" % (bf.node, bf.errstr) atexit.register(print_build_failures) - + + @@ -623,7 +616,8 @@ - + + # Make the build fail if we pass fail=1 on the command line if ARGUMENTS.get('fail', 0): Command('target', 'source', ['/bin/false']) @@ -670,7 +664,8 @@ print failures_message atexit.register(display_build_status) - + + @@ -678,14 +673,9 @@ - - % scons -Q - scons: `.' is up to date. - Build succeeded. - % scons -Q fail=1 - scons: *** [target] Source `source' not found, needed by target `target'. - FAILED!!!! - Failed building target: Source `source' not found, needed by target `target'. - + + scons -Q + scons -Q fail=1 + diff --git a/doc/user/parseconfig.in b/doc/user/parseconfig.in deleted file mode 100644 index 2dbefff..0000000 --- a/doc/user/parseconfig.in +++ /dev/null @@ -1,140 +0,0 @@ - - - - - Configuring the right options to build programs to work with - libraries--especially shared libraries--that are available - on POSIX systems can be very complicated. - To help this situation, - various utilies with names that end in config - return the command-line options for the GNU Compiler Collection (GCC) - that are needed to use these libraries; - for example, the command-line options - to use a library named lib - would be found by calling a utility named lib-config. - - - - - - A more recent convention is that these options - are available from the generic pkg-config program, - which has common framework, error handling, and the like, - so that all the package creator has to do is provide the set of strings - for his particular package. - - - - - - &SCons; construction environments have a &ParseConfig; method - that executes a *config utility - (either pkg-config or a - more specific utility) - and configures the appropriate construction variables - in the environment - based on the command-line options - returned by the specified command. - - - - - - env = Environment() - env['CPPPATH'] = ['/lib/compat'] - env.ParseConfig("pkg-config x11 --cflags --libs") - print env['CPPPATH'] - - - - - - &SCons; will execute the specified command string, - parse the resultant flags, - and add the flags to the appropriate environment variables. - - - - - - - % scons -Q - ['/lib/compat', '/usr/X11/include'] - scons: `.' is up to date. - - - - - In the example above, &SCons; has added the include directory to - CPPPATH. - (Depending upon what other flags are emitted by the - pkg-config command, - other variables may have been extended as well.) - - - - - - Note that the options are merged with existing options using - the &MergeFlags; method, - so that each option only occurs once in the construction variable: - - - - - - env = Environment() - env.ParseConfig("pkg-config x11 --cflags --libs") - env.ParseConfig("pkg-config x11 --cflags --libs") - print env['CPPPATH'] - - - - - - - % scons -Q - ['/usr/X11/include'] - scons: `.' is up to date. - diff --git a/doc/user/parseconfig.xml b/doc/user/parseconfig.xml index 3613d77..2dbefff 100644 --- a/doc/user/parseconfig.xml +++ b/doc/user/parseconfig.xml @@ -61,12 +61,14 @@ - + + env = Environment() env['CPPPATH'] = ['/lib/compat'] env.ParseConfig("pkg-config x11 --cflags --libs") print env['CPPPATH'] - + + @@ -111,12 +113,14 @@ - + + env = Environment() env.ParseConfig("pkg-config x11 --cflags --libs") env.ParseConfig("pkg-config x11 --cflags --libs") print env['CPPPATH'] - + + - - - - &SCons; has a bewildering array of construction variables - for different types of options when building programs. - Sometimes you may not know exactly which variable - should be used for a particular option. - - - - - - &SCons; construction environments have a &ParseFlags; method - that takes a set of typical command-line options - and distrbutes them into the appropriate construction variables. - Historically, it was created to support the &ParseConfig; method, - so it focuses on options used by the GNU Compiler Collection (GCC) - for the C and C++ toolchains. - - - - - - &ParseFlags; returns a dictionary containing the options - distributed into their respective construction variables. - Normally, this dictionary would be passed to &MergeFlags; - to merge the options into a &consenv;, - but the dictionary can be edited if desired to provide - additional functionality. - (Note that if the flags are not going to be edited, - calling &MergeFlags; with the options directly - will avoid an additional step.) - - - - - - env = Environment() - d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo") - for k,v in sorted(d.items()): - if v: - print k, v - env.MergeFlags(d) - env.Program('f1.c') - - - int main() { return 0; } - - - - - scons -Q - - - - - Note that if the options are limited to generic types - like those above, - they will be correctly translated for other platform types: - - - - - scons -Q - - - - - Since the assumption is that the flags are used for the GCC toolchain, - unrecognized flags are placed in &cv-link-CCFLAGS; - so they will be used for both C and C++ compiles: - - - - - - env = Environment() - d = env.ParseFlags("-whatever") - for k,v in sorted(d.items()): - if v: - print k, v - env.MergeFlags(d) - env.Program('f1.c') - - - int main() { return 0; } - - - - - scons -Q - - - - - &ParseFlags; will also accept a (recursive) list of strings as input; - the list is flattened before the strings are processed: - - - - - - env = Environment() - d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]]) - for k,v in sorted(d.items()): - if v: - print k, v - env.MergeFlags(d) - env.Program('f1.c') - - - int main() { return 0; } - - - - - scons -Q - - - - - If a string begins with a "!" (an exclamation mark, often called a bang), - the string is passed to the shell for execution. - The output of the command is then parsed: - - - - - - env = Environment() - d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"]) - for k,v in sorted(d.items()): - if v: - print k, v - env.MergeFlags(d) - env.Program('f1.c') - - - int main() { return 0; } - - - - - scons -Q - - - - - &ParseFlags; is regularly updated for new options; - consult the man page for details about those currently recognized. - - diff --git a/doc/user/parseflags.xml b/doc/user/parseflags.xml index d3f33c3..a0ea290 100644 --- a/doc/user/parseflags.xml +++ b/doc/user/parseflags.xml @@ -57,7 +57,8 @@ - + + env = Environment() d = env.ParseFlags("-I/opt/include -L/opt/lib -lfoo") for k,v in sorted(d.items()): @@ -65,16 +66,15 @@ print k, v env.MergeFlags(d) env.Program('f1.c') - + + + int main() { return 0; } + + - - % scons -Q - CPPPATH ['/opt/include'] - LIBPATH ['/opt/lib'] - LIBS ['foo'] - cc -o f1.o -c -I/opt/include f1.c - cc -o f1 f1.o -L/opt/lib -lfoo - + + scons -Q + @@ -84,15 +84,9 @@ - - C:\>scons -Q - CPPPATH ['/opt/include'] - LIBPATH ['/opt/lib'] - LIBS ['foo'] - cl /Fof1.obj /c f1.c /nologo /I\opt\include - link /nologo /OUT:f1.exe /LIBPATH:\opt\lib foo.lib f1.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + @@ -102,7 +96,8 @@ - + + env = Environment() d = env.ParseFlags("-whatever") for k,v in sorted(d.items()): @@ -110,14 +105,15 @@ print k, v env.MergeFlags(d) env.Program('f1.c') - + + + int main() { return 0; } + + - - % scons -Q - CCFLAGS -whatever - cc -o f1.o -c -whatever f1.c - cc -o f1 f1.o - + + scons -Q + @@ -126,7 +122,8 @@ - + + env = Environment() d = env.ParseFlags(["-I/opt/include", ["-L/opt/lib", "-lfoo"]]) for k,v in sorted(d.items()): @@ -134,16 +131,15 @@ print k, v env.MergeFlags(d) env.Program('f1.c') - + + + int main() { return 0; } + + - - % scons -Q - CPPPATH ['/opt/include'] - LIBPATH ['/opt/lib'] - LIBS ['foo'] - cc -o f1.o -c -I/opt/include f1.c - cc -o f1 f1.o -L/opt/lib -lfoo - + + scons -Q + @@ -153,7 +149,8 @@ - + + env = Environment() d = env.ParseFlags(["!echo -I/opt/include", "!echo -L/opt/lib", "-lfoo"]) for k,v in sorted(d.items()): @@ -161,16 +158,15 @@ print k, v env.MergeFlags(d) env.Program('f1.c') - - - - % scons -Q - CPPPATH ['/opt/include'] - LIBPATH ['/opt/lib'] - LIBS ['foo'] - cc -o f1.o -c -I/opt/include f1.c - cc -o f1 f1.o -L/opt/lib -lfoo - + + + int main() { return 0; } + + + + + scons -Q + diff --git a/doc/user/preface.in b/doc/user/preface.in deleted file mode 100644 index 6f3140b..0000000 --- a/doc/user/preface.in +++ /dev/null @@ -1,426 +0,0 @@ - - - - - Thank you for taking the time to read about &SCons;. - &SCons; is a next-generation - software construction tool, - or make tool--that is, a software utility - for building software (or other files) - and keeping built software up-to-date - whenever the underlying input files change. - - - - - - The most distinctive thing about &SCons; - is that its configuration files are - actually scripts, - written in the &Python; programming language. - This is in contrast to most alternative build tools, - which typically invent a new language to - configure the build. - &SCons; still has a learning curve, of course, - because you have to know what functions to call - to set up your build properly, - but the underlying syntax used should be familiar - to anyone who has ever looked at a Python script. - - - - - - Paradoxically, - using Python as the configuration file format - makes &SCons; - easier - for non-programmers to learn - than the cryptic languages of other build tools, - which are usually invented by programmers for other programmers. - This is in no small part due to the - consistency and readability that are hallmarks of Python. - It just so happens that making a real, live - scripting language the basis for the - configuration files - makes it a snap for more accomplished programmers - to do more complicated things with builds, - as necessary. - - - - - -
- &SCons; Principles - - - - There are a few overriding principles - we try to live up to in designing and implementing &SCons;: - - - - - - - Correctness - - - - - First and foremost, - by default, &SCons; guarantees a correct build - even if it means sacrificing performance a little. - We strive to guarantee the build is correct - regardless of how the software being built is structured, - how it may have been written, - or how unusual the tools are that build it. - - - - - - - Performance - - - - - Given that the build is correct, - we try to make &SCons; build software - as quickly as possible. - In particular, wherever we may have needed to slow - down the default &SCons; behavior to guarantee a correct build, - we also try to make it easy to speed up &SCons; - through optimization options that let you trade off - guaranteed correctness in all end cases for - a speedier build in the usual cases. - - - - - - - Convenience - - - - - &SCons; tries to do as much for you out of the box as reasonable, - including detecting the right tools on your system - and using them correctly to build the software. - - - - - - - - - - In a nutshell, we try hard to make &SCons; just - "do the right thing" and build software correctly, - with a minimum of hassles. - - - -
- - - - - -
- A Caveat About This Guide's Completeness - - - - One word of warning as you read through this Guide: - Like too much Open Source software out there, - the &SCons; documentation isn't always - kept up-to-date with the available features. - In other words, - there's a lot that &SCons; can do that - isn't yet covered in this User's Guide. - (Come to think of it, - that also describes a lot of proprietary software, doesn't it?) - - - - - - Although this User's Guide isn't as complete as we'd like it to be, - our development process does emphasize - making sure that the &SCons; man page is kept up-to-date - with new features. - So if you're trying to figure out how to do something - that &SCons; supports - but can't find enough (or any) information here, - it would be worth your while to look - at the man page to see if the information is covered there. - And if you do, - maybe you'd even consider contributing - a section to the User's Guide - so the next person looking for - that information won't have to - go through the same thing...? - - - -
- -
- Acknowledgements - - - - &SCons; would not exist without a lot of help - from a lot of people, - many of whom may not even be aware - that they helped or served as inspiration. - So in no particular order, - and at the risk of leaving out someone: - - - - - - First and foremost, - &SCons; owes a tremendous debt to Bob Sidebotham, - the original author of the classic Perl-based &Cons; tool - which Bob first released to the world back around 1996. - Bob's work on Cons classic provided the underlying architecture - and model of specifying a build configuration - using a real scripting language. - My real-world experience working on Cons - informed many of the design decisions in SCons, - including the improved parallel build support, - making Builder objects easily definable by users, - and separating the build engine from the wrapping interface. - - - - - - Greg Wilson was instrumental in getting - &SCons; started as a real project - when he initiated the Software Carpentry design - competition in February 2000. - Without that nudge, - marrying the advantages of the Cons classic - architecture with the readability of Python - might have just stayed no more than a nice idea. - - - - - - The entire &SCons; team have been - absolutely wonderful to work with, - and &SCons; would be nowhere near as useful a - tool without the energy, enthusiasm - and time people have contributed over the past few years. - The "core team" - of Chad Austin, Anthony Roach, - Bill Deegan, Charles Crain, Steve Leblanc, Greg Noel, - Gary Oberbrunner, Greg Spencer and Christoph Wiedemann - have been great about reviewing my (and other) changes - and catching problems before they get in the code base. - Of particular technical note: - Anthony's outstanding and innovative work on the tasking engine - has given &SCons; a vastly superior parallel build model; - Charles has been the master of the crucial Node infrastructure; - Christoph's work on the Configure infrastructure - has added crucial Autoconf-like functionality; - and Greg has provided excellent support - for Microsoft Visual Studio. - - - - - - Special thanks to David Snopek for contributing - his underlying "Autoscons" code that formed - the basis of Christoph's work with the Configure functionality. - David was extremely generous in making - this code available to &SCons;, - given that he initially released it under the GPL - and &SCons; is released under a less-restrictive MIT-style license. - - - - - - - - Thanks to Peter Miller - for his splendid change management system, &Aegis;, - which has provided the &SCons; project - with a robust development methodology from day one, - and which showed me how you could - integrate incremental regression tests into - a practical development cycle - (years before eXtreme Programming arrived on the scene). - - - - - - And last, thanks to Guido van Rossum - for his elegant scripting language, - which is the basis not only for the &SCons; implementation, - but for the interface itself. - - - -
- -
- Contact - - - - The best way to contact people involved with SCons, - including the author, - is through the SCons mailing lists. - - - - - - If you want to ask general questions about how to use &SCons; - send email to &scons-users;. - - - - - - If you want to contact the &SCons; development community directly, - send email to &scons-devel;. - - - - - - If you want to receive announcements about &SCons;, - join the low-volume &scons-announce; mailing list. - - - -
diff --git a/doc/user/python.in b/doc/user/python.in deleted file mode 100644 index e2a7cdd..0000000 --- a/doc/user/python.in +++ /dev/null @@ -1,154 +0,0 @@ - - - diff --git a/doc/user/repositories.in b/doc/user/repositories.in deleted file mode 100644 index 33de530..0000000 --- a/doc/user/repositories.in +++ /dev/null @@ -1,641 +0,0 @@ - - - - - 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. - - - -
- The &Repository; Method - - - - - - 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.) - - 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: - - - - - - env = Environment() - env.Program('hello.c') - Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') - - - int main() { printf("Hello, world!\n"); } - - - - - - 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. - - - -
- -
- Finding source files in repositories - - - - The above example - specifies that &SCons; - will first search for files under - the /usr/repository1 tree - and next under the /usr/repository2 tree. - &SCons; expects that any files it searches - for will be found in the same position - relative to the top-level directory. - In the above example, if the &hello_c; file is not - found in the local build tree, - &SCons; will search first for - a /usr/repository1/hello.c file - and then for a /usr/repository2/hello.c file - to use in its place. - - - - - - 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: - - - - - scons -Q - - - - - If, however, there is no local &hello_c; file, - but one exists in /usr/repository1, - &SCons; will recompile the &hello; program - from the source file it finds in the repository: - - - - - - env = Environment() - env.Program('hello.c') - Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') - - - int main() { printf("Hello, world!\n"); } - - - - - scons -Q - - - - - And similarly, if there is no local &hello_c; file - and no /usr/repository1/hello.c, - but one exists in /usr/repository2: - - - - - - env = Environment() - env.Program('hello.c') - Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') - - - int main() { printf("Hello, world!\n"); } - - - - - scons -Q - - - - - - -
- -
- Finding <literal>#include</literal> files in repositories - - - - We've already seen that SCons will scan the contents of - a source file for #include file names - and realize that targets built from that source file - also depend on the #include file(s). - For each directory in the &cv-link-CPPPATH; list, - &SCons; will actually search the corresponding directories - in any repository trees and establish the - correct dependencies on any - #include files that it finds - in repository directory. - - - - - - Unless the C compiler also knows about these directories - in the repository trees, though, - it will be unable to find the #include files. - If, for example, the &hello_c; file in - our previous example includes the &hello_h; - in its current directory, - and the &hello_h; only exists in the repository: - - - - - % scons -Q - cc -o hello.o -c hello.c - hello.c:1: hello.h: No such file or directory - - - - - In order to inform the C compiler about the repositories, - &SCons; will add appropriate - -I flags to the compilation commands - for each directory in the &cv-CPPPATH; list. - So if we add the current directory to the - construction environment &cv-CPPPATH; like so: - - - - - - env = Environment(CPPPATH = ['.']) - env.Program('hello.c') - Repository('__ROOT__/usr/repository1') - - - int main() { printf("Hello, world!\n"); } - - - - - - Then re-executing &SCons; yields: - - - - - scons -Q - - - - - The order of the -I options replicates, - for the C preprocessor, - the same repository-directory search path - that &SCons; uses for its own dependency analysis. - If there are multiple repositories and multiple &cv-CPPPATH; - directories, &SCons; will add the repository directories - to the beginning of each &cv-CPPPATH; directory, - rapidly multiplying the number of -I flags. - If, for example, the &cv-CPPPATH; contains three directories - (and shorter repository path names!): - - - - - - env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3']) - env.Program('hello.c') - Repository('__ROOT__/r1', '__ROOT__/r2') - - - int main() { printf("Hello, world!\n"); } - - - - - - Then we'll end up with nine -I options - on the command line, - three (for each of the &cv-CPPPATH; directories) - times three (for the local directory plus the two repositories): - - - - - scons -Q - - - - -
- Limitations on <literal>#include</literal> files in repositories - - - - &SCons; relies on the C compiler's - -I options to control the order in which - the preprocessor will search the repository directories - for #include files. - This causes a problem, however, with how the C preprocessor - handles #include lines with - the file name included in double-quotes. - - - - - - As we've seen, - &SCons; will compile the &hello_c; file from - the repository if it doesn't exist in - the local directory. - If, however, the &hello_c; file in the repository contains - a #include line with the file name in - double quotes: - - - - - #include "hello.h" - int - main(int argc, char *argv[]) - { - printf(HELLO_MESSAGE); - return (0); - } - - - - - Then the C preprocessor will always - use a &hello_h; file from the repository directory first, - even if there is a &hello_h; file in the local directory, - despite the fact that the command line specifies - -I as the first option: - - - - - - env = Environment(CPPPATH = ['.']) - env.Program('hello.c') - Repository('__ROOT__/usr/repository1') - - - int main() { printf("Hello, world!\n"); } - - - - - scons -Q - - - - - This behavior of the C preprocessor--always search - for a #include file in double-quotes - first in the same directory as the source file, - and only then search the -I--can - not, in general, be changed. - In other words, it's a limitation - that must be lived with if you want to use - code repositories in this way. - There are three ways you can possibly - work around this C preprocessor behavior: - - - - - - - - - Some modern versions of C compilers do have an option - to disable or control this behavior. - If so, add that option to &cv-link-CFLAGS; - (or &cv-link-CXXFLAGS; or both) in your construction environment(s). - Make sure the option is used for all construction - environments that use C preprocessing! - - - - - - - - Change all occurrences of #include "file.h" - to #include &lt;file.h&gt;. - Use of #include with angle brackets - does not have the same behavior--the -I - directories are searched first - for #include files--which - gives &SCons; direct control over the list of - directories the C preprocessor will search. - - - - - - - - Require that everyone working with compilation from - repositories check out and work on entire directories of files, - not individual files. - (If you use local wrapper scripts around - your source code control system's command, - you could add logic to enforce this restriction there. - - - - - - -
- -
- -
- Finding the &SConstruct; file in repositories - - - - &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 -Y option: - - - - - % scons -Q -Y /usr/repository1 -Y /usr/repository2 - - - - - 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. - - - -
- -
- Finding derived files in repositories - - - - 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. - - - - - - 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 run &SCons; in a separate build directory - and copy the resulting tree to the desired repository: - - - - - - env = Environment() - env.Program(['hello.c', 'file1.c', 'file2.c']) - Repository('/usr/repository1', '/usr/repository2') - - - int main() { printf("Hello, world!\n"); } - - - int f1() { printf("file1\n"); } - - - int f2() { printf("file2.c\n"); } - - - - - cd /usr/repository1 - scons -Q - - - - - (Note that this is safe even if the &SConstruct; file - lists /usr/repository1 as a repository, - because &SCons; will remove the current build directory - from its repository list for that invocation.) - - - - - - 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 -Y option to - tell &SCons; to fetch any other files it needs - from the repository: - - - - - - % cd $HOME/build - % edit hello.c - % scons -Q -Y /usr/repository1 - cc -c -o hello.o hello.c - cc -o hello hello.o /usr/repository1/file1.o /usr/repository1/file2.o - - - - - Notice that &SCons; realizes that it does not need to - rebuild local copies file1.o and file2.o files, - but instead uses the already-compiled files - from the repository. - - - -
- -
- Guaranteeing local copies of files - - - - 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: - - - - - % mkdir $HOME/build2 - % cd $HOME/build2 - % scons -Q -Y /usr/all/repository hello - scons: `hello' is up-to-date. - - - - - 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. - - - - - - 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: - - - - - - env = Environment() - hello = env.Program('hello.c') - Local(hello) - - - int main() { printf("Hello, world!\n"); } - - - - - - 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: - - - - - % scons -Y /usr/all/repository hello - Local copy of hello from /usr/all/repository/hello - scons: `hello' is up-to-date. - - - - - (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.) - - - -
diff --git a/doc/user/repositories.xml b/doc/user/repositories.xml index 2600381..33de530 100644 --- a/doc/user/repositories.xml +++ b/doc/user/repositories.xml @@ -73,11 +73,16 @@
- + + env = Environment() env.Program('hello.c') - Repository('/usr/repository1', '/usr/repository2') - + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + + + int main() { printf("Hello, world!\n"); } + + @@ -124,11 +129,9 @@ - - % scons -Q - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -139,13 +142,20 @@ - - - - % scons -Q - cc -o hello.o -c /usr/repository1/hello.c - cc -o hello hello.o - + + + env = Environment() + env.Program('hello.c') + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + + + int main() { printf("Hello, world!\n"); } + + + + + scons -Q + @@ -155,13 +165,20 @@ - - - - % scons -Q - cc -o hello.o -c /usr/repository2/hello.c - cc -o hello hello.o - + + + env = Environment() + env.Program('hello.c') + Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2') + + + int main() { printf("Hello, world!\n"); } + + + + + scons -Q + @@ -216,11 +233,16 @@ - + + env = Environment(CPPPATH = ['.']) env.Program('hello.c') - Repository('/usr/repository1') - + Repository('__ROOT__/usr/repository1') + + + int main() { printf("Hello, world!\n"); } + + @@ -228,11 +250,9 @@ - - % scons -Q - cc -o hello.o -c -I. -I/usr/repository1 hello.c - cc -o hello hello.o - + + scons -Q + @@ -249,11 +269,16 @@ - + + env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3']) env.Program('hello.c') - Repository('/r1', '/r2') - + Repository('__ROOT__/r1', '__ROOT__/r2') + + + int main() { printf("Hello, world!\n"); } + + @@ -264,11 +289,9 @@ - - % scons -Q - cc -o hello.o -c -Idir1 -I/r1/dir1 -I/r2/dir1 -Idir2 -I/r1/dir2 -I/r2/dir2 -Idir3 -I/r1/dir3 -I/r2/dir3 hello.c - cc -o hello hello.o - + + scons -Q + - - - - - - XXX - - - -
- Command-Line Options - - - - XXX - - - -
- -
- Getting at Command-Line Arguments - - - - XXX - - - -
- -
- Selective Builds - - - - XXX - - - -
- - - -
- Overriding Construction Variables - - - - XXX - - - -
diff --git a/doc/user/scanners.in b/doc/user/scanners.in deleted file mode 100644 index 50524e0..0000000 --- a/doc/user/scanners.in +++ /dev/null @@ -1,392 +0,0 @@ - - - - - - - &SCons; has built-in scanners that know how to look in - C, Fortran and IDL source files for information about - other files that targets built from those files depend on--for example, - in the case of files that use the C preprocessor, - the .h files that are specified - using #include lines in the source. - You can use the same mechanisms that &SCons; uses to create - its built-in scanners to write scanners of your own for file types - that &SCons; does not know how to scan "out of the box." - - - -
- A Simple Scanner Example - - - - Suppose, for example, that we want to create a simple scanner - for .foo files. - A .foo file contains some text that - will be processed, - and can include other files on lines that begin - with include - followed by a file name: - - - - - include filename.foo - - - - - Scanning a file will be handled by a Python function - that you must supply. - Here is a function that will use the Python - re module - to scan for the include lines in our example: - - - - - import re - - include_re = re.compile(r'^include\s+(\S+)$', re.M) - - def kfile_scan(node, env, path, arg): - contents = node.get_text_contents() - return env.File(include_re.findall(contents)) - - - - - It is important to note that you - have to return a list of File nodes from the scanner function, simple - strings for the file names won't do. As in the examples we are showing here, - you can use the &File; - function of your current Environment in order to create nodes on the fly from - a sequence of file names with relative paths. - - - - - - The scanner function must - accept the four specified arguments - and return a list of implicit dependencies. - Presumably, these would be dependencies found - from examining the contents of the file, - although the function can perform any - manipulation at all to generate the list of - dependencies. - - - - - - - node - - - - - An &SCons; node object representing the file being scanned. - The path name to the file can be - used by converting the node to a string - using the str() function, - or an internal &SCons; get_text_contents() - object method can be used to fetch the contents. - - - - - - - env - - - - - The construction environment in effect for this scan. - The scanner function may choose to use construction - variables from this environment to affect its behavior. - - - - - - - path - - - - - A list of directories that form the search path for included files - for this scanner. - This is how &SCons; handles the &cv-link-CPPPATH; and &cv-link-LIBPATH; - variables. - - - - - - - arg - - - - - An optional argument that you can choose to - have passed to this scanner function by - various scanner instances. - - - - - - - - - - A Scanner object is created using the &Scanner; function, - which typically takes an skeys argument - to associate the type of file suffix with this scanner. - The Scanner object must then be associated with the - &cv-link-SCANNERS; construction variable of a construction environment, - typically by using the &Append; method: - - - - - kscan = Scanner(function = kfile_scan, - skeys = ['.k']) - env.Append(SCANNERS = kscan) - - - - - When we put it all together, it looks like: - - - - - - import re - - include_re = re.compile(r'^include\s+(\S+)$', re.M) - - def kfile_scan(node, env, path): - contents = node.get_text_contents() - includes = include_re.findall(contents) - return env.File(includes) - - kscan = Scanner(function = kfile_scan, - skeys = ['.k']) - - env = Environment(ENV = {'PATH' : '__ROOT__/usr/local/bin'}) - env.Append(SCANNERS = kscan) - - env.Command('foo', 'foo.k', 'kprocess < $SOURCES > $TARGET') - - - include other_file - - - other_file - - - - - - cat - - - - - -
- -
- Adding a search path to a scanner: &FindPathDirs; - - - - Many scanners need to search for included files or dependencies - using a path variable; this is how &cv-link-CPPPATH; and - &cv-link-LIBPATH; work. The path to search is passed to your - scanner as the path argument. Path variables - may be lists of nodes, semicolon-separated strings, or even - contain SCons variables which need to be expanded. Fortunately, - &SCons; provides the &FindPathDirs; function which itself returns - a function to expand a given path (given as a SCons construction - variable name) to a list of paths at the time the scanner is - called. Deferring evaluation until that point allows, for - instance, the path to contain $TARGET references which differ for - each file scanned. - - - - - - Using &FindPathDirs; is quite easy. Continuing the above example, - using KPATH as the construction variable with the search path - (analogous to &cv-link-CPPPATH;), we just modify the &Scanner; - constructor call to include a path keyword arg: - - - - - - kscan = Scanner(function = kfile_scan, - skeys = ['.k'], - path=FindPathDirs('KPATH')) - - - - - - FindPathDirs returns a callable object that, when called, will - essentially expand the elements in env['KPATH'] and tell the - scanner to search in those dirs. It will also properly add - related repository and variant dirs to the search list. As a side - note, the returned method stores the path in an efficient way so - lookups are fast even when variable substitutions may be needed. - This is important since many files get scanned in a typical build. - - -
diff --git a/doc/user/scanners.xml b/doc/user/scanners.xml index f150d33..50524e0 100644 --- a/doc/user/scanners.xml +++ b/doc/user/scanners.xml @@ -285,7 +285,8 @@ over the file scanning rather than being called for each input line: - + + import re include_re = re.compile(r'^include\s+(\S+)$', re.M) @@ -298,11 +299,24 @@ over the file scanning rather than being called for each input line: kscan = Scanner(function = kfile_scan, skeys = ['.k']) - env = Environment(ENV = {'PATH' : '/usr/local/bin'}) + env = Environment(ENV = {'PATH' : '__ROOT__/usr/local/bin'}) env.Append(SCANNERS = kscan) env.Command('foo', 'foo.k', 'kprocess < $SOURCES > $TARGET') - + + + include other_file + + + other_file + + + + + + cat + + - - - - &SCons; has integrated support for multi-platform build configuration - similar to that offered by GNU &Autoconf;, - such as - figuring out what libraries or header files - are available on the local system. - This section describes how to use - this &SCons; feature. - - - - - - This chapter is still under development, - so not everything is explained as well as it should be. - See the &SCons; man page for additional information. - - - -
- &Configure_Contexts; - - - - The basic framework for multi-platform build configuration - in &SCons; is to attach a &configure_context; to a - construction environment by calling the &Configure; function, - perform a number of checks for - libraries, functions, header files, etc., - and to then call the configure context's &Finish; method - to finish off the configuration: - - - - - env = Environment() - conf = Configure(env) - # Checks for libraries, header files, etc. go here! - env = conf.Finish() - - - - - &SCons; provides a number of basic checks, - as well as a mechanism for adding your own custom checks. - - - - - - Note that &SCons; uses its own dependency - mechanism to determine when a check - needs to be run--that is, - &SCons; does not run the checks - every time it is invoked, - but caches the values returned by previous checks - and uses the cached values unless something has changed. - This saves a tremendous amount - of developer time while working on - cross-platform build issues. - - - - - - The next sections describe - the basic checks that &SCons; supports, - as well as how to add your own custom checks. - - - -
- -
- Checking for the Existence of Header Files - - - - Testing the existence of a header file - requires knowing what language the header file is. - A configure context has a &CheckCHeader; method - that checks for the existence of a C header file: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckCHeader('math.h'): - print 'Math.h must be installed!' - Exit(1) - if conf.CheckCHeader('foo.h'): - conf.env.Append('-DHAS_FOO_H') - env = conf.Finish() - - - - - Note that you can choose to terminate - the build if a given header file doesn't exist, - or you can modify the construction environment - based on the existence of a header file. - - - - - - If you need to check for the existence - a C++ header file, - use the &CheckCXXHeader; method: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckCXXHeader('vector.h'): - print 'vector.h must be installed!' - Exit(1) - env = conf.Finish() - - -
- -
- Checking for the Availability of a Function - - - - Check for the availability of a specific function - using the &CheckFunc; method: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckFunc('strcpy'): - print 'Did not find strcpy(), using local version' - conf.env.Append(CPPDEFINES = '-Dstrcpy=my_local_strcpy') - env = conf.Finish() - - -
- -
- Checking for the Availability of a Library - - - - Check for the availability of a library - using the &CheckLib; method. - You only specify the basename of the library, - you don't need to add a lib - prefix or a .a or .lib suffix: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckLib('m'): - print 'Did not find libm.a or m.lib, exiting!' - Exit(1) - env = conf.Finish() - - - - - Because the ability to use a library successfully - often depends on having access to a header file - that describes the library's interface, - you can check for a library - and a header file - at the same time by using the - &CheckLibWithHeader; method: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckLibWithHeader('m', 'math.h', 'c'): - print 'Did not find libm.a or m.lib, exiting!' - Exit(1) - env = conf.Finish() - - - - - This is essentially shorthand for - separate calls to the &CheckHeader; and &CheckLib; - functions. - - - -
- -
- Checking for the Availability of a &typedef; - - - - Check for the availability of a &typedef; - by using the &CheckType; method: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckType('off_t'): - print 'Did not find off_t typedef, assuming int' - conf.env.Append(CCFLAGS = '-Doff_t=int') - env = conf.Finish() - - - - - You can also add a string that will be - placed at the beginning of the test file - that will be used to check for the &typedef;. - This provide a way to specify - files that must be included to find the &typedef;: - - - - - env = Environment() - conf = Configure(env) - if not conf.CheckType('off_t', '#include &lt;sys/types.h&gt;\n'): - print 'Did not find off_t typedef, assuming int' - conf.env.Append(CCFLAGS = '-Doff_t=int') - env = conf.Finish() - - -
- -
- Adding Your Own Custom Checks - - - - A custom check is a Python function - that checks for a certain condition to exist - on the running system, - usually using methods that &SCons; - supplies to take care of the details - of checking whether a compilation succeeds, - a link succeeds, - a program is runnable, - etc. - A simple custom check for the existence of - a specific library might look as follows: - - - - - mylib_test_source_file = """ - #include &lt;mylib.h&gt; - int main(int argc, char **argv) - { - MyLibrary mylib(argc, argv); - return 0; - } - """ - - def CheckMyLibrary(context): - context.Message('Checking for MyLibrary...') - result = context.TryLink(mylib_test_source_file, '.c') - context.Result(result) - return result - - - - - The &Message; and &Result; methods - should typically begin and end a custom check to - let the user know what's going on: - the &Message; call prints the - specified message (with no trailing newline) - and the &Result; call prints - yes if the check succeeds and - no if it doesn't. - The &TryLink; method - actually tests for whether the - specified program text - will successfully link. - - - - - - (Note that a custom check can modify - its check based on any arguments you - choose to pass it, - or by using or modifying the configure context environment - in the context.env attribute.) - - - - - - This custom check function is - then attached to the &configure_context; - by passing a dictionary - to the &Configure; call - that maps a name of the check - to the underlying function: - - - - - env = Environment() - conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) - - - - - You'll typically want to make - the check and the function name the same, - as we've done here, - to avoid potential confusion. - - - - - - We can then put these pieces together - and actually call the CheckMyLibrary check - as follows: - - - - - mylib_test_source_file = """ - #include &lt;mylib.h&gt; - int main(int argc, char **argv) - { - MyLibrary mylib(argc, argv); - return 0; - } - """ - - def CheckMyLibrary(context): - context.Message('Checking for MyLibrary... ') - result = context.TryLink(mylib_test_source_file, '.c') - context.Result(result) - return result - - env = Environment() - conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) - if not conf.CheckMyLibrary(): - print 'MyLibrary is not installed!' - Exit(1) - env = conf.Finish() - - # We would then add actual calls like Program() to build - # something using the "env" construction environment. - - - - - If MyLibrary is not installed on the system, - the output will look like: - - - - - % scons - scons: Reading SConscript file ... - Checking for MyLibrary... failed - MyLibrary is not installed! - - - - - If MyLibrary is installed, - the output will look like: - - - - - % scons - scons: Reading SConscript file ... - Checking for MyLibrary... failed - scons: done reading SConscript - scons: Building targets ... - . - . - . - - -
- -
- Not Configuring When Cleaning Targets - - - - Using multi-platform configuration - as described in the previous sections - will run the configuration commands - even when invoking - scons -c - to clean targets: - - - - - % scons -Q -c - Checking for MyLibrary... yes - Removed foo.o - Removed foo - - - - - Although running the platform checks - when removing targets doesn't hurt anything, - it's usually unnecessary. - You can avoid this by using the - &GetOption; method to - check whether the (clean) - option has been invoked on the command line: - - - - - env = Environment() - if not env.GetOption('clean'): - conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) - if not conf.CheckMyLibrary(): - print 'MyLibrary is not installed!' - Exit(1) - env = conf.Finish() - - - - % scons -Q -c - Removed foo.o - Removed foo - - -
- - diff --git a/doc/user/sconf.xml b/doc/user/sconf.xml index f5db744..584a82e 100644 --- a/doc/user/sconf.xml +++ b/doc/user/sconf.xml @@ -58,12 +58,12 @@ - + env = Environment() conf = Configure(env) # Checks for libraries, header files, etc. go here! env = conf.Finish() - + @@ -109,7 +109,7 @@ - + env = Environment() conf = Configure(env) if not conf.CheckCHeader('math.h'): @@ -118,7 +118,7 @@ if conf.CheckCHeader('foo.h'): conf.env.Append('-DHAS_FOO_H') env = conf.Finish() - + @@ -137,14 +137,14 @@ - + env = Environment() conf = Configure(env) if not conf.CheckCXXHeader('vector.h'): print 'vector.h must be installed!' Exit(1) env = conf.Finish() - + @@ -158,14 +158,14 @@ - + env = Environment() conf = Configure(env) if not conf.CheckFunc('strcpy'): print 'Did not find strcpy(), using local version' conf.env.Append(CPPDEFINES = '-Dstrcpy=my_local_strcpy') env = conf.Finish() - + @@ -182,14 +182,14 @@ - + env = Environment() conf = Configure(env) if not conf.CheckLib('m'): print 'Did not find libm.a or m.lib, exiting!' Exit(1) env = conf.Finish() - + @@ -203,14 +203,14 @@ - + env = Environment() conf = Configure(env) if not conf.CheckLibWithHeader('m', 'math.h', 'c'): print 'Did not find libm.a or m.lib, exiting!' Exit(1) env = conf.Finish() - + @@ -232,14 +232,14 @@ - + env = Environment() conf = Configure(env) if not conf.CheckType('off_t'): print 'Did not find off_t typedef, assuming int' conf.env.Append(CCFLAGS = '-Doff_t=int') env = conf.Finish() - + @@ -251,14 +251,14 @@ - + env = Environment() conf = Configure(env) - if not conf.CheckType('off_t', '#include <sys/types.h>\n'): + if not conf.CheckType('off_t', '#include &lt;sys/types.h&gt;\n'): print 'Did not find off_t typedef, assuming int' conf.env.Append(CCFLAGS = '-Doff_t=int') env = conf.Finish() - + @@ -281,9 +281,9 @@ - + mylib_test_source_file = """ - #include <mylib.h> + #include &lt;mylib.h&gt; int main(int argc, char **argv) { MyLibrary mylib(argc, argv); @@ -296,7 +296,7 @@ result = context.TryLink(mylib_test_source_file, '.c') context.Result(result) return result - + @@ -336,10 +336,10 @@ - + env = Environment() conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) - + @@ -358,9 +358,9 @@ - + mylib_test_source_file = """ - #include <mylib.h> + #include &lt;mylib.h&gt; int main(int argc, char **argv) { MyLibrary mylib(argc, argv); @@ -383,7 +383,7 @@ # We would then add actual calls like Program() to build # something using the "env" construction environment. - + @@ -452,7 +452,7 @@ - + env = Environment() if not env.GetOption('clean'): conf = Configure(env, custom_tests = {'CheckMyLibrary' : CheckMyLibrary}) @@ -460,7 +460,7 @@ print 'MyLibrary is not installed!' Exit(1) env = conf.Finish() - + % scons -Q -c diff --git a/doc/user/separate.in b/doc/user/separate.in deleted file mode 100644 index 75605fe..0000000 --- a/doc/user/separate.in +++ /dev/null @@ -1,540 +0,0 @@ - - - - - - - It's often useful to keep any built files completely - separate from the source files. - In &SCons;, this is usually done by creating one or more separate - variant directory trees - that are used to hold the built objects files, libraries, - and executable programs, etc. - for a specific flavor, or variant, of build. - &SCons; provides two ways to do this, - one through the &SConscript; function that we've already seen, - and the second through a more flexible &VariantDir; function. - - - - - - One historical note: the &VariantDir; function - used to be called &BuildDir;. - That name is still supported - but has been deprecated - because the &SCons; functionality - differs from the model of a "build directory" - implemented by other build systems like the GNU Autotools. - - - -
- Specifying a Variant Directory Tree as Part of an &SConscript; Call - - - - The most straightforward way to establish a variant directory tree - uses the fact that the usual way to - set up a build hierarchy is to have an - &SConscript; file in the source subdirectory. - If you then pass a &variant_dir; argument to the - &SConscript; function call: - - - - - - SConscript('src/SConscript', variant_dir='build') - - - env = Environment() - env.Program('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - &SCons; will then build all of the files in - the &build; subdirectory: - - - - - ls src - scons -Q - ls build - - - - - But wait a minute--what's going on here? - &SCons; created the object file - build/hello.o - in the &build; subdirectory, - as expected. - But even though our &hello_c; file lives in the &src; subdirectory, - &SCons; has actually compiled a - build/hello.c file - to create the object file. - - - - - - What's happened is that &SCons; has duplicated - the &hello_c; file from the &src; subdirectory - to the &build; subdirectory, - and built the program from there. - The next section explains why &SCons; does this. - - - -
- -
- Why &SCons; Duplicates Source Files in a Variant Directory Tree - - - - &SCons; duplicates source files in variant directory trees - because it's the most straightforward way to guarantee a correct build - regardless of include-file directory paths, - relative references between files, - or tool support for putting files in different locations, - and the &SCons; philosophy is to, by default, - guarantee a correct build in all cases. - - - - - - The most direct reason to duplicate source files - in variant directories - is simply that some tools (mostly older versions) - are written to only build their output files - in the same directory as the source files. - In this case, the choices are either - to build the output file in the source directory - and move it to the variant directory, - or to duplicate the source files in the variant directory. - - - - - - Additionally, - relative references between files - can cause problems if we don't - just duplicate the hierarchy of source files - in the variant directory. - You can see this at work in - use of the C preprocessor #include - mechanism with double quotes, not angle brackets: - - - - - #include "file.h" - - - - - The de facto standard behavior - for most C compilers in this case - is to first look in the same directory - as the source file that contains the #include line, - then to look in the directories in the preprocessor search path. - Add to this that the &SCons; implementation of - support for code repositories - (described below) - means not all of the files - will be found in the same directory hierarchy, - and the simplest way to make sure - that the right include file is found - is to duplicate the source files into the variant directory, - which provides a correct build - regardless of the original location(s) of the source files. - - - - - - Although source-file duplication guarantees a correct build - even in these end-cases, - it can usually be safely disabled. - The next section describes - how you can disable the duplication of source files - in the variant directory. - - - -
- -
- Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree - - - - In most cases and with most tool sets, - &SCons; can place its target files in a build subdirectory - without - duplicating the source files - and everything will work just fine. - You can disable the default &SCons; behavior - by specifying duplicate=0 - when you call the &SConscript; function: - - - - - SConscript('src/SConscript', variant_dir='build', duplicate=0) - - - - - When this flag is specified, - &SCons; uses the variant directory - like most people expect--that is, - the output files are placed in the variant directory - while the source files stay in the source directory: - - - - - % ls src - SConscript - hello.c - % scons -Q - cc -c src/hello.c -o build/hello.o - cc -o build/hello build/hello.o - % ls build - hello - hello.o - - -
- -
- The &VariantDir; Function - - - - Use the &VariantDir; function to establish that target - files should be built in a separate directory - from the source files: - - - - - - VariantDir('build', 'src') - env = Environment() - env.Program('build/hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - Note that when you're not using - an &SConscript; file in the &src; subdirectory, - you must actually specify that - the program must be built from - the build/hello.c - file that &SCons; will duplicate in the - &build; subdirectory. - - - - - - When using the &VariantDir; function directly, - &SCons; still duplicates the source files - in the variant directory by default: - - - - - ls src - scons -Q - ls build - - - - - You can specify the same duplicate=0 argument - that you can specify for an &SConscript; call: - - - - - - VariantDir('build', 'src', duplicate=0) - env = Environment() - env.Program('build/hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - In which case &SCons; - will disable duplication of the source files: - - - - - ls src - scons -Q - ls build - - -
- -
- Using &VariantDir; With an &SConscript; File - - - - Even when using the &VariantDir; function, - it's much more natural to use it with - a subsidiary &SConscript; file. - For example, if the - src/SConscript - looks like this: - - - - - - VariantDir('build', 'src') - SConscript('build/SConscript') - - - env = Environment() - env.Program('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - Then our &SConstruct; file could look like: - - - - - - - - - Yielding the following output: - - - - - ls src - scons -Q - ls build - - - - - Notice that this is completely equivalent - to the use of &SConscript; that we - learned about in the previous section. - - - -
- -
- Using &Glob; with &VariantDir; - - - - The &Glob; file name pattern matching function - works just as usual when using &VariantDir;. - For example, if the - src/SConscript - looks like this: - - - - - - VariantDir('build', 'src') - SConscript('build/SConscript') - - - env = Environment() - env.Program('hello', Glob('*.c')) - - - #include "f2.h" - int main() { printf(f2()); } - - - const char * f2() { return("Hello, world!\n"); } - - - const char * f2(); - - - - - - Then with the same &SConstruct; file as in the previous section, - and source files f1.c - and f2.c in src, - we would see the following output: - - - - - ls src - scons -Q - ls build - - - - - The &Glob; function returns Nodes in the - build/ tree, as you'd expect. - - - -
- - diff --git a/doc/user/separate.xml b/doc/user/separate.xml index 6b449fe..75605fe 100644 --- a/doc/user/separate.xml +++ b/doc/user/separate.xml @@ -151,9 +151,18 @@ program using the F path name. - + + SConscript('src/SConscript', variant_dir='build') - + + + env = Environment() + env.Program('hello.c') + + + int main() { printf("Hello, world!\n"); } + + @@ -162,15 +171,11 @@ program using the F path name. - - % ls src - SConscript hello.c - % scons -Q - cc -o build/hello.o -c build/hello.c - cc -o build/hello build/hello.o - % ls build - SConscript hello hello.c hello.o - + + ls src + scons -Q + ls build + @@ -240,9 +245,9 @@ program using the F path name. - + #include "file.h" - + @@ -293,9 +298,9 @@ program using the F path name. - + SConscript('src/SConscript', variant_dir='build', duplicate=0) - + @@ -332,11 +337,16 @@ program using the F path name. - + + VariantDir('build', 'src') env = Environment() env.Program('build/hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -358,15 +368,11 @@ program using the F path name. - - % ls src - hello.c - % scons -Q - cc -o build/hello.o -c build/hello.c - cc -o build/hello build/hello.o - % ls build - hello hello.c hello.o - + + ls src + scons -Q + ls build + @@ -375,11 +381,16 @@ program using the F path name. - + + VariantDir('build', 'src', duplicate=0) env = Environment() env.Program('build/hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -388,15 +399,11 @@ program using the F path name. - - % ls src - hello.c - % scons -Q - cc -o build/hello.o -c src/hello.c - cc -o build/hello build/hello.o - % ls build - hello hello.o - + + ls src + scons -Q + ls build + @@ -414,10 +421,19 @@ program using the F path name. - + + + VariantDir('build', 'src') + SConscript('build/SConscript') + + env = Environment() env.Program('hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -425,11 +441,8 @@ program using the F path name. - - - VariantDir('build', 'src') - SConscript('build/SConscript') - + + @@ -437,15 +450,11 @@ program using the F path name. - - % ls src - SConscript hello.c - % scons -Q - cc -o build/hello.o -c build/hello.c - cc -o build/hello build/hello.o - % ls build - SConscript hello hello.c hello.o - + + ls src + scons -Q + ls build + @@ -470,10 +479,26 @@ program using the F path name. - + + + VariantDir('build', 'src') + SConscript('build/SConscript') + + env = Environment() env.Program('hello', Glob('*.c')) - + + + #include "f2.h" + int main() { printf(f2()); } + + + const char * f2() { return("Hello, world!\n"); } + + + const char * f2(); + + @@ -484,16 +509,11 @@ program using the F path name. - - % ls src - SConscript f1.c f2.c f2.h - % scons -Q - cc -o build/f1.o -c build/f1.c - cc -o build/f2.o -c build/f2.c - cc -o build/hello build/f1.o build/f2.o - % ls build - SConscript f1.c f1.o f2.c f2.h f2.o hello - + + ls src + scons -Q + ls build + diff --git a/doc/user/sideeffect.in b/doc/user/sideeffect.in deleted file mode 100644 index cbeefae..0000000 --- a/doc/user/sideeffect.in +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - Sometimes a program the you need to call - to build a target file - will also update another file, - such as a log file describing what the program - does while building the target. - For example, we the folowing configuration - would have &SCons; invoke a hypothetical - script named build - (in the local directory) - with command-line arguments that write - log information to a common - logfile.txt file: - - - - - env = Environment() - env.Command('file1.out', 'file.in', - './build --log logfile.txt $SOURCE $TARGET') - env.Command('file2.out', 'file.in', - './build --log logfile.txt $SOURCE $TARGET') - - - - - This can cause problems when running - the build in parallel if - &SCons; decides to update both targets - by running both program invocations at the same time. - The multiple program invocations - may interfere with each other - writing to the common log file, - leading at best to intermixed output in the log file, - and at worst to an actual failed build - (on a system like Windows, for example, - where only one process at a time can open the log file for writing). - - - - - - We can make sure that &SCons; does not - run these build - commands at the same time - by using the &SideEffect; function - to specify that updating - the logfile.txt file - is a side effect of building the specified - file1 - and - file2 - target files: - - - - - - env = Environment() - f1 = env.Command('file1.out', 'file1.in', - './build --log logfile.txt $SOURCE $TARGET') - f2 = env.Command('file2.out', 'file2.in', - './build --log logfile.txt $SOURCE $TARGET') - env.SideEffect('logfile.txt', f1 + f2) - - file1.in - file2.in - - cat - - - - - - - - - - This makes sure the the two - ./build steps are run sequentially, - even withthe --jobs=2 in the command line: - - - - - scons -Q --jobs=2 - - - - - The &SideEffect; function can be called multiple - times for the same side-effect file. - Additionally, the name used as a &SideEffect; does not - even need to actually exist as a file on disk. - &SCons; will still make sure - that the relevant targets - will be executed sequentially, not in parallel: - - - - - - env = Environment() - f1 = env.Command('file1.out', [], 'echo >$TARGET data1') - env.SideEffect('not_really_updated', f1) - f2 = env.Command('file2.out', [], 'echo >$TARGET data2') - env.SideEffect('not_really_updated', f2) - - - - - scons -Q --jobs=2 - - - - - Note that it might be tempting to - use &SideEffect; for additional target files - that a command produces. - For example, versions the Microsoft Visual C/C++ compiler - produce a foo.ilk - alongside compiling foo.obj file. - Specifying foo.ilk as a - side-effect of foo.obj - is not a recommended use of &SideEffect;, - because &SCons; handle side-effect files - slightly differently in its analysis of the dependency graph. - When a command produces multiple output files, - they should be specified as multiple targets of - the call to the relevant builder function, - and the &SideEffect; function itself should really only be used - when it's important to ensure that commands are not executed in parallel, - such as when a "peripheral" file (such as a log file) - may actually updated by more than one command invocation. - - diff --git a/doc/user/sideeffect.xml b/doc/user/sideeffect.xml index 2cb4254..cbeefae 100644 --- a/doc/user/sideeffect.xml +++ b/doc/user/sideeffect.xml @@ -134,14 +134,21 @@ - + + env = Environment() f1 = env.Command('file1.out', 'file1.in', './build --log logfile.txt $SOURCE $TARGET') f2 = env.Command('file2.out', 'file2.in', './build --log logfile.txt $SOURCE $TARGET') env.SideEffect('logfile.txt', f1 + f2) - + + file1.in + file2.in + + cat + + @@ -155,11 +162,9 @@ - - % scons -Q --jobs=2 - ./build --log logfile.txt file1.in file1.out - ./build --log logfile.txt file2.in file2.out - + + scons -Q --jobs=2 + @@ -173,19 +178,19 @@ - + + env = Environment() - f1 = env.Command('file1.out', [], 'echo >$TARGET data1') + f1 = env.Command('file1.out', [], 'echo >$TARGET data1') env.SideEffect('not_really_updated', f1) - f2 = env.Command('file2.out', [], 'echo >$TARGET data2') + f2 = env.Command('file2.out', [], 'echo >$TARGET data2') env.SideEffect('not_really_updated', f2) - + + - - % scons -Q --jobs=2 - echo > file1.out data1 - echo > file2.out data2 - + + scons -Q --jobs=2 + diff --git a/doc/user/simple.in b/doc/user/simple.in deleted file mode 100644 index 8a25be5..0000000 --- a/doc/user/simple.in +++ /dev/null @@ -1,517 +0,0 @@ - - - - - In this chapter, - you will see several examples of - very simple build configurations using &SCons;, - which will demonstrate how easy - it is to use &SCons; to - build programs from several different programming languages - on different types of systems. - - - -
- Building Simple C / C++ Programs - - - - Here's the famous "Hello, World!" program in C: - - - - - int - main() - { - printf("Hello, world!\n"); - } - - - - - And here's how to build it using &SCons;. - Enter the following into a file named &SConstruct;: - - - - - - Program('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - This minimal configuration file gives - &SCons; two pieces of information: - what you want to build - (an executable program), - and the input file from - which you want it built - (the hello.c file). - &b-link-Program; is a builder_method, - a Python call that tells &SCons; that you want to build an - executable program. - - - - - - That's it. Now run the &scons; command to build the program. - On a POSIX-compliant system like Linux or UNIX, - you'll see something like: - - - - - scons - - - - - On a Windows system with the Microsoft Visual C++ compiler, - you'll see something like: - - - - - scons - - - - - First, notice that you only need - to specify the name of the source file, - and that &SCons; correctly deduces the names of - the object and executable files to be built - from the base of the source file name. - - - - - - Second, notice that the same input &SConstruct; file, - without any changes, - generates the correct output file names on both systems: - hello.o and hello - on POSIX systems, - hello.obj and hello.exe - on Windows systems. - This is a simple example of how &SCons; - makes it extremely easy to - write portable software builds. - - - - - - (Note that we won't provide duplicate side-by-side - POSIX and Windows output for all of the examples in this guide; - just keep in mind that, unless otherwise specified, - any of the examples should work equally well on both types of systems.) - - - -
- -
- Building Object Files - - - - The &b-link-Program; builder method is only one of - many builder methods that &SCons; provides - to build different types of files. - Another is the &b-link-Object; builder method, - which tells &SCons; to build an object file - from the specified source file: - - - - - - Object('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - - Now when you run the &scons; command to build the program, - it will build just the &hello_o; object file on a POSIX system: - - - - - scons - - - - - And just the &hello_obj; object file - on a Windows system (with the Microsoft Visual C++ compiler): - - - - - scons - - -
- -
- Simple Java Builds - - - - &SCons; also makes building with Java extremely easy. - Unlike the &b-link-Program; and &b-link-Object; builder methods, - however, the &b-link-Java; builder method - requires that you specify - the name of a destination directory in which - you want the class files placed, - followed by the source directory - in which the .java files live: - - - - - - Java('classes', 'src') - - - public class Example1 - { - public static void main(String[] args) - { - System.out.println("Hello Java world!\n"); - } - } - - - - - - If the src directory - contains a single hello.java file, - then the output from running the &scons; command - would look something like this - (on a POSIX system): - - - - - scons - - - - - We'll cover Java builds in more detail, - including building Java archive (.jar) - and other types of file, - in . - - - -
- -
- Cleaning Up After a Build - - - - When using &SCons;, it is unnecessary to add special - commands or target names to clean up after a build. - Instead, you simply use the - -c or --clean - option when you invoke &SCons;, - and &SCons; removes the appropriate built files. - So if we build our example above - and then invoke scons -c - afterwards, the output on POSIX looks like: - - - - - - Program('hello.c') - - - int main() { printf("Hello, world!\n"); } - - - - - scons - scons -c - - - - - And the output on Windows looks like: - - - - - scons - scons -c - - - - - Notice that &SCons; changes its output to tell you that it - is Cleaning targets ... and - done cleaning targets. - - - -
- -
- The &SConstruct; File - - - - If you're used to build systems like &Make; - you've already figured out that the &SConstruct; file - is the &SCons; equivalent of a &Makefile;. - That is, the &SConstruct; file is the input file - that &SCons; reads to control the build. - - - -
- &SConstruct; Files Are Python Scripts - - - - There is, however, an important difference between - 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. - This User's Guide will introduce you step-by-step - to the relatively small amount of Python you'll - need to know to be able to use &SCons; effectively. - And Python is very easy to learn. - - - - - - One aspect of using Python as the - scripting language is that you can put comments - in your &SConstruct; file using Python's commenting convention; - that is, everything between a '#' and the end of the line - will be ignored: - - - - - # Arrange to build the "hello" program. - Program('hello.c') # "hello.c" is the source file. - - - - - You'll see throughout the remainder of this Guide - that being able to use the power of a - real scripting language - can greatly simplify the solutions - to complex requirements of real-world builds. - - - -
- -
- &SCons; Functions Are Order-Independent - - - - One important way in which the &SConstruct; - file is not exactly like a normal Python script, - and is more like a &Makefile;, - is that the order in which - the &SCons; functions are called in - the &SConstruct; file - does not - affect the order in which &SCons; - actually builds the programs and object files - you want it to build. - In programming parlance, - the &SConstruct; file is - declarative, - meaning you tell &SCons; what you want done - and let it figure out the order in which to do it, - rather than strictly imperative, - where you specify explicitly the order in - which to do things. - - - In other words, when you call the &b-link-Program; builder - (or any other builder method), - you're not telling &SCons; to build - the program at the instant the builder method is called. - Instead, you're telling &SCons; to build the program - that you want, for example, - a program built from a file named &hello_c;, - and it's up to &SCons; to build that program - (and any other files) whenever it's necessary. - (We'll learn more about how - &SCons; decides when building or rebuilding a file - is necessary in , below.) - - - - - - &SCons; reflects this distinction between - calling a builder method like &b-Program; - and actually building the program - by printing the status messages that indicate - when it's "just reading" the &SConstruct; file, - and when it's actually building the target files. - This is to make it clear when &SCons; is - executing the Python statements that make up the &SConstruct; file, - and when &SCons; is actually executing the - commands or other actions to - build the necessary files. - - - - - - Let's clarify this with an example. - Python has a print statement that - prints a string of characters to the screen. - If we put print statements around - our calls to the &b-Program; builder method: - - - - - - print "Calling Program('hello.c')" - Program('hello.c') - print "Calling Program('goodbye.c')" - Program('goodbye.c') - print "Finished calling Program()" - - - int main() { printf("Hello, world!\n"); } - - - int main() { printf("Goodbye, world!\n"); } - - - - - - Then when we execute &SCons;, - we see the output from the print - statements in between the messages about - reading the &SConscript; files, - indicating that that is when the - Python statements are being executed: - - - - - scons - - - - - Notice also that &SCons; built the &goodbye; program first, - even though the "reading &SConscript;" output - shows that we called Program('hello.c') - first in the &SConstruct; file. - - - -
- -
- -
- Making the &SCons; Output Less Verbose - - - - You've already seen how &SCons; prints - some messages about what it's doing, - surrounding the actual commands used to build the software: - - - - - scons - - - - - These messages emphasize the - order in which &SCons; does its work: - all of the configuration files - (generically referred to as &SConscript; files) - are read and executed first, - and only then are the target files built. - Among other benefits, these messages help to distinguish between - errors that occur while the configuration files are read, - and errors that occur while targets are being built. - - - - - - One drawback, of course, is that these messages clutter the output. - Fortunately, they're easily disabled by using - the &Q; option when invoking &SCons;: - - - - - scons -Q - - - - - Because we want this User's Guide to focus - on what &SCons; is actually doing, - we're going to use the &Q; option - to remove these messages from the - output of all the remaining examples in this Guide. - - - -
diff --git a/doc/user/simple.xml b/doc/user/simple.xml index 2a687a0..8a25be5 100644 --- a/doc/user/simple.xml +++ b/doc/user/simple.xml @@ -59,9 +59,14 @@
- + + Program('hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -86,15 +91,9 @@ - - % scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cc -o hello.o -c hello.c - cc -o hello hello.o - scons: done building targets. - + + scons + @@ -103,16 +102,9 @@ - - C:\>scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - scons: done building targets. - + + scons + @@ -164,9 +156,14 @@ - + + Object('hello.c') - + + + int main() { printf("Hello, world!\n"); } + + @@ -175,14 +172,9 @@ - - % scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cc -o hello.o -c hello.c - scons: done building targets. - + + scons + @@ -191,14 +183,9 @@ - - C:\>scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cl /Fohello.obj /c hello.c /nologo - scons: done building targets. - + + scons + @@ -218,9 +205,20 @@ - + + Java('classes', 'src') - + + + public class Example1 + { + public static void main(String[] args) + { + System.out.println("Hello Java world!\n"); + } + } + + @@ -232,14 +230,9 @@ - - % scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - javac -d classes -sourcepath src src/hello.java - scons: done building targets. - + + scons + @@ -269,24 +262,19 @@ - - - - % scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cc -o hello.o -c hello.c - cc -o hello hello.o - scons: done building targets. - % scons -c - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Cleaning targets ... - Removed hello.o - Removed hello - scons: done cleaning targets. - + + + Program('hello.c') + + + int main() { printf("Hello, world!\n"); } + + + + + scons + scons -c + @@ -294,23 +282,10 @@ - - C:\>scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - scons: done building targets. - C:\>scons -c - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Cleaning targets ... - Removed hello.obj - Removed hello.exe - scons: done cleaning targets. - + + scons + scons -c + @@ -444,13 +419,21 @@ - + + print "Calling Program('hello.c')" Program('hello.c') print "Calling Program('goodbye.c')" Program('goodbye.c') print "Finished calling Program()" - + + + int main() { printf("Hello, world!\n"); } + + + int main() { printf("Goodbye, world!\n"); } + + @@ -463,20 +446,9 @@ - - % scons - scons: Reading SConscript files ... - Calling Program('hello.c') - Calling Program('goodbye.c') - Finished calling Program() - scons: done reading SConscript files. - scons: Building targets ... - cc -o goodbye.o -c goodbye.c - cc -o goodbye goodbye.o - cc -o hello.o -c hello.c - cc -o hello hello.o - scons: done building targets. - + + scons + @@ -502,16 +474,9 @@ - - C:\>scons - scons: Reading SConscript files ... - scons: done reading SConscript files. - scons: Building targets ... - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - scons: done building targets. - + + scons + @@ -535,12 +500,9 @@ - - C:\>scons -Q - cl /Fohello.obj /c hello.c /nologo - link /nologo /OUT:hello.exe hello.obj - embedManifestExeCheck(target, source, env) - + + scons -Q + diff --git a/doc/user/sourcecode.in b/doc/user/sourcecode.in deleted file mode 100644 index 04c76d0..0000000 --- a/doc/user/sourcecode.in +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - XXX - - - -
- Fetching Source Code From BitKeeper - - - - XXX - - - - - - env = Environment() - env.SourceCode('.', env.BitKeeper()) - env.Program('hello.c') - - - s.hello.c - - - - - scons -Q - - -
- -
- Fetching Source Code From CVS - - - - XXX - - - - - - env = Environment() - env.SourceCode('.', env.CVS('/usr/local/CVS')) - env.Program('hello.c') - - - - - scons -Q - - -
- -
- Fetching Source Code From RCS - - - - XXX - - - - - - env = Environment() - env.SourceCode('.', env.RCS()) - env.Program('hello.c') - - - hello.c,v - - - - - scons -Q - - -
- -
- Fetching Source Code From SCCS - - - - XXX - - - - - - env = Environment() - env.SourceCode('.', env.SCCS()) - env.Program('hello.c') - - - s.hello.c - - - - - scons -Q - - -
- - diff --git a/doc/user/sourcecode.xml b/doc/user/sourcecode.xml index 1818d8e..04c76d0 100644 --- a/doc/user/sourcecode.xml +++ b/doc/user/sourcecode.xml @@ -42,18 +42,20 @@
- + + env = Environment() env.SourceCode('.', env.BitKeeper()) env.Program('hello.c') - + + + s.hello.c + + - - % scons -Q - bk get hello.c - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -66,18 +68,17 @@ - + + env = Environment() env.SourceCode('.', env.CVS('/usr/local/CVS')) env.Program('hello.c') - + + - - % scons -Q - cvs -d /usr/local/CVS co hello.c - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -90,18 +91,20 @@ - + + env = Environment() env.SourceCode('.', env.RCS()) env.Program('hello.c') - + + + hello.c,v + + - - % scons -Q - co hello.c - cc -o hello.o -c hello.c - cc -o hello hello.o - + + scons -Q + @@ -114,18 +117,20 @@ - + + env = Environment() env.SourceCode('.', env.SCCS()) env.Program('hello.c') - - - - % scons -Q - sccs get hello.c - cc -o hello.o -c hello.c - cc -o hello hello.o - + + + s.hello.c + + + + + scons -Q + diff --git a/doc/user/tasks.in b/doc/user/tasks.in deleted file mode 100644 index 79787a6..0000000 --- a/doc/user/tasks.in +++ /dev/null @@ -1,146 +0,0 @@ - - - -There is a common set of simple tasks that many build configurations rely -on as they become more complex. Most build tools have special -purpose constructs for performing these tasks, but since &SConscript; -files are &Python; scripts, you can use more flexible built-in &Python; -services to perform these tasks. This appendix lists a number of these -tasks and how to implement them in &Python; and &SCons;. - - - -Wildcard globbing to create a list of filenames - -files = Glob(wildcard) - - - - -Filename extension substitution - -import os.path -filename = os.path.splitext(filename)[0]+extension - - - - -Appending a path prefix to a list of filenames - -import os.path -filenames = [os.path.join(prefix, x) for x in filenames] - - - - -Substituting a path prefix with another one - -if filename.find(old_prefix) == 0: - filename = filename.replace(old_prefix, new_prefix) - - - - -Filtering a filename list to exclude/retain only a specific set -of extensions - -import os.path -filenames = [x for x in filenames if os.path.splitext(x)[1] in extensions] - - - - -The "backtick function": run a shell command and capture the -output -import os -output = os.popen(command).read() - - - - -Generating source code: how code can be generated and used by SCons - - - -The Copy builders here could be any arbitrary shell or python function -that produces one or more files. This example shows how to create -those files and use them in &SCons;. - - - - - -#### SConstruct -env = Environment() -env.Append(CPPPATH = "#") - -## Header example -env.Append(BUILDERS = - {'Copy1' : Builder(action = 'cat < $SOURCE > $TARGET', - suffix='.h', src_suffix='.bar')}) -env.Copy1('test.bar') # produces test.h from test.bar. -env.Program('app','main.cpp') # indirectly depends on test.bar - -## Source file example -env.Append(BUILDERS = - {'Copy2' : Builder(action = 'cat < $SOURCE > $TARGET', - suffix='.cpp', src_suffix='.bar2')}) -foo = env.Copy2('foo.bar2') # produces foo.cpp from foo.bar2. -env.Program('app2',['main2.cpp'] + foo) # compiles main2.cpp and foo.cpp into app2. - - - -#include "test.h" - - -// nothing here - - -//// main2.cpp - - -// nothing here - - - - - -Where main.cpp looks like this: - - - - - - - -produces this: - - - - scons -Q - - - diff --git a/doc/user/tasks.xml b/doc/user/tasks.xml index 1a13a5b..79787a6 100644 --- a/doc/user/tasks.xml +++ b/doc/user/tasks.xml @@ -91,25 +91,40 @@ those files and use them in &SCons;. - + + #### SConstruct env = Environment() env.Append(CPPPATH = "#") ## Header example env.Append(BUILDERS = - {'Copy1' : Builder(action = 'cat < $SOURCE > $TARGET', + {'Copy1' : Builder(action = 'cat < $SOURCE > $TARGET', suffix='.h', src_suffix='.bar')}) env.Copy1('test.bar') # produces test.h from test.bar. env.Program('app','main.cpp') # indirectly depends on test.bar ## Source file example env.Append(BUILDERS = - {'Copy2' : Builder(action = 'cat < $SOURCE > $TARGET', + {'Copy2' : Builder(action = 'cat < $SOURCE > $TARGET', suffix='.cpp', src_suffix='.bar2')}) foo = env.Copy2('foo.bar2') # produces foo.cpp from foo.bar2. env.Program('app2',['main2.cpp'] + foo) # compiles main2.cpp and foo.cpp into app2. - + + + +#include "test.h" + + +// nothing here + + +//// main2.cpp + + +// nothing here + + @@ -117,21 +132,15 @@ Where main.cpp looks like this: - - -#include "test.h" - + + produces this: - - % scons -Q - cc -o app main.cpp - cat < foo.bar2 > foo.cpp - cc -o app2 main2.cpp foo.cpp - cat < test.bar > test.h - + + scons -Q + diff --git a/doc/user/tools.in b/doc/user/tools.in deleted file mode 100644 index 512bf97..0000000 --- a/doc/user/tools.in +++ /dev/null @@ -1,38 +0,0 @@ - - - - -This appendix contains descriptions of all of the -Tools modules that are -available "out of the box" in this version of SCons. - - - - - -&tools-gen; - - diff --git a/doc/user/troubleshoot.in b/doc/user/troubleshoot.in deleted file mode 100644 index d171293..0000000 --- a/doc/user/troubleshoot.in +++ /dev/null @@ -1,914 +0,0 @@ - - - - - The experience of configuring any - software build tool to build a large code base - usually, at some point, - involves trying to figure out why - the tool is behaving a certain way, - and how to get it to behave the way you want. - &SCons; is no different. - This appendix contains a number of - different ways in which you can - get some additional insight into &SCons;' behavior. - - - - - - Note that we're always interested in trying to - improve how you can troubleshoot configuration problems. - If you run into a problem that has - you scratching your head, - and which there just doesn't seem to be a good way to debug, - odds are pretty good that someone else will run into - the same problem, too. - If so, please let the SCons development team know - (preferably by filing a bug report - or feature request at our project pages at tigris.org) - so that we can use your feedback - to try to come up with a better way to help you, - and others, get the necessary insight into &SCons; behavior - to help identify and fix configuration issues. - - - -
- Why is That Target Being Rebuilt? the &debug-explain; Option - - - - Let's look at a simple example of - a misconfigured build - that causes a target to be rebuilt - every time &SCons; is run: - - - - - - # Intentionally misspell the output file name in the - # command used to create the file: - Command('file.out', 'file.in', 'cp $SOURCE file.oout') - - - file.in - - - - - - (Note to Windows users: The POSIX &cp; command - copies the first file named on the command line - to the second file. - In our example, it copies the &file_in; file - to the &file_out; file.) - - - - - - Now if we run &SCons; multiple times on this example, - we see that it re-runs the &cp; - command every time: - - - - - scons -Q - scons -Q - scons -Q - - - - - In this example, - the underlying cause is obvious: - we've intentionally misspelled the output file name - in the &cp; command, - so the command doesn't actually - build the &file_out; file that we've told &SCons; to expect. - But if the problem weren't obvious, - it would be helpful - to specify the &debug-explain; option - on the command line - to have &SCons; tell us very specifically - why it's decided to rebuild the target: - - - - - scons -Q --debug=explain - - - - - If this had been a more complicated example - involving a lot of build output, - having &SCons; tell us that - it's trying to rebuild the target file - because it doesn't exist - would be an important clue - that something was wrong with - the command that we invoked to build it. - - - - - - The &debug-explain; option also comes in handy - to help figure out what input file changed. - Given a simple configuration that builds - a program from three source files, - changing one of the source files - and rebuilding with the &debug-explain; - option shows very specifically - why &SCons; rebuilds the files that it does: - - - - - - Program('prog', ['file1.c', 'file2.c', 'file3.c']) - - - file1.c - - - file2.c - - - file3.c - - - - - scons -Q - edit file2.c - scons -Q --debug=explain - - - - - This becomes even more helpful - in identifying when a file is rebuilt - due to a change in an implicit dependency, - such as an incuded .h file. - If the file1.c - and file3.c files - in our example - both included a &hello_h; file, - then changing that included file - and re-running &SCons; with the &debug-explain; option - will pinpoint that it's the change to the included file - that starts the chain of rebuilds: - - - - - - Program('prog', ['file1.c', 'file2.c', 'file3.c'], CPPPATH='.') - - - #include <hello.h> - file1.c - - - file2.c - - - #include <hello.h> - file3.c - - - #define string "world" - - - - - scons -Q - edit hello.h - scons -Q --debug=explain - - - - - (Note that the &debug-explain; option will only tell you - why &SCons; decided to rebuild necessary targets. - It does not tell you what files it examined - when deciding not - to rebuild a target file, - which is often a more valuable question to answer.) - - - -
- -
- What's in That Construction Environment? the &Dump; Method - - - - When you create a construction environment, - &SCons; populates it - with construction variables that are set up - for various compilers, linkers and utilities - that it finds on your system. - Although this is usually helpful and what you want, - it might be frustrating if &SCons; - doesn't set certain variables that you - expect to be set. - In situations like this, - it's sometimes helpful to use the - construction environment &Dump; method - to print all or some of - the construction variables. - Note that the &Dump; method - returns - the representation of the variables - in the environment - for you to print (or otherwise manipulate): - - - - - - env = Environment() - print env.Dump() - - - - - - On a POSIX system with gcc installed, - this might generate: - - - - - scons - - - - - On a Windows system with Visual C++ - the output might look like: - - - - - scons - - - - - The construction environments in these examples have - actually been restricted to just gcc and Visual C++, - respectively. - In a real-life situation, - the construction environments will - likely contain a great many more variables. - Also note that we've massaged the example output above - to make the memory address of all objects a constant 0x700000. - In reality, you would see a different hexadecimal - number for each object. - - - - - - To make it easier to see just what you're - interested in, - the &Dump; method allows you to - specify a specific constrcution variable - that you want to disply. - For example, - it's not unusual to want to verify - the external environment used to execute build commands, - to make sure that the PATH and other - environment variables are set up the way they should be. - You can do this as follows: - - - - - - env = Environment() - print env.Dump('ENV') - - - - - - Which might display the following when executed on a POSIX system: - - - - - scons - - - - - And the following when executed on a Windows system: - - - - - scons - - -
- -
- - What Dependencies Does &SCons; Know About? the &tree; Option - - - - Sometimes the best way to try to figure out what - &SCons; is doing is simply to take a look at the - dependency graph that it constructs - based on your &SConscript; files. - The --tree option - will display all or part of the - &SCons; dependency graph in an - "ASCII art" graphical format - that shows the dependency hierarchy. - - - - - - For example, given the following input &SConstruct; file: - - - - - - env = Environment(CPPPATH = ['.']) - env.Program('prog', ['f1.c', 'f2.c', 'f3.c']) - - - #include "inc.h" - - - #include "inc.h" - - - #include "inc.h" - - - inc.h - - - - - - Running &SCons; with the --tree=all - option yields: - - - - - scons -Q --tree=all - - - - - The tree will also be printed when the - -n (no execute) option is used, - which allows you to examine the dependency graph - for a configuration without actually - rebuilding anything in the tree. - - - - - - The --tree option only prints - the dependency graph for the specified targets - (or the default target(s) if none are specified on the command line). - So if you specify a target like f2.o - on the command line, - the --tree option will only - print the dependency graph for that file: - - - - - scons -Q --tree=all f2.o - - - - - This is, of course, useful for - restricting the output from a very large - build configuration to just a - portion in which you're interested. - Multiple targets are fine, - in which case a tree will be printed - for each specified target: - - - - - scons -Q --tree=all f1.o f3.o - - - - - The status argument may be used - to tell &SCons; to print status information about - each file in the dependency graph: - - - - - scons -Q --tree=status - - - - - Note that --tree=all,status is equivalent; - the all - is assumed if only status is present. - As an alternative to all, - you can specify --tree=derived - to have &SCons; only print derived targets - in the tree output, - skipping source files - (like .c and .h files): - - - - - scons -Q --tree=derived - - - - - You can use the status - modifier with derived as well: - - - - - scons -Q --tree=derived,status - - - - - Note that the order of the --tree= - arguments doesn't matter; - --tree=status,derived is - completely equivalent. - - - - - - The default behavior of the --tree option - is to repeat all of the dependencies each time the library dependency - (or any other dependency file) is encountered in the tree. - If certain target files share other target files, - such as two programs that use the same library: - - - - - - env = Environment(CPPPATH = ['.'], - LIBS = ['foo'], - LIBPATH = ['.']) - env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) - env.Program('prog1.c') - env.Program('prog2.c') - - - #include "inc.h" - - - #include "inc.h" - - - #include "inc.h" - - - #include "inc.h" - - - #include "inc.h" - - - inc.h - - - - - - Then there can be a lot of repetition in the - --tree= output: - - - - - scons -Q --tree=all - - - - - In a large configuration with many internal libraries - and include files, - this can very quickly lead to huge output trees. - To help make this more manageable, - a prune modifier may - be added to the option list, - in which case &SCons; - will print the name of a target that has - already been visited during the tree-printing - in [square brackets] - as an indication that the dependencies - of the target file may be found - by looking farther up the tree: - - - - - scons -Q --tree=prune - - - - - Like the status keyword, - the prune argument by itself - is equivalent to --tree=all,prune. - - - -
- -
- - How is &SCons; Constructing the Command Lines It Executes? the &debug-presub; Option - - - - Sometimes it's useful to look at the - pre-substitution string - that &SCons; uses to generate - the command lines it executes. - This can be done with the &debug-presub; option: - - - - - - env = Environment(CPPPATH = ['.']) - env.Program('prog', 'prog.c') - - - prog.c - - - - - - - % scons -Q --debug=presub - Building prog.o with action: - $CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCOMCOM $SOURCES - cc -o prog.o -c -I. prog.c - Building prog with action: - $SMART_LINKCOM - cc -o prog prog.o - - -
- -
- - Where is &SCons; Searching for Libraries? the &debug-findlibs; Option - - - - To get some insight into what library names - &SCons; is searching for, - and in which directories it is searching, - Use the --debug=findlibs option. - Given the following input &SConstruct; file: - - - - - - env = Environment(LIBPATH = ['libs1', 'libs2']) - env.Program('prog.c', LIBS=['foo', 'bar']) - - - prog.c - - - libs1/libfoo.a - - - libs2/libbar.a - - - - - - And the libraries libfoo.a - and libbar.a - in libs1 and libs2, - respectively, - use of the --debug=findlibs option yields: - - - - - scons -Q --debug=findlibs - - -
- - - -
- - Where is &SCons; Blowing Up? the &debug-stacktrace; Option - - - - In general, &SCons; tries to keep its error - messages short and informative. - That means we usually try to avoid showing - the stack traces that are familiar - to experienced Python programmers, - since they usually contain much more - information than is useful to most people. - - - - - - For example, the following &SConstruct; file: - - - - - - Program('prog.c') - - - - - - Generates the following error if the - prog.c file - does not exist: - - - - - scons -Q - - - - - In this case, - the error is pretty obvious. - But if it weren't, - and you wanted to try to get more information - about the error, - the &debug-stacktrace; option - would show you exactly where in the &SCons; source code - the problem occurs: - - - - - scons -Q --debug=stacktrace - - - - - Of course, if you do need to dive into the &SCons; source code, - we'd like to know if, or how, - the error messages or troubleshooting options - could have been improved to avoid that. - Not everyone has the necessary time or - Python skill to dive into the source code, - and we'd like to improve &SCons; - for those people as well... - - - -
- -
- - How is &SCons; Making Its Decisions? the &taskmastertrace; Option - - - - The internal &SCons; subsystem that handles walking - the dependency graph - and controls the decision-making about what to rebuild - is the Taskmaster. - &SCons; supports a --taskmastertrace - option that tells the Taskmaster to print - information about the children (dependencies) - of the various Nodes on its walk down the graph, - which specific dependent Nodes are being evaluated, - and in what order. - - - - - - The --taskmastertrace option - takes as an argument the name of a file in - which to put the trace output, - with - (a single hyphen) - indicating that the trace messages - should be printed to the standard output: - - - - - - env = Environment(CPPPATH = ['.']) - env.Program('prog.c') - - - #include "inc.h" - prog.c - - - #define STRING "one" - - - - - scons -Q --taskmastertrace=- prog - - - - - The --taskmastertrace option - doesn't provide information about the actual - calculations involved in deciding if a file is up-to-date, - but it does show all of the dependencies - it knows about for each Node, - and the order in which those dependencies are evaluated. - This can be useful as an alternate way to determine - whether or not your &SCons; configuration, - or the implicit dependency scan, - has actually identified all the correct dependencies - you want it to. - - - -
- -
- - Watch &SCons; prepare targets for building: the &debug-prepare; Option - - - - Sometimes SCons doesn't build the target you want - and it's difficult to figure out why. You can use - the --debug=prepare option - to see all the targets &SCons; is considering, whether - they are already up-to-date or not. The message is - printed before &SCons; decides whether to build the target. - - -
- -
- - Why is a file disappearing? the --debug=duplicate Option - - - - When using the &Duplicate; option to create variant dirs, - sometimes you may find files not getting copied to where you - expect (or not at all), or files mysteriously disappearing. These - are usually because of a misconfiguration of some kind in the - SConstruct/SConscript, but they can be tricky to debug. The - --debug=duplicate option shows each time a variant file is - unlinked and relinked from its source (or copied, depending on - settings), and also shows a message for removing "stale" - variant-dir files that no longer have a corresponding source file. - It also prints a line for each target that's removed just before - building, since that can also be mistaken for the same thing. - - - -
- - - - diff --git a/doc/user/troubleshoot.xml b/doc/user/troubleshoot.xml index 093574c..d171293 100644 --- a/doc/user/troubleshoot.xml +++ b/doc/user/troubleshoot.xml @@ -69,11 +69,16 @@ - + + # Intentionally misspell the output file name in the # command used to create the file: Command('file.out', 'file.in', 'cp $SOURCE file.oout') - + + + file.in + + @@ -93,14 +98,11 @@ - - % scons -Q - cp file.in file.oout - % scons -Q - cp file.in file.oout - % scons -Q - cp file.in file.oout - + + scons -Q + scons -Q + scons -Q + @@ -119,11 +121,9 @@ - - % scons -Q --debug=explain - scons: building `file.out' because it doesn't exist - cp file.in file.oout - + + scons -Q --debug=explain + @@ -151,22 +151,26 @@ - + + + Program('prog', ['file1.c', 'file2.c', 'file3.c']) + + + file1.c + + + file2.c + + + file3.c + + - - % scons -Q - cc -o file1.o -c file1.c - cc -o file2.o -c file2.c - cc -o file3.o -c file3.c - cc -o prog file1.o file2.o file3.o - % edit file2.c - [CHANGE THE CONTENTS OF file2.c] - % scons -Q --debug=explain - scons: rebuilding `file2.o' because `file2.c' changed - cc -o file2.o -c file2.c - scons: rebuilding `prog' because `file2.o' changed - cc -o prog file1.o file2.o file3.o - + + scons -Q + edit file2.c + scons -Q --debug=explain + @@ -185,26 +189,31 @@ - + + + Program('prog', ['file1.c', 'file2.c', 'file3.c'], CPPPATH='.') + + + #include <hello.h> + file1.c + + + file2.c + + + #include <hello.h> + file3.c + + + #define string "world" + + - - % scons -Q - cc -o file1.o -c -I. file1.c - cc -o file2.o -c -I. file2.c - cc -o file3.o -c -I. file3.c - cc -o prog file1.o file2.o file3.o - % edit hello.h - [CHANGE THE CONTENTS OF hello.h] - % scons -Q --debug=explain - scons: rebuilding `file1.o' because `hello.h' changed - cc -o file1.o -c -I. file1.c - scons: rebuilding `file3.o' because `hello.h' changed - cc -o file3.o -c -I. file3.c - scons: rebuilding `prog' because: - `file1.o' changed - `file3.o' changed - cc -o prog file1.o file2.o file3.o - + + scons -Q + edit hello.h + scons -Q --debug=explain + @@ -246,10 +255,12 @@ - + + env = Environment() print env.Dump() - + + @@ -258,79 +269,9 @@ - - % scons - scons: Reading SConscript files ... - { 'BUILDERS': {'_InternalInstall': <function InstallBuilderWrapper at 0x700000>, '_InternalInstallAs': <function InstallAsBuilderWrapper at 0x700000>}, - 'CONFIGUREDIR': '#/.sconf_temp', - 'CONFIGURELOG': '#/config.log', - 'CPPSUFFIXES': [ '.c', - '.C', - '.cxx', - '.cpp', - '.c++', - '.cc', - '.h', - '.H', - '.hxx', - '.hpp', - '.hh', - '.F', - '.fpp', - '.FPP', - '.m', - '.mm', - '.S', - '.spp', - '.SPP', - '.sx'], - 'DSUFFIXES': ['.d'], - 'Dir': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'Dirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'ENV': { 'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'}, - 'ESCAPE': <function escape at 0x700000>, - 'File': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'HOST_ARCH': None, - 'HOST_OS': None, - 'IDLSUFFIXES': ['.idl', '.IDL'], - 'INSTALL': <function copyFunc at 0x700000>, - 'LIBPREFIX': 'lib', - 'LIBPREFIXES': ['$LIBPREFIX'], - 'LIBSUFFIX': '.a', - 'LIBSUFFIXES': ['$LIBSUFFIX', '$SHLIBSUFFIX'], - 'MAXLINELENGTH': 128072, - 'OBJPREFIX': '', - 'OBJSUFFIX': '.o', - 'PLATFORM': 'posix', - 'PROGPREFIX': '', - 'PROGSUFFIX': '', - 'PSPAWN': <function piped_env_spawn at 0x700000>, - 'RDirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'SCANNERS': [], - 'SHELL': 'sh', - 'SHLIBPREFIX': '$LIBPREFIX', - 'SHLIBSUFFIX': '.so', - 'SHOBJPREFIX': '$OBJPREFIX', - 'SHOBJSUFFIX': '$OBJSUFFIX', - 'SPAWN': <function spawnvpe_spawn at 0x700000>, - 'TARGET_ARCH': None, - 'TARGET_OS': None, - 'TEMPFILE': <class 'SCons.Platform.TempFileMunge'>, - 'TEMPFILEPREFIX': '@', - 'TOOLS': ['install', 'install'], - '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', - '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', - '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', - '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', - '__RPATH': '$_RPATH', - '_concat': <function _concat at 0x700000>, - '_defines': <function _defines at 0x700000>, - '_stripixes': <function _stripixes at 0x700000>} - scons: done reading SConscript files. - scons: Building targets ... - scons: `.' is up to date. - scons: done building targets. - + + scons + @@ -339,112 +280,9 @@ - - C:\>scons - scons: Reading SConscript files ... - { 'BUILDERS': {'_InternalInstall': <function InstallBuilderWrapper at 0x700000>, 'Object': <SCons.Builder.CompositeBuilder object at 0x700000>, 'PCH': <SCons.Builder.BuilderBase object at 0x700000>, 'RES': <SCons.Builder.BuilderBase object at 0x700000>, 'SharedObject': <SCons.Builder.CompositeBuilder object at 0x700000>, 'StaticObject': <SCons.Builder.CompositeBuilder object at 0x700000>, '_InternalInstallAs': <function InstallAsBuilderWrapper at 0x700000>}, - 'CC': 'cl', - 'CCCOM': <SCons.Action.FunctionAction object at 0x700000>, - 'CCFLAGS': ['/nologo'], - 'CCPCHFLAGS': ['${(PCH and "/Yu%s \\"/Fp%s\\""%(PCHSTOP or "",File(PCH))) or ""}'], - 'CCPDBFLAGS': ['${(PDB and "/Z7") or ""}'], - 'CFILESUFFIX': '.c', - 'CFLAGS': [], - 'CONFIGUREDIR': '#/.sconf_temp', - 'CONFIGURELOG': '#/config.log', - 'CPPDEFPREFIX': '/D', - 'CPPDEFSUFFIX': '', - 'CPPSUFFIXES': [ '.c', - '.C', - '.cxx', - '.cpp', - '.c++', - '.cc', - '.h', - '.H', - '.hxx', - '.hpp', - '.hh', - '.F', - '.fpp', - '.FPP', - '.m', - '.mm', - '.S', - '.spp', - '.SPP', - '.sx'], - 'CXX': '$CC', - 'CXXCOM': '${TEMPFILE("$CXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $CXXFLAGS $CCFLAGS $_CCCOMCOM")}', - 'CXXFILESUFFIX': '.cc', - 'CXXFLAGS': ['$(', '/TP', '$)'], - 'DSUFFIXES': ['.d'], - 'Dir': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'Dirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'ENV': { 'PATH': 'C:\\WINDOWS\\System32', - 'PATHEXT': '.COM;.EXE;.BAT;.CMD', - 'SystemRoot': 'C:\\WINDOWS'}, - 'ESCAPE': <function escape at 0x700000>, - 'File': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'HOST_ARCH': '', - 'HOST_OS': 'win32', - 'IDLSUFFIXES': ['.idl', '.IDL'], - 'INCPREFIX': '/I', - 'INCSUFFIX': '', - 'INSTALL': <function copyFunc at 0x700000>, - 'LIBPREFIX': '', - 'LIBPREFIXES': ['$LIBPREFIX'], - 'LIBSUFFIX': '.lib', - 'LIBSUFFIXES': ['$LIBSUFFIX'], - 'MAXLINELENGTH': 2048, - 'MSVC_SETUP_RUN': True, - 'OBJPREFIX': '', - 'OBJSUFFIX': '.obj', - 'PCHCOM': '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS', - 'PCHPDBFLAGS': ['${(PDB and "/Yd") or ""}'], - 'PLATFORM': 'win32', - 'PROGPREFIX': '', - 'PROGSUFFIX': '.exe', - 'PSPAWN': <function piped_spawn at 0x700000>, - 'RC': 'rc', - 'RCCOM': <SCons.Action.FunctionAction object at 0x700000>, - 'RCFLAGS': [], - 'RCSUFFIXES': ['.rc', '.rc2'], - 'RDirs': <SCons.Defaults.Variable_Method_Caller object at 0x700000>, - 'SCANNERS': [], - 'SHCC': '$CC', - 'SHCCCOM': <SCons.Action.FunctionAction object at 0x700000>, - 'SHCCFLAGS': ['$CCFLAGS'], - 'SHCFLAGS': ['$CFLAGS'], - 'SHCXX': '$CXX', - 'SHCXXCOM': '${TEMPFILE("$SHCXX $_MSVC_OUTPUT_FLAG /c $CHANGED_SOURCES $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM")}', - 'SHCXXFLAGS': ['$CXXFLAGS'], - 'SHELL': None, - 'SHLIBPREFIX': '', - 'SHLIBSUFFIX': '.dll', - 'SHOBJPREFIX': '$OBJPREFIX', - 'SHOBJSUFFIX': '$OBJSUFFIX', - 'SPAWN': <function spawn at 0x700000>, - 'STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME': 1, - 'TARGET_ARCH': '', - 'TARGET_OS': 'win32', - 'TEMPFILE': <class 'SCons.Platform.TempFileMunge'>, - 'TEMPFILEPREFIX': '@', - 'TOOLS': ['msvc', 'install', 'install'], - '_CCCOMCOM': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $CCPCHFLAGS $CCPDBFLAGS', - '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}', - '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', - '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)', - '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}', - '_MSVC_OUTPUT_FLAG': <function msvc_output_flag at 0x700000>, - '_concat': <function _concat at 0x700000>, - '_defines': <function _defines at 0x700000>, - '_stripixes': <function _stripixes at 0x700000>} - scons: done reading SConscript files. - scons: Building targets ... - scons: `.' is up to date. - scons: done building targets. - + + scons + @@ -477,10 +315,12 @@ - + + env = Environment() print env.Dump('ENV') - + + @@ -488,15 +328,9 @@ - - % scons - scons: Reading SConscript files ... - { 'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'} - scons: done reading SConscript files. - scons: Building targets ... - scons: `.' is up to date. - scons: done building targets. - + + scons + @@ -504,17 +338,9 @@ - - C:\>scons - scons: Reading SConscript files ... - { 'PATH': 'C:\\WINDOWS\\System32', - 'PATHEXT': '.COM;.EXE;.BAT;.CMD', - 'SystemRoot': 'C:\\WINDOWS'} - scons: done reading SConscript files. - scons: Building targets ... - scons: `.' is up to date. - scons: done building targets. - + + scons + @@ -542,10 +368,24 @@ - + + env = Environment(CPPPATH = ['.']) env.Program('prog', ['f1.c', 'f2.c', 'f3.c']) - + + + #include "inc.h" + + + #include "inc.h" + + + #include "inc.h" + + + inc.h + + @@ -554,38 +394,9 @@ - - % scons -Q --tree=all - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - cc -o prog f1.o f2.o f3.o - +-. - +-SConstruct - +-f1.c - +-f1.o - | +-f1.c - | +-inc.h - +-f2.c - +-f2.o - | +-f2.c - | +-inc.h - +-f3.c - +-f3.o - | +-f3.c - | +-inc.h - +-inc.h - +-prog - +-f1.o - | +-f1.c - | +-inc.h - +-f2.o - | +-f2.c - | +-inc.h - +-f3.o - +-f3.c - +-inc.h - + + scons -Q --tree=all + @@ -609,13 +420,9 @@ - - % scons -Q --tree=all f2.o - cc -o f2.o -c -I. f2.c - +-f2.o - +-f2.c - +-inc.h - + + scons -Q --tree=all f2.o + @@ -629,17 +436,9 @@ - - % scons -Q --tree=all f1.o f3.o - cc -o f1.o -c -I. f1.c - +-f1.o - +-f1.c - +-inc.h - cc -o f3.o -c -I. f3.c - +-f3.o - +-f3.c - +-inc.h - + + scons -Q --tree=all f1.o f3.o + @@ -649,49 +448,9 @@ - - % scons -Q --tree=status - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - cc -o prog f1.o f2.o f3.o - E = exists - R = exists in repository only - b = implicit builder - B = explicit builder - S = side effect - P = precious - A = always build - C = current - N = no clean - H = no cache - - [E b ]+-. - [E C ] +-SConstruct - [E C ] +-f1.c - [E B C ] +-f1.o - [E C ] | +-f1.c - [E C ] | +-inc.h - [E C ] +-f2.c - [E B C ] +-f2.o - [E C ] | +-f2.c - [E C ] | +-inc.h - [E C ] +-f3.c - [E B C ] +-f3.o - [E C ] | +-f3.c - [E C ] | +-inc.h - [E C ] +-inc.h - [E B C ] +-prog - [E B C ] +-f1.o - [E C ] | +-f1.c - [E C ] | +-inc.h - [E B C ] +-f2.o - [E C ] | +-f2.c - [E C ] | +-inc.h - [E B C ] +-f3.o - [E C ] +-f3.c - [E C ] +-inc.h - + + scons -Q --tree=status + @@ -707,21 +466,9 @@ - - % scons -Q --tree=derived - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - cc -o prog f1.o f2.o f3.o - +-. - +-f1.o - +-f2.o - +-f3.o - +-prog - +-f1.o - +-f2.o - +-f3.o - + + scons -Q --tree=derived + @@ -730,32 +477,9 @@ - - % scons -Q --tree=derived,status - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - cc -o prog f1.o f2.o f3.o - E = exists - R = exists in repository only - b = implicit builder - B = explicit builder - S = side effect - P = precious - A = always build - C = current - N = no clean - H = no cache - - [E b ]+-. - [E B C ] +-f1.o - [E B C ] +-f2.o - [E B C ] +-f3.o - [E B C ] +-prog - [E B C ] +-f1.o - [E B C ] +-f2.o - [E B C ] +-f3.o - + + scons -Q --tree=derived,status + @@ -776,14 +500,34 @@ - + + env = Environment(CPPPATH = ['.'], LIBS = ['foo'], LIBPATH = ['.']) env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) env.Program('prog1.c') env.Program('prog2.c') - + + + #include "inc.h" + + + #include "inc.h" + + + #include "inc.h" + + + #include "inc.h" + + + #include "inc.h" + + + inc.h + + @@ -792,79 +536,9 @@ - - % scons -Q --tree=all - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - ar rc libfoo.a f1.o f2.o f3.o - ranlib libfoo.a - cc -o prog1.o -c -I. prog1.c - cc -o prog1 prog1.o -L. -lfoo - cc -o prog2.o -c -I. prog2.c - cc -o prog2 prog2.o -L. -lfoo - +-. - +-SConstruct - +-f1.c - +-f1.o - | +-f1.c - | +-inc.h - +-f2.c - +-f2.o - | +-f2.c - | +-inc.h - +-f3.c - +-f3.o - | +-f3.c - | +-inc.h - +-inc.h - +-libfoo.a - | +-f1.o - | | +-f1.c - | | +-inc.h - | +-f2.o - | | +-f2.c - | | +-inc.h - | +-f3.o - | +-f3.c - | +-inc.h - +-prog1 - | +-prog1.o - | | +-prog1.c - | | +-inc.h - | +-libfoo.a - | +-f1.o - | | +-f1.c - | | +-inc.h - | +-f2.o - | | +-f2.c - | | +-inc.h - | +-f3.o - | +-f3.c - | +-inc.h - +-prog1.c - +-prog1.o - | +-prog1.c - | +-inc.h - +-prog2 - | +-prog2.o - | | +-prog2.c - | | +-inc.h - | +-libfoo.a - | +-f1.o - | | +-f1.c - | | +-inc.h - | +-f2.o - | | +-f2.c - | | +-inc.h - | +-f3.o - | +-f3.c - | +-inc.h - +-prog2.c - +-prog2.o - +-prog2.c - +-inc.h - + + scons -Q --tree=all + @@ -884,51 +558,9 @@ - - % scons -Q --tree=prune - cc -o f1.o -c -I. f1.c - cc -o f2.o -c -I. f2.c - cc -o f3.o -c -I. f3.c - ar rc libfoo.a f1.o f2.o f3.o - ranlib libfoo.a - cc -o prog1.o -c -I. prog1.c - cc -o prog1 prog1.o -L. -lfoo - cc -o prog2.o -c -I. prog2.c - cc -o prog2 prog2.o -L. -lfoo - +-. - +-SConstruct - +-f1.c - +-f1.o - | +-f1.c - | +-inc.h - +-f2.c - +-f2.o - | +-f2.c - | +-inc.h - +-f3.c - +-f3.o - | +-f3.c - | +-inc.h - +-inc.h - +-libfoo.a - | +-[f1.o] - | +-[f2.o] - | +-[f3.o] - +-prog1 - | +-prog1.o - | | +-prog1.c - | | +-inc.h - | +-[libfoo.a] - +-prog1.c - +-[prog1.o] - +-prog2 - | +-prog2.o - | | +-prog2.c - | | +-inc.h - | +-[libfoo.a] - +-prog2.c - +-[prog2.o] - + + scons -Q --tree=prune + @@ -954,7 +586,15 @@ - + + + env = Environment(CPPPATH = ['.']) + env.Program('prog', 'prog.c') + + + prog.c + + - - - -This appendix contains descriptions of all of the -construction variables that are potentially -available "out of the box" in this version of SCons. -Whether or not setting a construction variable -in a construction environment -will actually have an effect depends on -whether any of the Tools and/or Builders -that use the variable have been -included in the construction environment. - - - - - -In this appendix, we have -appended the initial $ -(dollar sign) to the beginning of each -variable name when it appears in the text, -but left off the dollar sign -in the left-hand column -where the name appears for each entry. - - - - - -&variables-gen; - - diff --git a/doc/user/variants.in b/doc/user/variants.in deleted file mode 100644 index 9980b1d..0000000 --- a/doc/user/variants.in +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - The &variant_dir; keyword argument of - the &SConscript; function provides everything - we need to show how easy it is to create - variant builds using &SCons;. - Suppose, for example, that we want to - build a program for both Windows and Linux platforms, - but that we want to build it in a shared directory - with separate side-by-side build directories - for the Windows and Linux versions of the program. - - - - - - platform = ARGUMENTS.get('OS', Platform()) - - include = "#export/$PLATFORM/include" - lib = "#export/$PLATFORM/lib" - bin = "#export/$PLATFORM/bin" - - env = Environment(PLATFORM = platform, - BINDIR = bin, - INCDIR = include, - LIBDIR = lib, - CPPPATH = [include], - LIBPATH = [lib], - LIBS = 'world') - - Export('env') - - env.SConscript('src/SConscript', variant_dir='build/$PLATFORM') - - - - - - Import('env') - SConscript('hello/SConscript') - SConscript('world/SConscript') - - - Import('env') - hello = env.Program('hello.c') - env.Install('$BINDIR', hello) - - - #include "world.h" - int main(int argc, char *argv[]) { printf "hello.c\n"; world(); } - - - Import('env') - world = env.Library('world.c') - env.Install('$LIBDIR', world) - env.Install('$INCDIR', 'world.h') - - - #define STRING "world.h" - extern int world(); - - - int world() { printf "world.c\n"; } - - - - - - This SConstruct file, - when run on a Linux system, yields: - - - - - scons -Q OS=linux - - - - - The same SConstruct file on Windows would build: - - - - - scons -Q OS=windows - - - diff --git a/doc/user/variants.xml b/doc/user/variants.xml index 29d2d65..9980b1d 100644 --- a/doc/user/variants.xml +++ b/doc/user/variants.xml @@ -61,7 +61,8 @@ is pretty smart about rebuilding things when you change options. - + + platform = ARGUMENTS.get('OS', Platform()) include = "#export/$PLATFORM/include" @@ -79,7 +80,38 @@ is pretty smart about rebuilding things when you change options. Export('env') env.SConscript('src/SConscript', variant_dir='build/$PLATFORM') - + + + + + + Import('env') + SConscript('hello/SConscript') + SConscript('world/SConscript') + + + Import('env') + hello = env.Program('hello.c') + env.Install('$BINDIR', hello) + + + #include "world.h" + int main(int argc, char *argv[]) { printf "hello.c\n"; world(); } + + + Import('env') + world = env.Library('world.c') + env.Install('$LIBDIR', world) + env.Install('$INCDIR', 'world.h') + + + #define STRING "world.h" + extern int world(); + + + int world() { printf "world.c\n"; } + + @@ -88,17 +120,9 @@ is pretty smart about rebuilding things when you change options. - - % scons -Q OS=linux - Install file: "build/linux/world/world.h" as "export/linux/include/world.h" - cc -o build/linux/hello/hello.o -c -Iexport/linux/include build/linux/hello/hello.c - cc -o build/linux/world/world.o -c -Iexport/linux/include build/linux/world/world.c - ar rc build/linux/world/libworld.a build/linux/world/world.o - ranlib build/linux/world/libworld.a - Install file: "build/linux/world/libworld.a" as "export/linux/lib/libworld.a" - cc -o build/linux/hello/hello build/linux/hello/hello.o -Lexport/linux/lib -lworld - Install file: "build/linux/hello/hello" as "export/linux/bin/hello" - + + scons -Q OS=linux + @@ -106,17 +130,9 @@ is pretty smart about rebuilding things when you change options. - - C:\>scons -Q OS=windows - Install file: "build/windows/world/world.h" as "export/windows/include/world.h" - cl /Fobuild\windows\hello\hello.obj /c build\windows\hello\hello.c /nologo /Iexport\windows\include - cl /Fobuild\windows\world\world.obj /c build\windows\world\world.c /nologo /Iexport\windows\include - lib /nologo /OUT:build\windows\world\world.lib build\windows\world\world.obj - Install file: "build/windows/world/world.lib" as "export/windows/lib/world.lib" - link /nologo /OUT:build\windows\hello\hello.exe /LIBPATH:export\windows\lib world.lib build\windows\hello\hello.obj - embedManifestExeCheck(target, source, env) - Install file: "build/windows/hello/hello.exe" as "export/windows/bin/hello.exe" - + + scons -Q OS=windows +