Bug 603370 part 1 - Add an option to expandlibs-exec to allow to reorder the objects list. r=ted
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 20 Jan 2012 09:50:44 +0100
changeset 84976 283408b8d8a3724ef0f5ee2bce08e21ce3acb924
parent 84975 0fce8e34930ffe177d1887c2ed779f86007a3b43
child 84977 f6cbf4661e213cde490fbfd618047d6c305bc438
push id21888
push userbmo@edmorley.co.uk
push dateSat, 21 Jan 2012 02:32:50 +0000
treeherdermozilla-central@099ec081e8aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs603370
milestone12.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 603370 part 1 - Add an option to expandlibs-exec to allow to reorder the objects list. r=ted
config/config.mk
config/expandlibs_exec.py
config/tests/unit-expandlibs.py
js/src/config/config.mk
js/src/config/expandlibs_exec.py
--- a/config/config.mk
+++ b/config/config.mk
@@ -773,18 +773,18 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist -- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -43,16 +43,20 @@ With the --extract argument (useful for 
 from static libraries (or use those listed in library descriptors directly).
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
+
+With the --reorder argument, followed by a file name, it will reorder the
+object files from the command line according to the order given in the file.
+Implies --extract.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
@@ -120,30 +124,51 @@ class ExpandArgsMore(ExpandArgs):
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
+    def reorder(self, order_list):
+        '''Given a list of file names without OBJ_SUFFIX, rearrange self
+        so that the object file names it contains are ordered according to
+        that list.
+        '''
+        objs = [o for o in self if o.endswith(conf.OBJ_SUFFIX)]
+        if not objs: return
+        idx = self.index(objs[0])
+        # Keep everything before the first object, then the ordered objects,
+        # then any other objects, then any non-objects after the first object
+        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
+        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
+                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
+                   [x for x in self[idx:] if not x.endswith(conf.OBJ_SUFFIX)]
+
+
 def main():
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
+    parser.add_option("--reorder", dest="reorder",
+        help="reorder the objects according to the given list", metavar="FILE")
 
     (options, args) = parser.parse_args()
 
     with ExpandArgsMore(args) as args:
-        if options.extract:
+        if options.extract or options.reorder:
             args.extract()
+        if options.reorder:
+            with open(options.reorder) as file:
+                args.reorder([l.strip() for l in file.readlines()])
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -262,10 +262,33 @@ class TestExpandArgsMore(TestExpandInit)
 
             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
 
+    def test_reorder(self):
+        '''Test object reordering'''
+        # We don't care about AR_EXTRACT testing, which is done in test_extract
+        config.AR_EXTRACT = ''
+
+        # ExpandArgsMore does the same as ExpandArgs
+        with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
+            self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) 
+
+            # Use an order containing object files from libraries
+            order_files = [self.libx_files[1], self.libx_files[0], self.liby_files[2], self.files[1]]
+            order = [os.path.splitext(os.path.basename(f))[0] for f in order_files]
+            args.reorder(order[:2] + ['unknown'] + order[2:])
+
+            # self.files has objects at #1, #2, #4
+            self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
+            self.assertRelEqual(args[3:7], order_files)
+            self.assertRelEqual(args[7:9], [self.files[2], self.files[4]])
+            self.assertRelEqual(args[9:11], self.liby_files[:2])
+            self.assertRelEqual(args[11:12], [self.libx_files[2]])
+            self.assertRelEqual(args[12:14], [self.files[3], self.files[5]])
+            self.assertRelEqual(args[14:], [self.liby_files[3]])
+
 if __name__ == '__main__':
     unittest.main(testRunner=MozTestRunner())
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -773,18 +773,18 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist -- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
--- a/js/src/config/expandlibs_exec.py
+++ b/js/src/config/expandlibs_exec.py
@@ -43,16 +43,20 @@ With the --extract argument (useful for 
 from static libraries (or use those listed in library descriptors directly).
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
+
+With the --reorder argument, followed by a file name, it will reorder the
+object files from the command line according to the order given in the file.
+Implies --extract.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
@@ -120,30 +124,51 @@ class ExpandArgsMore(ExpandArgs):
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
+    def reorder(self, order_list):
+        '''Given a list of file names without OBJ_SUFFIX, rearrange self
+        so that the object file names it contains are ordered according to
+        that list.
+        '''
+        objs = [o for o in self if o.endswith(conf.OBJ_SUFFIX)]
+        if not objs: return
+        idx = self.index(objs[0])
+        # Keep everything before the first object, then the ordered objects,
+        # then any other objects, then any non-objects after the first object
+        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
+        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
+                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
+                   [x for x in self[idx:] if not x.endswith(conf.OBJ_SUFFIX)]
+
+
 def main():
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
+    parser.add_option("--reorder", dest="reorder",
+        help="reorder the objects according to the given list", metavar="FILE")
 
     (options, args) = parser.parse_args()
 
     with ExpandArgsMore(args) as args:
-        if options.extract:
+        if options.extract or options.reorder:
             args.extract()
+        if options.reorder:
+            with open(options.reorder) as file:
+                args.reorder([l.strip() for l in file.readlines()])
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file: