Make Export() work for local variables. (Anthony Roach)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 20 Apr 2003 03:30:39 +0000 (03:30 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 20 Apr 2003 03:30:39 +0000 (03:30 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@652 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Script/SConscript.py
test/SConscript.py

index 27dd9a7f6a0cb4054552bbe0dd6870fec21b71b0..18c5d809c0e9bc4f0b3454cf55c2ec1a3331ecc6 100644 (file)
@@ -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 ,
index 2f3ffbd0fc2e2aac1cc05d7a6c95031dbd8e477e..f6f274653055172f6cebd8d969c959e30f3aae58 100644 (file)
@@ -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.
index 1c9d2b2e7fe3f460466f6e99a858f7cdc373dc59..e77b879e1610564c54cb9f142630031c3029794c 100644 (file)
@@ -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
 
index df215a362dad1dc1cf2b59e85222e85917cb0ce5..a290d070bce297496ec5fbfc61265590cecc49d2 100644 (file)
@@ -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()