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/output.xml | 703 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) create mode 100644 doc/user/output.xml (limited to 'doc/user/output.xml') diff --git a/doc/user/output.xml b/doc/user/output.xml new file mode 100644 index 0000000..89b443b --- /dev/null +++ b/doc/user/output.xml @@ -0,0 +1,703 @@ + + + + + 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 + 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. + + + + + 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: + + + + + C:\>scons -h + scons: Reading SConscript files ... + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + + scons: warning: No installed VCs + File "<stdin>", line 67, in __call__ + + scons: warning: No version of Visual Studio compiler found - C/C++ compilers most likely not set correctly + File "<stdin>", line 67, in __call__ + 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. + + + + + But only show the relevant option on a Linux or UNIX system: + + + + + % 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. + + + + + 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') + + + + + 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') + + + + + + 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') + + + + + 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 + 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 . + + + + + 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: `.' 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'. + + +
-- cgit v1.2.3