diff --git a/CHANGES.txt b/CHANGES.txt index 8d58fd433..58fb9cf45 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -47,6 +47,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER Note: on Windows, SCons currently only has builtin support for clang, not for clang-cl, the version of the frontend that uses cl.exe-compatible command line switches. + - Some clarifications in the User Guide "Environments" chapter. RELEASE 4.8.1 - Tue, 03 Sep 2024 17:22:20 -0700 diff --git a/RELEASE.txt b/RELEASE.txt index 785ef953e..f831305f2 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -29,7 +29,7 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY - List modifications to existing features, where the previous behavior wouldn't actually be considered a bug -- Override envirionments, created when giving construction environment +- Override environments, created when giving construction environment keyword arguments to Builder calls (or manually, through the undocumented Override method), were modified not to "leak" on item deletion. The item will now not be deleted from the base environment. @@ -77,6 +77,8 @@ DOCUMENTATION typo fixes, even if they're mentioned in src/CHANGES.txt to give the contributor credit) +- Some clarifications in the User Guide "Environments" chapter. + DEVELOPMENT ----------- diff --git a/SCons/EnvironmentTests.py b/SCons/EnvironmentTests.py index 6a69e3cd1..361dda972 100644 --- a/SCons/EnvironmentTests.py +++ b/SCons/EnvironmentTests.py @@ -1037,7 +1037,8 @@ def test_BuilderWrapper_attributes(self) -> None: # underlying method it tests (Environment.BuilderWrapper.execute()) # is necessary, but we're leaving the code here for now in case # that's mistaken. - def _DO_NOT_test_Builder_execs(self) -> None: + @unittest.skip("BuilderWrapper.execute method not needed") + def test_Builder_execs(self) -> None: """Test Builder execution through different environments One environment is initialized with a single @@ -1291,10 +1292,14 @@ def RDirs(pathlist, fs=env.fs): ] assert flags == expect, flags - env.Replace(F77PATH = [ 'foo', '$FOO/bar', blat ], - INCPREFIX = 'foo ', - INCSUFFIX = 'bar', - FOO = 'baz') + # do a Replace using the dict form + newvalues = { + "F77PATH": ['foo', '$FOO/bar', blat], + "INCPREFIX": 'foo ', + "INCSUFFIX": 'bar', + "FOO": 'baz', + } + env.Replace(**newvalues) flags = env.subst_list('$_F77INCFLAGS', 1)[0] expect = [ '$(', normalize_path('foo'), diff --git a/SCons/Subst.xml b/SCons/Subst.xml index 00ed135ce..4ac4f7d0e 100644 --- a/SCons/Subst.xml +++ b/SCons/Subst.xml @@ -31,16 +31,16 @@ This file is processed by the bin/SConsDoc.py module. -Specifies the exceptions that will be allowed -when expanding construction variables. +Specifies the exceptions that will be ignored +when expanding &consvars;. By default, -any construction variable expansions that generate a -NameError +any &consvar; expansions that generate a +&NameError; or -IndexError +&IndexError; exception will expand to a '' -(an empty string) and not cause scons to fail. +(an empty string) and not cause &scons; to fail. All exceptions not in the specified list will generate an error message and terminate processing. @@ -51,7 +51,8 @@ If &f-AllowSubstExceptions; is called multiple times, each call completely overwrites the previous list -of allowed exceptions. +of ignored exceptions. +Calling it with no arguments means no exceptions will be ignored. diff --git a/doc/generated/functions.gen b/doc/generated/functions.gen index ff10f9df0..8563d66ac 100644 --- a/doc/generated/functions.gen +++ b/doc/generated/functions.gen @@ -405,16 +405,16 @@ env.Alias('update', ['file1', 'file2'], "update_database $SOURCES") AllowSubstExceptions([exception, ...]) -Specifies the exceptions that will be allowed -when expanding construction variables. +Specifies the exceptions that will be ignored +when expanding &consvars;. By default, -any construction variable expansions that generate a -NameError +any &consvar; expansions that generate a +&NameError; or -IndexError +&IndexError; exception will expand to a '' -(an empty string) and not cause scons to fail. +(an empty string) and not cause &scons; to fail. All exceptions not in the specified list will generate an error message and terminate processing. @@ -425,7 +425,8 @@ If &f-AllowSubstExceptions; is called multiple times, each call completely overwrites the previous list -of allowed exceptions. +of ignored exceptions. +Calling it with no arguments means no exceptions will be ignored. @@ -1634,6 +1635,19 @@ Example: cvars = env.Dictionary() cc_values = env.Dictionary('CC', 'CCFLAGS', 'CCCOM') + + +The object returned by &f-link-env-Dictionary; should be treated +as a read-only view into the &consvars;. +Some &consvars; have special internal handling, +and making changes through the &f-env-Dictionary; object can bypass +that handling and cause data inconsistencies. +The primary use of &f-env-Dictionary; is for diagnostic purposes - +it is used widely by test cases specifically because +it bypasses the special handling so that behavior +can be verified. + + diff --git a/doc/generated/variables.gen b/doc/generated/variables.gen index 68ac6db12..26371cff2 100644 --- a/doc/generated/variables.gen +++ b/doc/generated/variables.gen @@ -9651,16 +9651,41 @@ The suffix used for tar file names. TEMPFILE -A callable object used to handle overly long command line strings, -since operations which call out to a shell will fail -if the line is longer than the shell can accept. -This tends to particularly impact linking. -The tempfile object stores the command line in a temporary -file in the appropriate format, and returns -an alternate command line so the invoked tool will make -use of the contents of the temporary file. -If you need to replace the default tempfile object, -the callable should take into account the settings of +Holds a callable object which will be invoked to transform long +command lines (string or list) into an alternate form. +Length limits on various operating systems +may cause long command lines to fail when calling out to +a shell to run the command. +Most often affects linking, when there are many object files and/or +libraries to be linked, but may also affect other +compilation steps which have many arguments. +&cv-TEMPFILE; is not called directly, +but rather is typically embedded in another +&consvar;, to be expanded when used. Example: + + + +env["TEMPFILE"] = TempFileMunge +env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES', '$LINKCOMSTR')}" + + + +The SCons default value for &cv-TEMPFILE;, +TempFileMunge, +performs command substitution on the passed command line, +calculates whether modification is needed, +then puts all but the first word (assumed to be the command name) +of the resulting list into a temporary file +(sometimes called a response file or command file), +and returns a new command line consisting of the +the command name and an appropriately formatted reference +to the temporary file. + + + +A replacement for the default tempfile object would need +to do fundamentally the same thing, including taking into account +the values of &cv-link-MAXLINELENGTH;, &cv-link-TEMPFILEPREFIX;, &cv-link-TEMPFILESUFFIX;, @@ -9668,6 +9693,11 @@ the callable should take into account the settings of &cv-link-TEMPFILEDIR; and &cv-link-TEMPFILEARGESCFUNC;. +If a particular use case requires a different transformation +than the default, it is recommended to copy the mechanism and +define a new &consvar; and rewrite the relevant *COM +variable(s) to use it, to avoid possibly disrupting existing uses +of &cv-TEMPFILE;. @@ -9726,6 +9756,9 @@ Note this value is used literally and not expanded by the subst logic. The directory to create the long-lines temporary file in. +If unset, some suitable default should be chosen. +The default tempfile object lets the &Python; +tempfile module choose. @@ -9736,6 +9769,8 @@ The directory to create the long-lines temporary file in. The prefix for the name of the temporary file used to store command lines exceeding &cv-link-MAXLINELENGTH;. +The prefix must include the compiler syntax to actually +include and process the file. The default prefix is '@', which works for the &MSVC; and GNU toolchains on Windows. Set this appropriately for other toolchains, @@ -9751,7 +9786,7 @@ or '-via' for ARM toolchain. The suffix for the name of the temporary file used to store command lines exceeding &cv-link-MAXLINELENGTH;. -The suffix should include the dot ('.') if one is wanted as +The suffix should include the dot ('.') if one is needed as it will not be added automatically. The default is .lnk. diff --git a/doc/scons.mod b/doc/scons.mod index 76d82dfbd..ba70c056b 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -308,8 +308,10 @@ This file is processed by the bin/SConsDoc.py module. -IndexError"> -NameError"> +AttributeError"> +IndexError"> +KeyError"> +NameError"> str"> zipfile"> diff --git a/doc/user/command-line.xml b/doc/user/command-line.xml index 0bdb9c577..c0a3c0c55 100644 --- a/doc/user/command-line.xml +++ b/doc/user/command-line.xml @@ -874,7 +874,7 @@ prog.c get method, so you can supply a default value if the variable is not given on the command line. Otherwise, the build - will fail with a KeyError + will fail with a &KeyError; if the variable is not set. diff --git a/doc/user/environments.xml b/doc/user/environments.xml index eeaa23f75..a630c659d 100644 --- a/doc/user/environments.xml +++ b/doc/user/environments.xml @@ -410,7 +410,7 @@ environment, of directory names, suffixes, etc. - Unlike &Make;, &SCons; does not automatically + Unlike &Make;, &SCons; does not automatically copy or import values between different environments (with the exception of explicit clones of &consenvs;, which inherit the values from their parent). @@ -458,26 +458,39 @@ environment, of directory names, suffixes, etc. If you're not familiar with the &Python; programming language, - we need to talk a little bit about the &Python; dictionary data type. - A dictionary (also known by terms such as mapping, associative array - and key-value store) associates keys with values, such - that asking the dict about a key gives you back the associated value - and assigning to a key creates the association - either a new - setting if the key was unknown, or replacing the - previous association if the key was already in the dictionary. - Values can be retrieved using item access - (the key name in square brackets ([])), - and dictionaries also provide a - method named get which responds - with a default value, either None or a value - you supply as the second argument, if the key is not in the dictionary, - which avoids failing in that case. The syntax - for initializing a dictionary uses curly braces ({}). - Here are some simple examples (inspired by those in the official - Python tutorial) using syntax that indicates - interacting with the &Python; interpreter - (>>> is the interpreter prompt) - - you can try these out: + here is a short summary of the &Python; dictionary data type, + or "dict". You may also see the terms mapping, associative array + or key-value store used for this type of data structure, + which appears in many programming languages. + + + + + + A dictionary associates keys with values, + so asking the dict about a key gives you back the associated value. + Values can be retrieved using item access: + the key name string in square brackets (mydict["keyname"]). + If the key is not present, you get a &KeyError; exception. + Dicts also provide a get() method + which returns a default value if the key is not present, + so it does not fail in that case. + You can specity the default as a second argument to the + get call, otherwise it defaults to + None. + + + + + + Assigning to a key creates the association - either a new + key/value pair if the key was unknown, or replacing the + previous value if the key was already in the dictionary. + Initializing a dictionary uses curly braces ({}). + Here are some simple examples inspired by those in the official + &Python; tutorial, as you would see them if you typed these to + the interactive &Python; interpreter + (>>> is the interpreter prompt): @@ -503,7 +516,7 @@ None &Consenvs; are written to behave like a &Python; - dictionary, and the &cv-ENV; construction variable in + dictionary, and the &cv-ENV; &consvar; in a &consenv; is a &Python; dictionary. The os.environ value that &Python; uses to make available the external environment is also a @@ -527,7 +540,7 @@ None os.environ dictionary. That syntax means the environ attribute of the os module. - In Python, to access the contents of a module you must first + In &Python;, to access the contents of a module you must first import it - so you would include the import os statement to any &SConscript; file @@ -578,18 +591,18 @@ void main() { } A &consenv; is an object that has a number of associated &consvars;, each with a name and a value, just like a dictionary. - (A construction environment also has an attached + (A &consenv; also has an attached set of &Builder; methods, - about which we'll learn more later.) + which you'll learn more about later.) -
- Creating a &ConsEnv;: the &Environment; Function +
+ Creating a &ConsEnv;: the &Environment; Function - A &consenv; is created by the &Environment; method: + A &consenv; is created by the &f-link-Environment; function: @@ -599,13 +612,12 @@ env = Environment() - By default, &SCons; initializes every - new construction environment + &SCons; initializes every new &consenv; 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 + The &consvars; are initialized with values describing the C compiler, the Fortran compiler, @@ -617,7 +629,7 @@ env = Environment() - When you initialize a construction environment + When you initialize a &consenv; you can set the values of the environment's &consvars; to control how a program is built. @@ -637,18 +649,18 @@ int main() { } - The construction environment in this example + The &consenv; in this example is still initialized with the same default - construction variable values, + &consvar; values, except that the user has explicitly specified use of the GNU C compiler &gcc;, and that the (optimization level two) flag should be used when compiling the object file. - In other words, the explicit initializations of + In other words, the explicit initialization of &cv-link-CC; and &cv-link-CCFLAGS; - override the default values in the newly-created - construction environment. + overrides the default values in the newly-created + &consenv;. So a run from this example would look like: @@ -659,13 +671,13 @@ int main() { }
-
+
Fetching Values From a &ConsEnv; You can fetch individual values, known as - Construction Variables, + &ConsVars;, using the same syntax used for accessing individual named items in a &Python; dictionary: @@ -685,8 +697,9 @@ print("LATEX is: %s" % env.get('LATEX', None)) for building any targets, but because it's still a valid &SConstruct; it will be evaluated and the &Python; print calls will output the values - of &cv-link-CC; and &cv-link-LATEX; for us (remember using the - .get() method for fetching means + of &cv-link-CC; and &cv-link-LATEX; for us (remember + from the sidebar that using the + get() method for access means we get a default value back, rather than a failure, if the variable is not set): @@ -764,7 +777,7 @@ print(env.Dump())
-
+
Expanding Values From a &ConsEnv;: the &subst; Method @@ -802,7 +815,7 @@ print("CC is: %s" % env.subst('$CC')) env = Environment(CCFLAGS='-DFOO') -print("CCCOM is: %s" % env['CCCOM']) +print("CCCOM is:", env['CCCOM']) @@ -828,13 +841,13 @@ scons: `.' is up to date. env = Environment(CCFLAGS='-DFOO') -print("CCCOM is: %s" % env.subst('$CCCOM')) +print("CCCOM is:", env.subst('$CCCOM')) Will recursively expand all of - the construction variables prefixed + the &consvars; prefixed with $ (dollar signs), showing us the final output: @@ -857,20 +870,20 @@ scons: `.' is up to date.
-
- Handling Problems With Value Expansion +
+ Handling Problems With Value Expansion (advanced topic) - - If a problem occurs when expanding a construction variable, - by default it is expanded to '' - (an empty string), and will not cause &scons; to fail. + If a problem occurs when expanding a &consvar;, + by default it is expanded to an empty string, + that is, "replaced with nothing" - + &scons; will not fail for unknown variables. env = Environment() -print("value is: %s"%env.subst( '->$MISSING<-' )) +print("value is:", env.subst('->$MISSING<-')) @@ -879,26 +892,33 @@ print("value is: %s"%env.subst( '->$MISSING<-' )) - 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. + Sometimes this behavior leads to surprises while the build + configuration is being developed, + for example a typo in a variable name isn't reported, + and the variable expression is just dropped (empty string). + &SCons; provides a &f-link-AllowSubstExceptions; function + to allow the behavior to be tuned. + Internally, when a problem occurs with a variable expansion, + it generates an exception, + but before letting that exception kill the build, + &scons; checks a list of exceptions to ignore - by default + &NameError; and &IndexError;. + You can call &AllowSubstExceptions; to set the list of ignored + exceptions to anything you wish, including none at all. + That way, when a variable fails to expand that you thought + should be expanding to something, the build will stop and + you'll get an error message that should help diagnose the problem. + You give &AllowSubstExceptions; as many exception name arguments + as you wish it to ignore, + or call it with no arguments to have all expansion exceptions + propagate and stop &scons;. AllowSubstExceptions() env = Environment() -print("value is: %s"%env.subst( '->$MISSING<-' )) +print("value is:", env.subst('->$MISSING<-')) @@ -908,8 +928,8 @@ print("value is: %s"%env.subst( '->$MISSING<-' )) 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 + most usefully with the ${...} &consvar; + syntax. For example, this would allow zero-division to occur in a variable expansion in addition to the default exceptions allowed @@ -918,7 +938,7 @@ print("value is: %s"%env.subst( '->$MISSING<-' )) AllowSubstExceptions(IndexError, NameError, ZeroDivisionError) env = Environment() -print("value is: %s"%env.subst( '->${1 / 0}<-' )) +print("value is:", env.subst('->${1 / 0}<-')) @@ -933,7 +953,7 @@ print("value is: %s"%env.subst( '->${1 / 0}<-' ))
-
+
Controlling the Default &ConsEnv;: the &DefaultEnvironment; Function @@ -989,7 +1009,7 @@ DefaultEnvironment(CC='/usr/local/bin/gcc') 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: + the default &consenv; has been initialized: @@ -1016,7 +1036,7 @@ def_env['CC'] = '/usr/local/bin/gcc' that &SCons; performs by specifying some specific tool modules with which to - initialize the default construction environment: + initialize the default &consenv;: @@ -1168,29 +1188,29 @@ int main() { }
-
+
Making Copies of &ConsEnvs;: the &Clone; Method - Sometimes you want more than one construction environment + Sometimes you want more than one &consenv; 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, + variables when you create each &consenv;, you can use the &f-link-env-Clone; method - to create a copy of a construction environment. + to create a copy of a &consenv;. - Like the &f-link-Environment; call that creates a construction environment, + Like the &f-link-Environment; call that creates a &consenv;, the &Clone; method takes &consvar; assignments, - which will override the values in the copied construction environment. + which will override the values in the copied &consenv;. For example, suppose we want to use &gcc; to create three versions of a program, one optimized, one debug, and one with neither. - We could do this by creating a "base" construction environment + We could do this by creating a "base" &consenv; that sets &cv-link-CC; to &gcc;, and then creating two copies, one which sets &cv-link-CCFLAGS; for optimization @@ -1229,12 +1249,12 @@ int main() { }
-
+
Replacing Values: the &Replace; Method - You can replace existing construction variable values + You can replace existing &consvar; values using the &f-link-env-Replace; method: @@ -1252,10 +1272,10 @@ int main() { } - The replacing value + The new value (-DDEFINE2 in the above example) - completely replaces the value in the - construction environment: + replaces the value in the &consenv; - it's + like a &Python; assignment statement for &consvars;. @@ -1265,9 +1285,8 @@ int main() { } - You can safely call &Replace; - for construction variables that - don't exist in the construction environment: + You can safely call &Replace; for &consvars; that + don't exist in the &consenv; @@ -1281,9 +1300,7 @@ print("NEW_VARIABLE = %s" % env['NEW_VARIABLE']) - In this case, - the construction variable simply - gets added to the construction environment: + In this case, the &consvar; simply gets added to the &consenv;. @@ -1293,8 +1310,26 @@ print("NEW_VARIABLE = %s" % env['NEW_VARIABLE']) + If you have a lot of variables to replace, it may be more + convenient to put them in a dictionary and pass that to the + &Replace; method. That might look like: + + +newvalues = { + "F77PATH": ['foo', '$FOO/bar', blat], + "INCPREFIX": 'foo ', + "INCSUFFIX": 'bar', + "FOO": 'baz', +} +env.Replace(**newvalues) + + + + + + Because the variables - aren't expanded until the construction environment + aren't expanded until the &consenv; is actually used to build the targets, and because &SCons; function and method calls are order-independent, @@ -1356,14 +1391,14 @@ int main() { }
-
+
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 + that a &consvar; should be + set to a value only if the &consenv; does not already have that variable defined You can do this with the &f-link-env-SetDefault; method, which behaves similarly to the setdefault @@ -1379,7 +1414,7 @@ env.SetDefault(SPECIAL_FLAG='-extra-option') This is especially useful when writing your own Tool modules - to apply variables to construction environments. + to apply variables to &consenvs;. -
+
Propagating &PATH; From the External Environment @@ -1919,7 +1954,7 @@ env = Environment(ENV=os.environ.copy())
-
+
Adding to <varname>PATH</varname> Values in the Execution Environment @@ -1970,11 +2005,11 @@ env.AppendENVPath('LIB', '/usr/local/lib')
Using the toolpath for external Tools -
+
The default tool search path - Normally when using a tool from the construction environment, + Normally when using a tool from the &consenv;, several different search locations are checked by default. This includes the SCons/Tools/ directory that is part of the &scons; distribution @@ -1996,7 +2031,7 @@ SCons/Tool/SomeTool/__init__.py
-
+
Providing an external directory to toolpath @@ -2027,8 +2062,8 @@ SCons/Tool/SomeTool/__init__.py
-
- Nested Tools within a toolpath +
+ Nested Tools within a toolpath (advanced topic) @@ -2060,8 +2095,8 @@ SCons/Tool/SubDir1/SubDir2/SomeTool/__init__.py
-
- Using sys.path within the toolpath +
+ Using <literal>sys.path</literal> within the toolpath If we want to access tools external to &scons; which are findable @@ -2109,7 +2144,7 @@ C:\Python35\Lib\site-packages\someinstalledpackage\SomeTool\__init__.py
-
+
Using the &PyPackageDir; function to add to the toolpath diff --git a/doc/user/parseconfig.xml b/doc/user/parseconfig.xml index aac3cf3f6..ee52c92c7 100644 --- a/doc/user/parseconfig.xml +++ b/doc/user/parseconfig.xml @@ -55,7 +55,7 @@ This file is processed by the bin/SConsDoc.py module. - &SCons; &consvars; have a &f-link-ParseConfig; + &SCons; &consenvs; have a &f-link-ParseConfig; method that asks the host system to execute a command and then configures the appropriate &consvars; based on the output of that command. @@ -102,7 +102,7 @@ scons: `.' is up to date. In the example above, &SCons; has added the include directory to &cv-link-CPPPATH; - (Depending upon what other flags are emitted by the + (depending on what other flags are emitted by the pkg-config command, other variables may have been extended as well.) diff --git a/doc/user/preface.xml b/doc/user/preface.xml index bccad5091..8c0ba874f 100644 --- a/doc/user/preface.xml +++ b/doc/user/preface.xml @@ -102,7 +102,7 @@ This file is processed by the bin/SConsDoc.py module. --> -
+
&SCons; Principles @@ -193,7 +193,7 @@ This file is processed by the bin/SConsDoc.py module. --> -
+
How to Use this Guide @@ -223,19 +223,23 @@ This file is processed by the bin/SConsDoc.py module. - It is often useful to keep &SCons; man page open in a separate + If you are viewing an html version of this Guide, there are many + hyperlinks present that you can follow to get more details + if you want them, as the User Guide intentionally does not attempt + to provide every detail, to allow smoother study of the basics. + It may also be useful to keep the &SCons; man page open in a separate browser tab or window to refer to as a complement to this Guide, - as the User Guide does not attempt to provide every detail. - While this Guide's Appendices A-D do duplicate information that appears - in the man page (this is to allow intra-document links to - definitions of &consvars;, builders, tools and environment methods - to work), the rest of the man page is unique content. + which can avoid some jumping back and forth. + The four important manpage sections describiing the + of &consvars;, builders, tools and environment methods + are actually duplicated as appendices in the User Guide, + to avoid inter-document links.
-
+
A Caveat About This Guide's Completeness @@ -272,7 +276,7 @@ This file is processed by the bin/SConsDoc.py module.
-
+
Acknowledgements @@ -395,7 +399,7 @@ This file is processed by the bin/SConsDoc.py module. And last, thanks to Guido van Rossum - for his elegant scripting language, + for his elegant scripting language &Python;, which is the basis not only for the &SCons; implementation, but for the interface itself. @@ -403,7 +407,7 @@ This file is processed by the bin/SConsDoc.py module.
-
+
Contact