From: stevenknight Date: Sun, 20 Apr 2003 03:30:39 +0000 (+0000) Subject: Make Export() work for local variables. (Anthony Roach) X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=296a3b942aba75540d1c0ea6e7a09c63ede7bf08;p=scons.git Make Export() work for local variables. (Anthony Roach) git-svn-id: http://scons.tigris.org/svn/scons/trunk@652 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 27dd9a7f..18c5d809 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -3318,9 +3318,12 @@ The exported variables are kept in a global collection, so subsequent calls to .BR Export () will over-write previous exports that have the same name. -Multiple variable names should be passed to +Multiple variable names can be passed to .BR Export () -as separate arguments. Examples: +as separate arguments or as a list. A dictionary can be used to map +variables to a different name when exported. Both local variables and +global variables can be exported. +Examples: .ES env = Environment() @@ -3328,8 +3331,14 @@ env = Environment() Export("env") package = 'my_name' -# Make env and package available for all SConscript files to Import(). +# Make env and package available for all SConscript files:. Export("env", "package") + +# Make env and package available for all SConscript files: +Export(["env", "package"]) + +# Make env available using the name debug:. +Export({"debug":env}) .EE .IP @@ -3405,14 +3414,17 @@ argument to Variables exported by .BR SConscript () have precedence. -Multiple variable names should be passed to +Multiple variable names can be passed to .BR Import () -as separate arguments. +as separate arguments or as a list. The variable "*" can be used +to import all variables. Examples: .ES Import("env") Import("env", "variable") +Import(["env", "variable"]) +Import("*") .EE .TP @@ -3554,7 +3566,8 @@ as a SConscript (configuration) file. The optional .I exports -argument provides a list of variable names to export to +argument provides a list of variable names or a dictionary of +named values to export to .IR script ". " These variables are locally exported only to the specified .IR script , diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 2f3ffbd0..f6f27465 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -69,6 +69,12 @@ RELEASE 0.14 - XXX - Add a standalone "Alias" function (separate from an Environment). + - Make Export() work for local variables. + + - Support passing a dictionary to Export(). + + - Support Import('*') to import everything that's been Export()ed. + From Greg Spencer: - Support the C preprocessor #import statement. diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 1c9d2b2e..e77b879e 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -75,24 +75,46 @@ def _scons_add_args(alist): a, b = string.split(arg, '=', 2) arguments[a] = b +def get_calling_namespaces(): + """Return the locals and globals for the function that called + into this module in the current callstack.""" + try: 1/0 + except: frame = sys.exc_info()[2].tb_frame + + while frame.f_globals.get("__name__") == __name__: frame = frame.f_back + + return frame.f_locals, frame.f_globals + + +def compute_exports(exports): + """Compute a dictionary of exports given one of the parameters + to the Export() function or the exports argument to SConscript().""" + exports = SCons.Util.argmunge(exports) + loc, glob = get_calling_namespaces() + + retval = {} + try: + for export in exports: + if SCons.Util.is_Dict(export): + retval.update(export) + else: + try: + retval[export] = loc[export] + except KeyError: + retval[export] = glob[export] + except KeyError, x: + raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x + + return retval + + class Frame: """A frame on the SConstruct/SConscript call stack""" def __init__(self, exports): self.globals = BuildDefaultGlobals() self.retval = None self.prev_dir = SCons.Node.FS.default_fs.getcwd() - self.exports = {} # exports from the calling SConscript - - try: - if SCons.Util.is_List(exports): - for export in exports: - self.exports[export] = stack[-1].globals[export] - else: - for export in string.split(exports): - self.exports[export] = stack[-1].globals[export] - except KeyError, x: - raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x - + self.exports = compute_exports(exports) # exports from the calling SConscript # the SConstruct/SConscript call stack: stack = [] @@ -339,21 +361,22 @@ def FindFile(file, dirs): return SCons.Node.FS.find_file(file, nodes) def Export(*vars): - try: - for var in vars: - for v in string.split(var): - global_exports[v] = stack[-1].globals[v] - except KeyError, x: - raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x + for var in vars: + global_exports.update(compute_exports(var)) def Import(*vars): try: for var in vars: - for v in string.split(var): - if stack[-1].exports.has_key(v): - stack[-1].globals[v] = stack[-1].exports[v] + var = SCons.Util.argmunge(var) + for v in var: + if 'v' == '*': + stack[-1].globals.update(global_exports) + stack[-1].globals.update(stack[-1].exports[v]) else: - stack[-1].globals[v] = global_exports[v] + if stack[-1].exports.has_key(v): + stack[-1].globals[v] = stack[-1].exports[v] + else: + stack[-1].globals[v] = global_exports[v] except KeyError,x: raise SCons.Errors.UserError, "Import of non-existant variable '%s'"%x diff --git a/test/SConscript.py b/test/SConscript.py index df215a36..a290d070 100644 --- a/test/SConscript.py +++ b/test/SConscript.py @@ -212,5 +212,135 @@ test.run(arguments = ".", stdout = test.wrap_stdout(read_str = 'SConstruct %s\nSConscript %s\n' % (wpath, wpath), build_str = 'scons: "." is up to date.\n')) +# Test exporting all global variables as a list of keys: +test.write("SConstruct", """ +x = 'x' +y = 'zoom' +Export(globals().keys()) +SConscript('SConscript') +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test exporting all global variables as a list of keys in SConscript call: +test.write("SConstruct", """ +x = 'x' +y = 'zoom' +SConscript('SConscript', globals().keys()) +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test exporting all global variables as a dictionary: +test.write("SConstruct", """ +x = 'x' +y = 'zoom' +Export(globals()) +SConscript('SConscript') +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test exporting all global variables as dictionary in SConscript call: +test.write("SConstruct", """ +x = 'x' +y = 'zoom' +SConscript('SConscript', globals()) +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test export of local variables: +test.write("SConstruct", """ +def f(): + x = 'x' + y = 'zoom' + Export('x', 'y') + +f() +SConscript('SConscript') +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test export of local variables in SConscript call: +test.write("SConstruct", """ +def f(): + x = 'x' + y = 'zoom' + SConscript('SConscript', ['x', 'y']) +f() +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test export of local variables as a dictionary: +test.write("SConstruct", """ +def f(): + x = 'x' + y = 'zoom' + Export(locals()) + +f() +SConscript('SConscript') +""") + +test.write("SConscript", """ +Import(['x', 'y']) +assert x == 'x' +assert y == 'zoom' +""") + +test.run(arguments = ".") + +# Test importing all variables: +test.write("SConstruct", """ +x = 'x' +y = 'zoom' +Export('x') +SConscript('SConscript', 'y') +""") + +test.write("SConscript", """ +Import('*') +assert x == 'x' +assert y == 'zoom' +""") test.pass_test()