Commits

Tom Tanner committed 58f4e12 Merge

Merged scons/scons into default

Comments (0)

Files changed (12)

 *.py[co]
 .sconsign*
 .svn
+.git
 *~
+*.xcodeproj

QMTest/TestCmd.py

     test.fail_test(condition)
     test.fail_test(condition, function)
     test.fail_test(condition, function, skip)
+    test.fail_test(condition, function, skip, message)
 
     test.no_result()
     test.no_result(condition)
     TestCmd.fail_test(condition)
     TestCmd.fail_test(condition, function)
     TestCmd.fail_test(condition, function, skip)
+    TestCmd.fail_test(condition, function, skip, message)
 
     TestCmd.no_result()
     TestCmd.no_result(condition)
         atfrom = "\tfrom"
     return string
 
-def fail_test(self = None, condition = 1, function = None, skip = 0):
+def fail_test(self = None, condition = 1, function = None, skip = 0, message=None):
     """Cause the test to fail.
 
     By default, the fail_test() method reports that the test FAILED
             sep = "\n\t"
 
     at = _caller(traceback.extract_stack(), skip)
-    sys.stderr.write("FAILED test" + of + desc + sep + at)
+    if message:
+        msg = "\t%s\n"%message
+    else:
+        msg = ""
+    sys.stderr.write("FAILED test" + of + desc + sep + at + msg)
 
     sys.exit(1)
 
 
     unified_diff = staticmethod(difflib.unified_diff)
 
-    def fail_test(self, condition = 1, function = None, skip = 0):
+    def fail_test(self, condition = 1, function = None, skip = 0, message = None):
         """Cause the test to fail.
         """
         if not condition:
         fail_test(self = self,
                   condition = condition,
                   function = function,
-                  skip = skip)
+                  skip = skip,
+                  message = message)
 
     def interpreter_set(self, interpreter):
         """Set the program to be used to interpret the program
             head, tail = os.path.split(head)
         result.append(head or tail)
         result.reverse()
-        
-        return result        
+
+        return result
 
     def dir_fixture(self, srcdir, dstdir=None):
         """Copies the contents of the specified folder srcdir from
         if dstdir:
             dstdir = self.canonicalize(dstdir)
         else:
-            dstdir = '.'            
+            dstdir = '.'
 
         if dstdir != '.' and not os.path.exists(dstdir):
             dstlist = self.parse_path(dstdir)
                         dstlist = dstlist[1:]
                     for idx in range(len(dstlist)):
                         self.subdir(dstlist[:idx+1])
-                    
+
             dpath = os.path.join(self.workdir, dstfile)
         shutil.copy(spath, dpath)
 
         if universal_newlines is None:
             universal_newlines = self.universal_newlines
 
-        # On Windows, if we make stdin a pipe when we plan to send 
+        # On Windows, if we make stdin a pipe when we plan to send
         # no input, and the test program exits before
         # Popen calls msvcrt.open_osfhandle, that call will fail.
         # So don't use a pipe for stdin if we don't need one.
                 program = self.program
             if not interpreter:
                 interpreter = self.interpreter
-        
+
         if chdir:
             oldcwd = os.getcwd()
             if not os.path.isabs(chdir):
 dh_builddeb = whereis('dh_builddeb')
 fakeroot = whereis('fakeroot')
 gzip = whereis('gzip')
-rpmbuild = whereis('rpmbuild') or whereis('rpm')
+rpmbuild = whereis('rpmbuild')
 hg = os.path.exists('.hg') and whereis('hg')
 svn = os.path.exists('.svn') and whereis('svn')
 unzip = whereis('unzip')
 
 RELEASE 2.3.1.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE
 
-  From XXX:
-    - first change here
+  From Gary Oberbrunner:
+    - Test harness: fail_test() can now print a message to help debugging.
+
+  From William Deegan:
+    - VS2012 & VS2010 Resolve initialization issues by adding path to reg.exe
+      in shell used to run batch files.
+    - MSVC Support fixed defaulting TARGET_ARCH to HOST_ARCH. It should be
+      None if not explicitly set.
+    - MSVC Fixed issue where if more than one Architectures compilers are
+      detected, it would take the last one found, and not the first.
+
+  From Philipp Kraus:
+    - Added optional ZIPROOT to Zip tool.
 
 RELEASE 2.3.0 - Mon, 02 Mar 2013 13:22:29 -0400
 

src/engine/SCons/Debug.py

             return res[4]
 
 # returns caller's stack
-def caller_stack(*backlist):
+def caller_stack():
     import traceback
-    if not backlist:
-        backlist = [0]
+    tb = traceback.extract_stack()
+    # strip itself and the caller from the output
+    tb = tb[:-2]
     result = []
-    for back in backlist:
-        tb = traceback.extract_stack(limit=3+back)
-        key = tb[0][:3]
+    for back in tb:
+        # (filename, line number, function name, text)
+        key = back[:3]
         result.append('%s:%d(%s)' % func_shorten(key))
     return result
 

src/engine/SCons/Environment.py

         self._dict['HOST_ARCH']    = self._dict.get('HOST_ARCH',None)
         
         # Now set defaults for TARGET_{OS|ARCH}
-        self._dict['TARGET_OS']      = self._dict.get('HOST_OS',None)
-        self._dict['TARGET_ARCH']    = self._dict.get('HOST_ARCH',None)
+        self._dict['TARGET_OS']      = self._dict.get('TARGET_OS',None)
+        self._dict['TARGET_ARCH']    = self._dict.get('TARGET_ARCH',None)
         
 
         # Apply the passed-in and customizable variables to the

src/engine/SCons/Tool/MSCommon/common.py

 
 def is_win64():
     """Return true if running on windows 64 bits.
-    
+
     Works whether python itself runs in 64 bits or 32 bits."""
     # Unfortunately, python does not provide a useful way to determine
     # if the underlying Windows OS is 32-bit or 64-bit.  Worse, whether
     # the Python itself is 32-bit or 64-bit affects what it returns,
-    # so nothing in sys.* or os.* help.  
+    # so nothing in sys.* or os.* help.
 
     # Apparently the best solution is to use env vars that Windows
     # sets.  If PROCESSOR_ARCHITECTURE is not x86, then the python
             if k in os.environ and (force or not k in normenv):
                 normenv[k] = os.environ[k].encode('mbcs')
 
+    # This shouldn't be necessary, since the default environment should include system32,
+    # but keep this here to be safe, since it's needed to find reg.exe which the MSVC
+    # bat scripts use.
+    sys32_dir = os.path.join(os.environ.get("SystemRoot", os.environ.get("windir",r"C:\Windows\system32")),"System32")
+
+    if sys32_dir not in normenv['PATH']:
+        normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_dir
+
+    debug("PATH: %s"%normenv['PATH'])
+
     return normenv
 
 def get_output(vcbat, args = None, env = None):
     """Parse the output of given bat file, with given args."""
-    
+
     if env is None:
         # Create a blank environment, for use in launching the tools
         env = SCons.Environment.Environment(tools=[])
     # settings in vs.py.
     vars = [
         'COMSPEC',
-        'VS110COMNTOOLS',
-        'VS100COMNTOOLS',
+# Still set, but setup script will discard these if registry has values.
+#         'VS110COMNTOOLS',
+#         'VS100COMNTOOLS',
         'VS90COMNTOOLS',
         'VS80COMNTOOLS',
         'VS71COMNTOOLS',
     # and won't work under Pythons not built with threading.
     stdout = popen.stdout.read()
     stderr = popen.stderr.read()
+
+    # Extra debug logic, uncomment if necessar
+#     debug('get_output():stdout:%s'%stdout)
+#     debug('get_output():stderr:%s'%stderr)
+
     if stderr:
         # TODO: find something better to do with stderr;
         # this at least prevents errors from getting swallowed.
                 p = p.encode('mbcs')
                 # XXX: For some reason, VC98 .bat file adds "" around the PATH
                 # values, and it screws up the environment later, so we strip
-                # it. 
+                # it.
                 p = p.strip('"')
                 dkeep[key].append(p)
 

src/engine/SCons/Tool/MSCommon/vc.py

     "itanium"   : "ia64",
     "x86"       : "x86",
     "x86_64"    : "amd64",
+    "x86_amd64" : "x86_amd64", # Cross compile to 64 bit from 32bits
 }
 
 # Given a (host, target) tuple, return the argument for the bat file. Both host
 _HOST_TARGET_ARCH_TO_BAT_ARCH = {
     ("x86", "x86"): "x86",
     ("x86", "amd64"): "x86_amd64",
+    ("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express
     ("amd64", "amd64"): "amd64",
     ("amd64", "x86"): "x86",
     ("x86", "ia64"): "x86_ia64"
     # target platform
     (host_platform, target_platform,req_target_platform) = get_host_target(env)
 
-    # If the user hasn't specifically requested a TARGET_ARCH, and
-    # The TARGET_ARCH is amd64 then also try 32 bits if there are no viable
-    # 64 bit tools installed
     try_target_archs = [target_platform]
-    if not req_target_platform and target_platform in ('amd64','x86_64'):
+    debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform))
+
+    # VS2012 has a "cross compile" environment to build 64 bit 
+    # with x86_amd64 as the argument to the batch setup script
+    if req_target_platform in ('amd64','x86_64'):
+        try_target_archs.append('x86_amd64')
+    elif not req_target_platform and target_platform in ['amd64','x86_64']:
+        # There may not be "native" amd64, but maybe "cross" x86_amd64 tools
+        try_target_archs.append('x86_amd64')
+        # If the user hasn't specifically requested a TARGET_ARCH, and
+        # The TARGET_ARCH is amd64 then also try 32 bits if there are no viable
+        # 64 bit tools installed
         try_target_archs.append('x86')
 
+    debug("msvs_find_valid_batch_script(): host_platform: %s try_target_archs:%s"%(host_platform, try_target_archs))
+
     d = None
     for tp in try_target_archs:
         # Set to current arch.
             except BatchFileExecutionError, e:
                 debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
                 vc_script=None
+                continue
         if not vc_script and sdk_script:
             debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
             try:
         elif not vc_script and not sdk_script:
             debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
             continue
+        
+        debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg))
+        break # We've found a working target_platform, so stop looking
     
     # If we cannot find a viable installed compiler, reset the TARGET_ARCH
     # To it's initial value

src/engine/SCons/Tool/zip.py

                     for fname in filenames:
                         path = os.path.join(dirpath, fname)
                         if os.path.isfile(path):
-                            zf.write(path)
+                            zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))))
             else:
-                zf.write(str(s))
+                zf.write(str(s), os.path.relpath(str(s), str(env.get('ZIPROOT', ''))))
         zf.close()
 else:
     zipcompression = 0
     env['ZIPCOM']     = zipAction
     env['ZIPCOMPRESSION'] =  zipcompression
     env['ZIPSUFFIX']  = '.zip'
+    env['ZIPROOT']    = SCons.Util.CLVar('')
 
 def exists(env):
     return internal_zip or env.Detect('zip')

src/engine/SCons/Tool/zip.xml

 The suffix used for zip file names.
 </summary>
 </cvar>
+
+<cvar name="ZIPROOT">
+<summary>
+An optional zip root directory (default empty).  The filenames stored
+in the zip file will be relative to this directory, if given.
+Otherwise the filenames are relative to the current directory of the
+command.
+For instance:
+<example>
+env = Environment()
+env.Zip('foo.zip', 'subdir1/subdir2/file1', ZIPROOT='subdir1')
+</example>
+will produce a zip file <literal>foo.zip</literal>
+containing a file with the name
+<literal>subdir2/file1</literal> rather than
+<literal>subdir1/subdir2/file1</literal>.
+</summary>
+</cvar>
 try:
     import zipfile
 except ImportError:
-    zip = test.where_is('zip')
-    if not zip:
-        x = "Python version has no 'ziplib' module nor 'zip' utility; skipping tests.\n"
-        test.skip_test(x)
+    x = "Python version has no 'ziplib' module; skipping tests.\n"
+    test.skip_test(x)
+
+def zipfile_contains(zipfilename, names):
+    """Returns True if zipfilename contains all the names, False otherwise."""
+    zf=zipfile.ZipFile(zipfilename, 'r')
+    if type(names)==type(''):
+        names=[names]
+    for name in names:
+        try:
+            info=zf.getinfo(name)
+        except KeyError, e:     # name not found
+            zf.close()
+            return False
+    return True
+
+def zipfile_files(fname):
+    """Returns all the filenames in zip file fname."""
+    zf = zipfile.ZipFile(fname, 'r')
+    return [x.filename for x in zf.infolist()]
 
 test.subdir('sub1')
 
-test.write('myzip.py', r"""\
-import os
-import os.path
-import sys
-def process(outfile, name):
-    if os.path.isdir(name):
-        ## TODO 2.4: the next three lines can be replaced by
-        #for entry in sorted(os.listdir(name)):
-        list = os.listdir(name)
-        list.sort()
-        for entry in list:
-            process(outfile, os.path.join(name, entry))
-    else:
-        outfile.write(open(name, 'rb').read())
-outfile = open(sys.argv[1], 'wb')
-for infile in sys.argv[2:]:
-    process(outfile, infile)
-outfile.close()
-sys.exit(0)
-""")
-
 test.write('SConstruct', """
-env = Environment(tools = ['zip'],
-                  ZIPCOM = r'%(_python_)s myzip.py $TARGET $SOURCES')
+env = Environment(tools = ['zip'])
 env.Zip(target = 'aaa.zip', source = ['file1', 'file2'])
 env.Zip(target = 'aaa.zip', source = 'file3')
 env.Zip(target = 'bbb', source = 'sub1')
 
 test.run(arguments = 'aaa.zip', stderr = None)
 
-test.fail_test(test.read('aaa.zip') != "file1\nfile2\nfile3\n")
+test.must_exist('aaa.zip')
+test.fail_test(not zipfile_contains('aaa.zip', ['file1', 'file2', 'file3']))
 
 test.run(arguments = 'bbb.zip', stderr = None)
 
-test.fail_test(test.read('bbb.zip') != "sub1/file5\nsub1/file6\nfile4\n")
+test.must_exist('bbb.zip')
+test.fail_test(not zipfile_contains('bbb.zip', ['sub1/file5', 'sub1/file6', 'file4']))
 
-try:
-    import zipfile
-    internal_zip = 1
-    zip = 1
+######
 
-    def files(fname):
-        zf = zipfile.ZipFile(fname, 'r')
-        return [x.filename for x in zf.infolist()]
+marker_out = test.workpath('marker.out').replace('\\', '\\\\')
 
-except ImportError:
-    internal_zip = 0
-    zip = test.detect('ZIP', 'zip')
-    unzip = test.where_is('unzip')
-
-    def files(fname, test=test, unzip=unzip):
-        test.run(program = unzip, arguments = "-l -qq %s" % fname)
-        lines = test.stdout().split("\n")[:-1]
-        def lastword(line):
-            return line.split()[-1]
-        return list(map(lastword, lines))
-
-if zip:
-
-    marker_out = test.workpath('marker.out').replace('\\', '\\\\')
-
-    test.write('SConstruct', """\
+test.write('SConstruct', """\
 def marker(target, source, env):
     open(r'%s', 'wb').write("marker\\n")
 f1 = Environment()
 f2.Zip(target = 'f2.zip', source = 'file15')
 f3.Zip(target = 'f3', source = 'file16')
 f3.Zip(target = 'f3', source = ['file17', 'file18'])
-try:
-    import zipfile
-    sources = ['file10', 'file11', 'file12', 'file13', 'file14', 'file15']
-    f1.Zip(target = 'f4.zip', source = sources)
-    f1.Zip(target = 'f4stored.zip', source = sources,
-           ZIPCOMPRESSION = zipfile.ZIP_STORED)
-    f1.Zip(target = 'f4deflated.zip', source = sources,
-           ZIPCOMPRESSION = zipfile.ZIP_DEFLATED)
-except ImportError:
-    pass
+
+import zipfile
+sources = ['file10', 'file11', 'file12', 'file13', 'file14', 'file15']
+f1.Zip(target = 'f4.zip', source = sources)
+f1.Zip(target = 'f4stored.zip', source = sources,
+       ZIPCOMPRESSION = zipfile.ZIP_STORED)
+f1.Zip(target = 'f4deflated.zip', source = sources,
+       ZIPCOMPRESSION = zipfile.ZIP_DEFLATED)
 """ % marker_out)
 
-    for f in ['file10', 'file11', 'file12',
-              'file13', 'file14', 'file15',
-              'file16', 'file17', 'file18']:
-        test.write(f, f + "\n")
+for f in ['file10', 'file11', 'file12',
+          'file13', 'file14', 'file15',
+          'file16', 'file17', 'file18']:
+    test.write(f, f + "\n")
 
-    test.run(arguments = 'f1.zip', stderr = None)
+test.run(arguments = 'f1.zip', stderr = None)
 
-    test.fail_test(os.path.exists(test.workpath('marker.out')))
+test.fail_test(os.path.exists(test.workpath('marker.out')))
 
-    test.fail_test(not os.path.exists(test.workpath('f1.zip')))
+test.fail_test(not os.path.exists(test.workpath('f1.zip')))
 
-    test.run(arguments = 'f2.zip', stderr = None)
+test.run(arguments = 'f2.zip', stderr = None)
 
-    test.fail_test(test.read('marker.out') != 'marker\n')
+test.fail_test(test.read('marker.out') != 'marker\n')
 
-    test.fail_test(not os.path.exists(test.workpath('f2.zip')))
+test.fail_test(not os.path.exists(test.workpath('f2.zip')))
 
-    test.run(arguments = '.', stderr = None)
+test.run(arguments = '.', stderr = None)
 
-    test.fail_test(os.path.exists(test.workpath('f3.zip')))
-    test.fail_test(not os.path.exists(test.workpath('f3.xyzzy')))
+test.fail_test(os.path.exists(test.workpath('f3.zip')))
+test.fail_test(not os.path.exists(test.workpath('f3.xyzzy')))
 
-    test.fail_test(files("f1.zip") != ['file10', 'file11', 'file12'])
+test.fail_test(zipfile_files("f1.zip") != ['file10', 'file11', 'file12'])
 
-    test.fail_test(files("f2.zip") != ['file13', 'file14', 'file15'])
+test.fail_test(zipfile_files("f2.zip") != ['file13', 'file14', 'file15'])
 
-    test.fail_test(files("f3.xyzzy") != ['file16', 'file17', 'file18'])
+test.fail_test(zipfile_files("f3.xyzzy") != ['file16', 'file17', 'file18'])
 
-    if internal_zip:
-        f4_size = os.stat('f4.zip')[stat.ST_SIZE]
-        f4stored_size = os.stat('f4stored.zip')[stat.ST_SIZE]
-        f4deflated_size = os.stat('f4deflated.zip')[stat.ST_SIZE]
+f4_size = os.stat('f4.zip')[stat.ST_SIZE]
+f4stored_size = os.stat('f4stored.zip')[stat.ST_SIZE]
+f4deflated_size = os.stat('f4deflated.zip')[stat.ST_SIZE]
 
-        test.fail_test(f4_size != f4deflated_size)
-        test.fail_test(f4stored_size == f4deflated_size)
+test.fail_test(f4_size != f4deflated_size)
+test.fail_test(f4stored_size == f4deflated_size)
 
 test.pass_test()
 

test/ZIP/ZIPROOT.py

+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import stat
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+import zipfile
+
+def zipfile_contains(zipfilename, names):
+    """Returns True if zipfilename contains all the names, False otherwise."""
+    zf=zipfile.ZipFile(zipfilename, 'r')
+    if type(names)==type(''):
+        names=[names]
+    for name in names:
+        try:
+            info=zf.getinfo(name)
+        except KeyError, e:     # name not found
+            zf.close()
+            return False
+    return True
+
+def zipfile_files(fname):
+    """Returns all the filenames in zip file fname."""
+    zf = zipfile.ZipFile(fname, 'r')
+    return [x.filename for x in zf.infolist()]
+
+test.subdir('sub1')
+test.subdir(['sub1', 'sub2'])
+
+test.write('SConstruct', """
+env = Environment(tools = ['zip'])
+env.Zip(target = 'aaa.zip', source = ['sub1/file1'], ZIPROOT='sub1')
+env.Zip(target = 'bbb.zip', source = ['sub1/file2', 'sub1/sub2/file2'], ZIPROOT='sub1')
+""" % locals())
+
+test.write(['sub1', 'file1'], "file1\n")
+test.write(['sub1', 'file2'], "file2a\n")
+test.write(['sub1', 'sub2', 'file2'], "file2b\n")
+
+test.run(arguments = 'aaa.zip', stderr = None)
+
+test.must_exist('aaa.zip')
+
+# TEST: Zip file should contain 'file1', not 'sub1/file1', because of ZIPROOT.
+zf=zipfile.ZipFile('aaa.zip', 'r')
+test.fail_test(zf.testzip() is not None)
+zf.close()
+
+files=zipfile_files('aaa.zip')
+test.fail_test(zipfile_files('aaa.zip') != ['file1'],
+               message='Zip file aaa.zip has wrong files: %s'%repr(files))
+
+###
+
+test.run(arguments = 'bbb.zip', stderr = None)
+
+test.must_exist('bbb.zip')
+
+# TEST: Zip file should contain 'sub2/file2', not 'sub1/sub2/file2', because of ZIPROOT.
+zf=zipfile.ZipFile('bbb.zip', 'r')
+test.fail_test(zf.testzip() is not None)
+zf.close()
+
+files=zipfile_files('bbb.zip')
+test.fail_test(zipfile_files('bbb.zip') != ['file2', 'sub2/file2'],
+               message='Zip file bbb.zip has wrong files: %s'%repr(files))
+
+
+test.pass_test()