Bug 648407 - Support expandlibs_exec.py --extract on windows. r=ted
authorMike Hommey <mh+mozilla@glandium.org>
Sun, 17 Mar 2013 07:44:57 +0100
changeset 136323 267c636bd241616fb5e83b84feba2a5c1dd3b23e
parent 136322 fc11223a77451464f54852d1cc307d4dda15237e
child 136324 e26ae173a3e5db2ecede844dc2314ee07d2b3dd8
push id336
push userakeybl@mozilla.com
push dateMon, 17 Jun 2013 22:53:19 +0000
treeherdermozilla-release@574a39cdf657 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs648407
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 648407 - Support expandlibs_exec.py --extract on windows. r=ted
config/expandlibs_exec.py
config/tests/unit-expandlibs.py
js/src/config/expandlibs_exec.py
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -65,28 +65,32 @@ class ExpandArgsMore(ExpandArgs):
         corresponding lib descriptor.
         '''
         ar_extract = conf.AR_EXTRACT.split()
         newlist = []
         for arg in args:
             if os.path.splitext(arg)[1] == conf.LIB_SUFFIX:
                 if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
                     newlist += self._extract(self._expand_desc(arg))
-                elif os.path.exists(arg) and len(ar_extract):
+                    continue
+                elif os.path.exists(arg) and (len(ar_extract) or conf.AR == 'lib'):
                     tmp = tempfile.mkdtemp(dir=os.curdir)
                     self.tmp.append(tmp)
-                    subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
+                    if conf.AR == 'lib':
+                        out = subprocess.check_output([conf.AR, '-NOLOGO', '-LIST', arg])
+                        for l in out.splitlines():
+                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % l, os.path.abspath(arg)], cwd=tmp)
+                    else:
+                        subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
                     objs = []
                     for root, dirs, files in os.walk(tmp):
                         objs += [relativize(os.path.join(root, f)) for f in files if isObject(f)]
-                    newlist += objs
-                else:
-                    newlist += [arg]
-            else:
-                newlist += [arg]
+                    newlist += sorted(objs)
+                    continue
+            newlist += [arg]
         return newlist
 
     def makelist(self):
         '''Replaces object file names with a temporary list file, using a
         list format depending on the EXPAND_LIBS_LIST_STYLE variable
         '''
         objs = [o for o in self if isObject(o)]
         if not len(objs): return
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -5,27 +5,29 @@ import os
 import imp
 from tempfile import mkdtemp
 from shutil import rmtree
 import mozunit
 
 from UserString import UserString
 # Create a controlled configuration for use by expandlibs
 config_win = {
+    'AR': 'lib',
     'AR_EXTRACT': '',
     'DLL_PREFIX': '',
     'LIB_PREFIX': '',
     'OBJ_SUFFIX': '.obj',
     'LIB_SUFFIX': '.lib',
     'DLL_SUFFIX': '.dll',
     'IMPORT_LIB_SUFFIX': '.lib',
     'LIBS_DESC_SUFFIX': '.desc',
     'EXPAND_LIBS_LIST_STYLE': 'list',
 }
 config_unix = {
+    'AR': 'ar',
     'AR_EXTRACT': 'ar -x',
     'DLL_PREFIX': 'lib',
     'LIB_PREFIX': 'lib',
     'OBJ_SUFFIX': '.o',
     'LIB_SUFFIX': '.a',
     'DLL_SUFFIX': '.so',
     'IMPORT_LIB_SUFFIX': '',
     'LIBS_DESC_SUFFIX': '.desc',
@@ -245,46 +247,76 @@ class TestExpandArgsMore(TestExpandInit)
         self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
 
     def test_extract(self):
         '''Test library extraction'''
         # Divert subprocess.call
         subprocess_call = subprocess.call
         extracted = {}
         def call(args, **kargs):
-            # The command called is always AR_EXTRACT
-            ar_extract = config.AR_EXTRACT.split()
-            self.assertRelEqual(args[:len(ar_extract)], ar_extract)
+            if config.AR == 'lib':
+                self.assertEqual(args[:2], [config.AR, '-NOLOGO'])
+                self.assertTrue(args[2].startswith('-EXTRACT:'))
+                extract = [args[2][len('-EXTRACT:'):]]
+                self.assertTrue(extract)
+                args = args[3:]
+            else:
+                # The command called is always AR_EXTRACT
+                ar_extract = config.AR_EXTRACT.split()
+                self.assertEqual(args[:len(ar_extract)], ar_extract)
+                args = args[len(ar_extract):]
             # Remaining argument is always one library
-            self.assertRelEqual([os.path.splitext(arg)[1] for arg in args[len(ar_extract):]], [config.LIB_SUFFIX])
-            # Simulate AR_EXTRACT extracting one object file for the library
-            lib = os.path.splitext(os.path.basename(args[len(ar_extract)]))[0]
-            extracted[lib] = os.path.join(kargs['cwd'], "{0}".format(Obj(lib)))
-            self.touch([extracted[lib]])
+            self.assertEqual(len(args), 1)
+            arg = args[0]
+            self.assertEqual(os.path.splitext(arg)[1], config.LIB_SUFFIX)
+            # Simulate file extraction
+            lib = os.path.splitext(os.path.basename(arg))[0]
+            if config.AR != 'lib':
+                extract = [lib, lib + '2']
+            extract = [os.path.join(kargs['cwd'], f) for f in extract]
+            if config.AR != 'lib':
+                extract = [Obj(f) for f in extract]
+            if not lib in extracted:
+                extracted[lib] = []
+            extracted[lib].extend(extract)
+            self.touch(extract)
         subprocess.call = call
 
+        def check_output(args, **kargs):
+            # The command called is always AR
+            ar = config.AR
+            self.assertEqual(args[0:3], [ar, '-NOLOGO', '-LIST'])
+            # Remaining argument is always one library
+            self.assertRelEqual([os.path.splitext(arg)[1] for arg in args[3:]],
+[config.LIB_SUFFIX])
+            # Simulate LIB -NOLOGO -LIST
+            lib = os.path.splitext(os.path.basename(args[3]))[0]
+            return '%s\n%s\n' % (Obj(lib), Obj(lib + '2'))
+        subprocess.check_output = check_output
+
         # ExpandArgsMore does the same as ExpandArgs
         self.touch([self.tmpfile('liby', Lib('y'))])
         with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
             self.assertRelEqual(args, ['foo', '-bar'] + self.files + [self.tmpfile('liby', Lib('y'))])
 
             # ExpandArgsMore also has an extra method extracting static libraries
             # when possible
             args.extract()
 
             files = self.files + self.liby_files + self.libx_files
-            if not len(config.AR_EXTRACT):
-                # If we don't have an AR_EXTRACT, extract() expands libraries with a
-                # descriptor when the corresponding library exists (which ExpandArgs
-                # alone doesn't)
-                self.assertRelEqual(args, ['foo', '-bar'] + files)
-            else:
-                # With AR_EXTRACT, it uses the descriptors when there are, and actually
-                # extracts the remaining libraries
-                self.assertRelEqual(args, ['foo', '-bar'] + [extracted[os.path.splitext(os.path.basename(f))[0]] if f.endswith(config.LIB_SUFFIX) else f for f in files])
+            # With AR_EXTRACT, it uses the descriptors when there are, and
+            # actually
+            # extracts the remaining libraries
+            extracted_args = []
+            for f in files:
+                if f.endswith(config.LIB_SUFFIX):
+                    extracted_args.extend(sorted(extracted[os.path.splitext(os.path.basename(f))[0]]))
+                else:
+                    extracted_args.append(f)
+            self.assertRelEqual(args, ['foo', '-bar'] + extracted_args)
 
             tmp = args.tmp
         # Check that all temporary files are properly removed
         self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
 
         # Restore subprocess.call
         subprocess.call = subprocess_call
 
--- a/js/src/config/expandlibs_exec.py
+++ b/js/src/config/expandlibs_exec.py
@@ -65,28 +65,32 @@ class ExpandArgsMore(ExpandArgs):
         corresponding lib descriptor.
         '''
         ar_extract = conf.AR_EXTRACT.split()
         newlist = []
         for arg in args:
             if os.path.splitext(arg)[1] == conf.LIB_SUFFIX:
                 if os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
                     newlist += self._extract(self._expand_desc(arg))
-                elif os.path.exists(arg) and len(ar_extract):
+                    continue
+                elif os.path.exists(arg) and (len(ar_extract) or conf.AR == 'lib'):
                     tmp = tempfile.mkdtemp(dir=os.curdir)
                     self.tmp.append(tmp)
-                    subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
+                    if conf.AR == 'lib':
+                        out = subprocess.check_output([conf.AR, '-NOLOGO', '-LIST', arg])
+                        for l in out.splitlines():
+                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % l, os.path.abspath(arg)], cwd=tmp)
+                    else:
+                        subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
                     objs = []
                     for root, dirs, files in os.walk(tmp):
                         objs += [relativize(os.path.join(root, f)) for f in files if isObject(f)]
-                    newlist += objs
-                else:
-                    newlist += [arg]
-            else:
-                newlist += [arg]
+                    newlist += sorted(objs)
+                    continue
+            newlist += [arg]
         return newlist
 
     def makelist(self):
         '''Replaces object file names with a temporary list file, using a
         list format depending on the EXPAND_LIBS_LIST_STYLE variable
         '''
         objs = [o for o in self if isObject(o)]
         if not len(objs): return