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 131542 267c636bd241616fb5e83b84feba2a5c1dd3b23e
parent 131541 fc11223a77451464f54852d1cc307d4dda15237e
child 131543 e26ae173a3e5db2ecede844dc2314ee07d2b3dd8
push idunknown
push userunknown
push dateunknown
reviewersted
bugs648407
milestone22.0a1
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