From 72c578fd4b0b4a5a43e18594339ac4ff26c376dc Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Sat, 2 Jan 2010 20:56:27 +0100 Subject: Imported Upstream version 1.2.0.d20091224 --- doc/user/hierarchy.xml | 746 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 746 insertions(+) create mode 100644 doc/user/hierarchy.xml (limited to 'doc/user/hierarchy.xml') diff --git a/doc/user/hierarchy.xml b/doc/user/hierarchy.xml new file mode 100644 index 0000000..3495c5f --- /dev/null +++ b/doc/user/hierarchy.xml @@ -0,0 +1,746 @@ + + + + + + + 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']) + + + + + And subsidiary &SConscript; files that look like this: + + + + + + env = Environment() + env.Program('prog1', ['main.c', 'foo1.c', 'foo2.c']) + + + + + And this: + + + + + + env = Environment() + env.Program('prog2', ['main.c', 'bar1.c', 'bar2.c']) + + + + + Then, when we run &SCons; in the top-level directory, + our build looks like: + + + + + % 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 + + + + + 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: + + + + + env = Environment() + env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c']) + + + + + 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 + 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 + + + + + (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: + + + + + env = Environment() + env.Program('prog', ['main.c', '/usr/joe/lib/foo1.c', 'foo2.c']) + + + + + Which, when executed, would yield: + + + + + % 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 + + + + + (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) + + + + + We can do this by using the &Return; + function in the + foo/SConscript file like this: + + + + + + Import('env') + obj = env.Object('foo.c') + Return('obj') + + + + + (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 + 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 + + + + +
+ +
+ + -- cgit v1.2.3