Browse Source

use frg's patches for bug 1429875

Bill Gianopoulos 3 years ago
parent
commit
736844699e

+ 82 - 0
bug1240930-253/mozilla/1429875-1-61a1.patch

@@ -0,0 +1,82 @@
+# HG changeset patch
+# User Chris Manchester <cmanchester@mozilla.com>
+# Date 1521588665 25200
+# Node ID 36f505b0e0da72cbcd109ec7eeb2fb449f6da927
+# Parent  eef5caff081b8b774e7f31607a652aa56c7b8d7c
+Bug 1429875 - Add a "name" property to Library and Program objects that corresponds to the output basename. r=glandium
+
+MozReview-Commit-ID: J4gt1fGUzOa
+
+diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py
+--- a/python/mozbuild/mozbuild/frontend/data.py
++++ b/python/mozbuild/mozbuild/frontend/data.py
+@@ -424,16 +424,19 @@ class BaseProgram(Linkable):
+         if self.installed:
+             return ObjDirPath(self._context, '!/' + mozpath.join(self.install_target, self.program))
+         else:
+             return ObjDirPath(self._context, '!' + self.program)
+ 
+     def __repr__(self):
+         return '<%s: %s/%s>' % (type(self).__name__, self.relobjdir, self.program)
+ 
++    @property
++    def name(self):
++        return self.program
+ 
+ class Program(BaseProgram):
+     """Context derived container object for PROGRAM"""
+     SUFFIX_VAR = 'BIN_SUFFIX'
+     KIND = 'target'
+ 
+ 
+ class HostProgram(HostMixin, BaseProgram):
+@@ -531,16 +534,20 @@ class BaseLibrary(Linkable):
+             )
+             self.import_name = self.lib_name
+ 
+         self.refs = []
+ 
+     def __repr__(self):
+         return '<%s: %s/%s>' % (type(self).__name__, self.relobjdir, self.lib_name)
+ 
++    @property
++    def name(self):
++        return self.lib_name
++
+ 
+ class Library(BaseLibrary):
+     """Context derived container object for a library"""
+     KIND = 'target'
+     __slots__ = (
+     )
+ 
+     def __init__(self, context, basename, real_name=None):
+diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
++++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+@@ -1116,19 +1116,25 @@ class TestEmitterBasic(unittest.TestCase
+ 
+     def test_linkables_cxx_link(self):
+         """Test that linkables transitively set cxx_link properly."""
+         reader = self.reader('test-linkables-cxx-link')
+         got_results = 0
+         for obj in self.read_topsrcdir(reader):
+             if isinstance(obj, SharedLibrary):
+                 if obj.basename == 'cxx_shared':
++                    self.assertEquals(obj.name, '%scxx_shared%s' %
++                                      (reader.config.dll_prefix,
++                                       reader.config.dll_suffix))
+                     self.assertTrue(obj.cxx_link)
+                     got_results += 1
+                 elif obj.basename == 'just_c_shared':
++                    self.assertEquals(obj.name, '%sjust_c_shared%s' %
++                                      (reader.config.dll_prefix,
++                                       reader.config.dll_suffix))
+                     self.assertFalse(obj.cxx_link)
+                     got_results += 1
+         self.assertEqual(got_results, 2)
+ 
+     def test_generated_sources(self):
+         """Test that GENERATED_SOURCES works properly."""
+         reader = self.reader('generated-sources')
+         objs = self.read_topsrcdir(reader)

+ 54 - 0
bug1240930-253/mozilla/1429875-2-61a1.patch

@@ -0,0 +1,54 @@
+# HG changeset patch
+# User Chris Manchester <cmanchester@mozilla.com>
+# Date 1521588665 25200
+# Node ID 4cdc60a9f06ee184973d888f7013a4ab30fe4e99
+# Parent  7f14895e2fca740e8d135619564e562014844c83
+Bug 1429875 - Do not take DIST_INSTALL into account when deciding to build static libraries. r=glandium
+
+Now that we're no longer shipping the SDK we no longer need real libraries for
+the libraries that were created by this rule.
+
+MozReview-Commit-ID: ALATVGBayHu
+
+diff --git a/config/rules.mk b/config/rules.mk
+--- a/config/rules.mk
++++ b/config/rules.mk
+@@ -95,38 +95,23 @@ endif # ENABLE_TESTS
+ # Library rules
+ #
+ # If FORCE_STATIC_LIB is set, build a static library.
+ # Otherwise, build a shared library.
+ #
+ 
+ ifndef LIBRARY
+ ifdef REAL_LIBRARY
+-# Don't build actual static library if a shared library is also built
+-ifdef FORCE_SHARED_LIB
+-# ... except when we really want one
+ ifdef NO_EXPAND_LIBS
+ LIBRARY			:= $(REAL_LIBRARY)
+ else
+ LIBRARY			:= $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
+ endif
+-else
+-# Only build actual library if it is installed in DIST/lib
+-ifeq (,$(DIST_INSTALL)$(NO_EXPAND_LIBS))
+-LIBRARY			:= $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
+-else
+-ifdef NO_EXPAND_LIBS
+-LIBRARY			:= $(REAL_LIBRARY)
+-else
+-LIBRARY			:= $(REAL_LIBRARY) $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
+ endif
+ endif
+-endif
+-endif # REAL_LIBRARY
+-endif # LIBRARY
+ 
+ ifndef HOST_LIBRARY
+ ifdef HOST_LIBRARY_NAME
+ HOST_LIBRARY		:= $(LIB_PREFIX)$(HOST_LIBRARY_NAME).$(LIB_SUFFIX)
+ endif
+ endif
+ 
+ ifdef FORCE_SHARED_LIB

+ 287 - 0
bug1240930-253/mozilla/1429875-3-61a1.patch

@@ -0,0 +1,287 @@
+# HG changeset patch
+# User Chris Manchester <cmanchester@mozilla.com>
+# Date 1521588665 25200
+# Node ID decbe4a4cdc77b610f7b9bae8622dbfcd00f2694
+# Parent  989c246b8606907c1e4218db7c254820c8d13fc7
+Bug 1429875 - Add a unit test for linkage variables in the make backend. r=glandium
+
+MozReview-Commit-ID: HREobMhWTwg
+
+diff --git a/python/mozbuild/mozbuild/test/backend/common.py b/python/mozbuild/mozbuild/test/backend/common.py
+--- a/python/mozbuild/mozbuild/test/backend/common.py
++++ b/python/mozbuild/mozbuild/test/backend/common.py
+@@ -191,16 +191,27 @@ CONFIGS = defaultdict(lambda: {
+     'program-paths': {
+         'defines': {},
+         'non_global_defines': [],
+         'substs': {
+             'COMPILE_ENVIRONMENT': '1',
+             'BIN_SUFFIX': '.prog',
+         },
+     },
++    'linkage': {
++        'defines': {},
++        'non_global_defines': [],
++        'substs': {
++            'COMPILE_ENVIRONMENT': '1',
++            'LIB_SUFFIX': 'a',
++            'BIN_SUFFIX': '.exe',
++            'DLL_SUFFIX': '.so',
++            'OBJ_SUFFIX': 'o',
++        },
++    },
+ })
+ 
+ 
+ class BackendTester(unittest.TestCase):
+     def setUp(self):
+         self._old_env = dict(os.environ)
+         os.environ.pop('MOZ_OBJDIR', None)
+ 
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/moz.build
+@@ -0,0 +1,11 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++include('templates.mozbuild')
++
++DIRS += [
++     'real',
++     'shared',
++     'prog',
++     'static',
++]
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/prog/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/prog/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/prog/moz.build
+@@ -0,0 +1,11 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++DIRS += ['qux']
++
++Program('MyProgram')
++
++USE_LIBS += [
++    'bar',
++    'baz',
++]
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/prog/qux/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/prog/qux/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/prog/qux/moz.build
+@@ -0,0 +1,6 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++SOURCES += ['qux1.c']
++
++SharedLibrary('qux')
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/prog/qux/qux1.c b/python/mozbuild/mozbuild/test/backend/data/linkage/prog/qux/qux1.c
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/foo1.c b/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/foo1.c
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/foo2.c b/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/foo2.c
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/real/foo/moz.build
+@@ -0,0 +1,9 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++SOURCES += [
++    'foo1.c',
++    'foo2.c'
++]
++
++FINAL_LIBRARY = 'foo'
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/real/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/real/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/real/moz.build
+@@ -0,0 +1,14 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++DIRS += [
++    'foo',
++]
++
++NO_EXPAND_LIBS = True
++
++OS_LIBS += ['-lbaz']
++
++USE_LIBS += ['static:baz']
++
++Library('foo')
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/shared/baz/baz1.c b/python/mozbuild/mozbuild/test/backend/data/linkage/shared/baz/baz1.c
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/shared/baz/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/shared/baz/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/shared/baz/moz.build
+@@ -0,0 +1,6 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++SOURCES += ['baz1.c']
++
++FINAL_LIBRARY = 'baz'
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/shared/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/shared/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/shared/moz.build
+@@ -0,0 +1,14 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++DIRS += [
++    'baz',
++]
++
++STATIC_LIBRARY_NAME = 'baz_s'
++FORCE_STATIC_LIB = True
++
++OS_LIBS += ['-lfoo']
++USE_LIBS += ['qux']
++
++SharedLibrary('baz')
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar1.cc b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar1.cc
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build
+@@ -0,0 +1,8 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++SOURCES += [
++    'bar1.cc',
++]
++
++FINAL_LIBRARY = 'bar'
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/static/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/static/moz.build
+@@ -0,0 +1,12 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++DIRS += [
++    'bar',
++]
++
++USE_LIBS += ['foo']
++
++OS_LIBS += ['-lbar']
++
++Library('bar')
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/templates.mozbuild b/python/mozbuild/mozbuild/test/backend/data/linkage/templates.mozbuild
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/templates.mozbuild
+@@ -0,0 +1,23 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++@template
++def Library(name):
++    LIBRARY_NAME = name
++
++@template
++def SharedLibrary(name):
++    FORCE_SHARED_LIB = True
++    LIBRARY_NAME = name
++
++@template
++def Binary():
++    # Add -lfoo for testing purposes.
++    OS_LIBS += ['foo']
++
++
++@template
++def Program(name):
++    PROGRAM = name
++
++    Binary()
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
++++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+@@ -982,16 +982,61 @@ class TestRecursiveMakeBackend(BackendTe
+ 
+         with open(os.path.join(env.topobjdir, 'cxx-library', 'backend.mk'), 'rb') as fh:
+             lines = fh.readlines()
+             lines = [line.rstrip() for line in lines]
+ 
+             for line in lines:
+                 self.assertNotIn('LIB_IS_C_ONLY', line)
+ 
++    def test_linkage(self):
++        env = self._consume('linkage', RecursiveMakeBackend)
++        expected_linkage = {
++            'prog': {
++                'SHARED_LIBS': ['$(DEPTH)/shared/baz', '$(DEPTH)/prog/qux/qux'],
++                'STATIC_LIBS': ['$(DEPTH)/static/bar%s' % env.lib_suffix],
++                'OS_LIBS': ['-lfoo', '-lbaz', '-lbar'],
++            },
++            'shared': {
++                'OS_LIBS': ['-lfoo'],
++                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux'],
++                'STATIC_LIBS': ['$(DEPTH)/shared/baz/shared_baz%s' %
++                                env.lib_suffix],
++            },
++            'static': {
++                'STATIC_LIBS': [
++                    '$(DEPTH)/static/bar/static_bar.a',
++                    '$(DEPTH)/real/foo.a',
++                ],
++                'OS_LIBS': ['-lbar'],
++                'SHARED_LIBS': [],
++            },
++            'real': {
++                'STATIC_LIBS': [
++                    '$(DEPTH)/shared/baz_s%s' % env.lib_suffix,
++                    '$(DEPTH)/real/foo/real_foo%s' % env.lib_suffix,
++                ],
++                'SHARED_LIBS': [],
++                'OS_LIBS': ['-lbaz'],
++            }
++        }
++        actual_linkage = {}
++        for name in expected_linkage.keys():
++            with open(os.path.join(env.topobjdir, name, 'backend.mk'), 'rb') as fh:
++                actual_linkage[name] = [line.rstrip() for line in fh.readlines()]
++        for name in expected_linkage:
++            for var in expected_linkage[name]:
++                for val in expected_linkage[name][var]:
++                    line = '%s += %s' % (var, val)
++                    self.assertIn(line,
++                                  actual_linkage[name])
++                    actual_linkage[name].remove(line)
++                for line in actual_linkage[name]:
++                    self.assertNotIn('%s +=' % var, line)
++
+     def test_jar_manifests(self):
+         env = self._consume('jar-manifests', RecursiveMakeBackend)
+ 
+         with open(os.path.join(env.topobjdir, 'backend.mk'), 'rb') as fh:
+             lines = fh.readlines()
+ 
+         lines = [line.rstrip() for line in lines]
+ 

+ 1777 - 0
bug1240930-253/mozilla/1429875-4-61a1.patch

@@ -0,0 +1,1777 @@
+# HG changeset patch
+# User Chris Manchester <cmanchester@mozilla.com>
+# Date 1521588665 25200
+# Node ID 7547d66e0f518d20f61b492eac027d5a34ac6fb4
+# Parent  59d0e2f57d34fdd5e1b6bf98f8cb0591811eb4aa
+Bug 1429875 - Remove expandlibs and instead generate list files in the mozbuild backend. r=glandium
+
+MozReview-Commit-ID: 5eLwnh1HHGj
+
+diff --git a/build/clang-plugin/Makefile.in b/build/clang-plugin/Makefile.in
+--- a/build/clang-plugin/Makefile.in
++++ b/build/clang-plugin/Makefile.in
+@@ -8,20 +8,16 @@ include $(topsrcdir)/config/config.mk
+ # variable to limit ourselves to what we need to build the clang plugin.
+ ifneq ($(HOST_OS_ARCH),WINNT)
+ DSO_LDOPTS := -shared
+ endif
+ 
+ ifeq ($(HOST_OS_ARCH)_$(OS_ARCH),Linux_Darwin)
+ # Use the host compiler instead of the target compiler.
+ CXX := $(HOST_CXX)
+-# expandlibs doesn't know the distinction between host and target toolchains,
+-# and on cross linux/darwin builds, the options to give to the linker for file
+-# lists differ between both, so don't use file lists.
+-EXPAND_MKSHLIB_ARGS :=
+ endif
+ 
+ # Use the default OS X deployment target to enable using the libc++ headers
+ # correctly.  Note that the binary produced here is a host tool and doesn't need
+ # to be distributed.
+ MACOSX_DEPLOYMENT_TARGET :=
+ 
+ # Temporarily relax the requirements for libstdc++ symbol versions on static
+diff --git a/config/config.mk b/config/config.mk
+--- a/config/config.mk
++++ b/config/config.mk
+@@ -432,28 +432,16 @@ JAVAC_FLAGS += -source 1.4
+ 
+ ifdef MOZ_DEBUG
+ JAVAC_FLAGS += -g
+ endif
+ 
+ # MDDEPDIR is the subdirectory where dependency files are stored
+ MDDEPDIR := .deps
+ 
+-EXPAND_LIBS_EXEC = $(PYTHON) $(MOZILLA_DIR)/config/expandlibs_exec.py
+-EXPAND_LIBS_GEN = $(PYTHON) $(MOZILLA_DIR)/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_LINK = $(EXPAND_LIBS_EXEC) --uselist -- $(LINKER)
+-EXPAND_MKSHLIB_ARGS = --uselist
+-ifdef SYMBOL_ORDER
+-EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
+-endif
+-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
+-
+ # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
+ # this file
+ OBJ_SUFFIX := $(_OBJ_SUFFIX)
+ 
+ # PGO builds with GCC build objects with instrumentation in a first pass,
+ # then objects optimized, without instrumentation, in a second pass. If
+ # we overwrite the objects from the first pass with those from the second,
+ # we end up not getting instrumentation data for better optimization on
+diff --git a/config/expandlibs.py b/config/expandlibs.py
+deleted file mode 100644
+--- a/config/expandlibs.py
++++ /dev/null
+@@ -1,143 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this
+-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-'''Expandlibs is a system that allows to replace some libraries with a
+-descriptor file containing some linking information about them.
+-
+-The descriptor file format is as follows:
+----8<-----
+-OBJS = a.o b.o ...
+-LIBS = libfoo.a libbar.a ...
+---->8-----
+-
+-(In the example above, OBJ_SUFFIX is o and LIB_SUFFIX is a).
+-
+-Expandlibs also canonicalizes how to pass libraries to the linker, such
+-that only the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} form needs to be used:
+-given a list of files, expandlibs will replace items with the form
+-${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} following these rules:
+-
+-- If a ${DLL_PREFIX}${ROOT}.${DLL_SUFFIX} or
+-  ${DLL_PREFIX}${ROOT}.${IMPORT_LIB_SUFFIX} file exists, use that instead
+-- If the ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} file exists, use it
+-- If a ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX}.${LIB_DESC_SUFFIX} file exists,
+-  replace ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} with the OBJS and LIBS the
+-  descriptor contains. And for each of these LIBS, also apply the same
+-  rules.
+-'''
+-from __future__ import with_statement
+-import sys, os, errno
+-import expandlibs_config as conf
+-
+-def ensureParentDir(file):
+-    '''Ensures the directory parent to the given file exists'''
+-    dir = os.path.dirname(file)
+-    if dir and not os.path.exists(dir):
+-        try:
+-            os.makedirs(dir)
+-        except OSError, error:
+-            if error.errno != errno.EEXIST:
+-                raise
+-
+-def relativize(path):
+-    '''Returns a path relative to the current working directory, if it is
+-    shorter than the given path'''
+-    def splitpath(path):
+-        dir, file = os.path.split(path)
+-        if os.path.splitdrive(dir)[1] == os.sep:
+-            return [file]
+-        return splitpath(dir) + [file]
+-
+-    if not os.path.exists(path):
+-        return path
+-    curdir = splitpath(os.path.abspath(os.curdir))
+-    abspath = splitpath(os.path.abspath(path))
+-    while curdir and abspath and curdir[0] == abspath[0]:
+-        del curdir[0]
+-        del abspath[0]
+-    if not curdir and not abspath:
+-        return '.'
+-    relpath = os.path.join(*[os.pardir for i in curdir] + abspath)
+-    if len(path) > len(relpath):
+-        return relpath
+-    return path
+-
+-def isObject(path):
+-    '''Returns whether the given path points to an object file, that is,
+-    ends with OBJ_SUFFIX or .i_o'''
+-    return os.path.splitext(path)[1] in [conf.OBJ_SUFFIX, '.i_o']
+-
+-def isDynamicLib(path):
+-    '''Returns whether the given path points to a dynamic library, that is,
+-    ends with DLL_SUFFIX.'''
+-    # On mac, the xul library is named XUL, instead of libxul.dylib. Assume any
+-    # file by that name is a dynamic library.
+-    return os.path.splitext(path)[1] == conf.DLL_SUFFIX or os.path.basename(path) == 'XUL'
+-
+-class LibDescriptor(dict):
+-    KEYS = ['OBJS', 'LIBS']
+-
+-    def __init__(self, content=None):
+-        '''Creates an instance of a lib descriptor, initialized with contents
+-        from a list of strings when given. This is intended for use with
+-        file.readlines()'''
+-        if isinstance(content, list) and all([isinstance(item, str) for item in content]):
+-            pass
+-        elif content is not None:
+-            raise TypeError("LibDescriptor() arg 1 must be None or a list of strings")
+-        super(LibDescriptor, self).__init__()
+-        for key in self.KEYS:
+-            self[key] = []
+-        if not content:
+-            return
+-        for key, value in [(s.strip() for s in item.split('=', 2)) for item in content if item.find('=') >= 0]:
+-            if key in self.KEYS:
+-                self[key] = value.split()
+-
+-    def __str__(self):
+-        '''Serializes the lib descriptor'''
+-        return '\n'.join('%s = %s' % (k, ' '.join(self[k])) for k in self.KEYS if len(self[k]))
+-
+-class ExpandArgs(list):
+-    def __init__(self, args):
+-        '''Creates a clone of the |args| list and performs file expansion on
+-        each item it contains'''
+-        super(ExpandArgs, self).__init__()
+-        self._descs = set()
+-        for arg in args:
+-            self += self._expand(arg)
+-
+-    def _expand(self, arg):
+-        '''Internal function doing the actual work'''
+-        (root, ext) = os.path.splitext(arg)
+-        if ext != conf.LIB_SUFFIX or not os.path.basename(root).startswith(conf.LIB_PREFIX):
+-            return [relativize(arg)]
+-        if conf.LIB_PREFIX:
+-            dll = root.replace(conf.LIB_PREFIX, conf.DLL_PREFIX, 1) + conf.DLL_SUFFIX
+-        else:
+-            dll = root + conf.DLL_SUFFIX
+-        if os.path.exists(dll):
+-            if conf.IMPORT_LIB_SUFFIX:
+-                return [relativize(root + conf.IMPORT_LIB_SUFFIX)]
+-            else:
+-                return [relativize(dll)]
+-        return self._expand_desc(arg)
+-
+-    def _expand_desc(self, arg):
+-        '''Internal function taking care of lib descriptor expansion only'''
+-        desc = os.path.abspath(arg + conf.LIBS_DESC_SUFFIX)
+-        if os.path.exists(desc):
+-            if desc in self._descs:
+-                return []
+-            self._descs.add(desc)
+-            with open(desc, 'r') as f:
+-                desc = LibDescriptor(f.readlines())
+-            objs = [relativize(o) for o in desc['OBJS']]
+-            for lib in desc['LIBS']:
+-                objs += self._expand(lib)
+-            return objs
+-        return [relativize(arg)]
+-
+-if __name__ == '__main__':
+-    print " ".join(ExpandArgs(sys.argv[1:]))
+diff --git a/config/expandlibs_config.py b/config/expandlibs_config.py
+deleted file mode 100644
+--- a/config/expandlibs_config.py
++++ /dev/null
+@@ -1,29 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this
+-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-from buildconfig import substs
+-
+-def normalize_suffix(suffix):
+-    '''Returns a normalized suffix, i.e. ensures it starts with a dot and
+-    doesn't starts or ends with whitespace characters'''
+-    value = suffix.strip()
+-    if len(value) and not value.startswith('.'):
+-        value = '.' + value
+-    return value
+-
+-# Variables from the build system
+-AR = substs['AR']
+-AR_EXTRACT = substs['AR_EXTRACT'].replace('$(AR)', AR)
+-DLL_PREFIX = substs['DLL_PREFIX']
+-LIB_PREFIX = substs['LIB_PREFIX']
+-RUST_LIB_PREFIX = substs['RUST_LIB_PREFIX']
+-OBJ_SUFFIX = normalize_suffix(substs['OBJ_SUFFIX'])
+-LIB_SUFFIX = normalize_suffix(substs['LIB_SUFFIX'])
+-RUST_LIB_SUFFIX = normalize_suffix(substs['RUST_LIB_SUFFIX'])
+-DLL_SUFFIX = normalize_suffix(substs['DLL_SUFFIX'])
+-IMPORT_LIB_SUFFIX = normalize_suffix(substs['IMPORT_LIB_SUFFIX'])
+-LIBS_DESC_SUFFIX = normalize_suffix(substs['LIBS_DESC_SUFFIX'])
+-EXPAND_LIBS_LIST_STYLE = substs['EXPAND_LIBS_LIST_STYLE']
+-EXPAND_LIBS_ORDER_STYLE = substs['EXPAND_LIBS_ORDER_STYLE']
+-LD_PRINT_ICF_SECTIONS = substs['LD_PRINT_ICF_SECTIONS']
+diff --git a/config/expandlibs_exec.py b/config/expandlibs_exec.py
+deleted file mode 100644
+--- a/config/expandlibs_exec.py
++++ /dev/null
+@@ -1,354 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this
+-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-'''expandlibs-exec.py applies expandlibs rules, and some more (see below) to
+-a given command line, and executes that command line with the expanded
+-arguments.
+-
+-With the --extract argument (useful for e.g. $(AR)), it extracts object files
+-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 --symbol-order argument, followed by a file name, it will add the
+-relevant linker options to change the order in which the linker puts the
+-symbols appear in the resulting binary. Only works for ELF targets.
+-'''
+-from __future__ import with_statement
+-import sys
+-import os
+-from expandlibs import (
+-    ExpandArgs,
+-    relativize,
+-    isDynamicLib,
+-    isObject,
+-)
+-import expandlibs_config as conf
+-from optparse import OptionParser
+-import subprocess
+-import tempfile
+-import shutil
+-import subprocess
+-import re
+-from mozbuild.makeutil import Makefile
+-
+-# The are the insert points for a GNU ld linker script, assuming a more
+-# or less "standard" default linker script. This is not a dict because
+-# order is important.
+-SECTION_INSERT_BEFORE = [
+-  ('.text', '.fini'),
+-  ('.rodata', '.rodata1'),
+-  ('.data.rel.ro', '.dynamic'),
+-  ('.data', '.data1'),
+-]
+-
+-class ExpandArgsMore(ExpandArgs):
+-    ''' Meant to be used as 'with ExpandArgsMore(args) as ...: '''
+-    def __enter__(self):
+-        self.tmp = []
+-        return self
+-        
+-    def __exit__(self, type, value, tb):
+-        '''Automatically remove temporary files'''
+-        for tmp in self.tmp:
+-            if os.path.isdir(tmp):
+-                shutil.rmtree(tmp, True)
+-            else:
+-                os.remove(tmp)
+-
+-    def extract(self):
+-        self[0:] = self._extract(self)
+-
+-    def _extract(self, args):
+-        '''When a static library name is found, either extract its contents
+-        in a temporary directory or use the information found in the
+-        corresponding lib descriptor.
+-        '''
+-        ar_extract = conf.AR_EXTRACT.split()
+-        newlist = []
+-
+-        def lookup(base, f):
+-            for root, dirs, files in os.walk(base):
+-                if f in files:
+-                    return os.path.join(root, f)
+-
+-        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))
+-                    continue
+-                elif os.path.exists(arg) and (len(ar_extract) or conf.AR == 'lib'):
+-                    tmp = tempfile.mkdtemp(dir=os.curdir)
+-                    self.tmp.append(tmp)
+-                    if conf.AR == 'lib':
+-                        out = subprocess.check_output([conf.AR, '-NOLOGO', '-LIST', arg])
+-                        files = out.splitlines()
+-                        # If lib -list returns a list full of dlls, it's an
+-                        # import lib.
+-                        if all(isDynamicLib(f) for f in files):
+-                            newlist += [arg]
+-                            continue
+-                        for f in files:
+-                            subprocess.call([conf.AR, '-NOLOGO', '-EXTRACT:%s' % f, os.path.abspath(arg)], cwd=tmp)
+-                    else:
+-                        subprocess.call(ar_extract + [os.path.abspath(arg)], cwd=tmp)
+-                    objs = []
+-                    basedir = os.path.dirname(arg)
+-                    for root, dirs, files in os.walk(tmp):
+-                        for f in files:
+-                            if isObject(f):
+-                                # If the file extracted from the library also
+-                                # exists in the directory containing the
+-                                # library, or one of its subdirectories, use
+-                                # that instead.
+-                                maybe_obj = lookup(os.path.join(basedir, os.path.relpath(root, tmp)), f)
+-                                if maybe_obj:
+-                                    objs.append(relativize(maybe_obj))
+-                                else:
+-                                    objs.append(relativize(os.path.join(root, f)))
+-                    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
+-        fd, tmp = tempfile.mkstemp(suffix=".list",dir=os.curdir)
+-        if conf.EXPAND_LIBS_LIST_STYLE == "linkerscript":
+-            content = ['INPUT("%s")\n' % obj for obj in objs]
+-            ref = tmp
+-        elif conf.EXPAND_LIBS_LIST_STYLE == "filelist":
+-            content = ["%s\n" % obj for obj in objs]
+-            ref = "-Wl,-filelist," + tmp
+-        elif conf.EXPAND_LIBS_LIST_STYLE == "list":
+-            content = ["%s\n" % obj for obj in objs]
+-            ref = "@" + tmp
+-        else:
+-            os.close(fd)
+-            os.remove(tmp)
+-            return
+-        self.tmp.append(tmp)
+-        f = os.fdopen(fd, "w")
+-        f.writelines(content)
+-        f.close()
+-        idx = self.index(objs[0])
+-        newlist = self[0:idx] + [ref] + [os.path.normpath(item) for item in self[idx:] if item not in objs]
+-        self[0:] = newlist
+-
+-    def _getFoldedSections(self):
+-        '''Returns a dict about folded sections.
+-        When section A and B are folded into section C, the dict contains:
+-        { 'A': 'C',
+-          'B': 'C',
+-          'C': ['A', 'B'] }'''
+-        if not conf.LD_PRINT_ICF_SECTIONS:
+-            return {}
+-
+-        proc = subprocess.Popen(self + [conf.LD_PRINT_ICF_SECTIONS], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+-        (stdout, stderr) = proc.communicate()
+-        result = {}
+-        # gold's --print-icf-sections output looks like the following:
+-        # ld: ICF folding section '.section' in file 'file.o'into '.section' in file 'file.o'
+-        # In terms of words, chances are this will change in the future,
+-        # especially considering "into" is misplaced. Splitting on quotes
+-        # seems safer.
+-        for l in stderr.split('\n'):
+-            quoted = l.split("'")
+-            if len(quoted) > 5 and quoted[1] != quoted[5]:
+-                result[quoted[1]] = [quoted[5]]
+-                if quoted[5] in result:
+-                    result[quoted[5]].append(quoted[1])
+-                else:
+-                    result[quoted[5]] = [quoted[1]]
+-        return result
+-
+-    def _getOrderedSections(self, ordered_symbols):
+-        '''Given an ordered list of symbols, returns the corresponding list
+-        of sections following the order.'''
+-        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+-            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+-        finder = SectionFinder([arg for arg in self if isObject(arg) or os.path.splitext(arg)[1] == conf.LIB_SUFFIX])
+-        folded = self._getFoldedSections()
+-        sections = set()
+-        ordered_sections = []
+-        for symbol in ordered_symbols:
+-            symbol_sections = finder.getSections(symbol)
+-            all_symbol_sections = []
+-            for section in symbol_sections:
+-                if section in folded:
+-                    if isinstance(folded[section], str):
+-                        section = folded[section]
+-                    all_symbol_sections.append(section)
+-                    all_symbol_sections.extend(folded[section])
+-                else:
+-                    all_symbol_sections.append(section)
+-            for section in all_symbol_sections:
+-                if not section in sections:
+-                    ordered_sections.append(section)
+-                    sections.add(section)
+-        return ordered_sections
+-
+-    def orderSymbols(self, order):
+-        '''Given a file containing a list of symbols, adds the appropriate
+-        argument to make the linker put the symbols in that order.'''
+-        with open(order) as file:
+-            sections = self._getOrderedSections([l.strip() for l in file.readlines() if l.strip()])
+-        split_sections = {}
+-        linked_sections = [s[0] for s in SECTION_INSERT_BEFORE]
+-        for s in sections:
+-            for linked_section in linked_sections:
+-                if s.startswith(linked_section):
+-                    if linked_section in split_sections:
+-                        split_sections[linked_section].append(s)
+-                    else:
+-                        split_sections[linked_section] = [s]
+-                    break
+-        content = []
+-        # Order is important
+-        linked_sections = [s for s in linked_sections if s in split_sections]
+-
+-        if conf.EXPAND_LIBS_ORDER_STYLE == 'section-ordering-file':
+-            option = '-Wl,--section-ordering-file,%s'
+-            content = sections
+-            for linked_section in linked_sections:
+-                content.extend(split_sections[linked_section])
+-                content.append('%s.*' % linked_section)
+-                content.append(linked_section)
+-
+-        elif conf.EXPAND_LIBS_ORDER_STYLE == 'linkerscript':
+-            option = '-Wl,-T,%s'
+-            section_insert_before = dict(SECTION_INSERT_BEFORE)
+-            for linked_section in linked_sections:
+-                content.append('SECTIONS {')
+-                content.append('  %s : {' % linked_section)
+-                content.extend('    *(%s)' % s for s in split_sections[linked_section])
+-                content.append('  }')
+-                content.append('}')
+-                content.append('INSERT BEFORE %s' % section_insert_before[linked_section])
+-        else:
+-            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+-
+-        fd, tmp = tempfile.mkstemp(dir=os.curdir)
+-        f = os.fdopen(fd, "w")
+-        f.write('\n'.join(content)+'\n')
+-        f.close()
+-        self.tmp.append(tmp)
+-        self.append(option % tmp)
+-
+-class SectionFinder(object):
+-    '''Instances of this class allow to map symbol names to sections in
+-    object files.'''
+-
+-    def __init__(self, objs):
+-        '''Creates an instance, given a list of object files.'''
+-        if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
+-            raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
+-        self.mapping = {}
+-        for obj in objs:
+-            if not isObject(obj) and os.path.splitext(obj)[1] != conf.LIB_SUFFIX:
+-                raise Exception('%s is not an object nor a static library' % obj)
+-            for symbol, section in SectionFinder._getSymbols(obj):
+-                sym = SectionFinder._normalize(symbol)
+-                if sym in self.mapping:
+-                    if not section in self.mapping[sym]:
+-                        self.mapping[sym].append(section)
+-                else:
+-                    self.mapping[sym] = [section]
+-
+-    def getSections(self, symbol):
+-        '''Given a symbol, returns a list of sections containing it or the
+-        corresponding thunks. When the given symbol is a thunk, returns the
+-        list of sections containing its corresponding normal symbol and the
+-        other thunks for that symbol.'''
+-        sym = SectionFinder._normalize(symbol)
+-        if sym in self.mapping:
+-            return self.mapping[sym]
+-        return []
+-
+-    @staticmethod
+-    def _normalize(symbol):
+-        '''For normal symbols, return the given symbol. For thunks, return
+-        the corresponding normal symbol.'''
+-        if re.match('^_ZThn[0-9]+_', symbol):
+-            return re.sub('^_ZThn[0-9]+_', '_Z', symbol)
+-        return symbol
+-
+-    @staticmethod
+-    def _getSymbols(obj):
+-        '''Returns a list of (symbol, section) contained in the given object
+-        file.'''
+-        proc = subprocess.Popen(['objdump', '-t', obj], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+-        (stdout, stderr) = proc.communicate()
+-        syms = []
+-        for line in stdout.splitlines():
+-            # Each line has the following format:
+-            # <addr> [lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>
+-            tmp = line.split(' ',1)
+-            # This gives us ["<addr>", "[lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>"]
+-            # We only need to consider cases where "<section>\t<length> <symbol>" is present,
+-            # and where the [FfO] flag is either F (function) or O (object).
+-            if len(tmp) > 1 and len(tmp[1]) > 6 and tmp[1][6] in ['O', 'F']:
+-                tmp = tmp[1][8:].split()
+-                # That gives us ["<section>","<length>", "<symbol>"]
+-                syms.append((tmp[-1], tmp[0]))
+-        return syms
+-
+-def print_command(out, args):
+-    print >>out, "Executing: " + " ".join(args)
+-    for tmp in [f for f in args.tmp if os.path.isfile(f)]:
+-        print >>out, tmp + ":"
+-        with open(tmp) as file:
+-            print >>out, "".join(["    " + l for l in file.readlines()])
+-    out.flush()
+-
+-def main(args, proc_callback=None):
+-    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("--symbol-order", dest="symbol_order", metavar="FILE",
+-        help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
+-
+-    (options, args) = parser.parse_args(args)
+-
+-    with ExpandArgsMore(args) as args:
+-        if options.extract:
+-            args.extract()
+-        if options.symbol_order:
+-            args.orderSymbols(options.symbol_order)
+-        if options.uselist:
+-            args.makelist()
+-
+-        if options.verbose:
+-            print_command(sys.stderr, args)
+-        try:
+-            proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+-            if proc_callback:
+-                proc_callback(proc)
+-        except Exception, e:
+-            print >>sys.stderr, 'error: Launching', args, ':', e
+-            raise e
+-        (stdout, stderr) = proc.communicate()
+-        if proc.returncode and not options.verbose:
+-            print_command(sys.stderr, args)
+-        sys.stderr.write(stdout)
+-        sys.stderr.flush()
+-        if proc.returncode:
+-            return proc.returncode
+-        return 0
+-
+-if __name__ == '__main__':
+-    exit(main(sys.argv[1:]))
+diff --git a/config/expandlibs_gen.py b/config/expandlibs_gen.py
+deleted file mode 100644
+--- a/config/expandlibs_gen.py
++++ /dev/null
+@@ -1,41 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this
+-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-'''Given a list of object files and library names, prints a library
+-descriptor to standard output'''
+-
+-from __future__ import with_statement
+-import sys
+-import os
+-import expandlibs_config as conf
+-from expandlibs import LibDescriptor, isObject, ensureParentDir
+-from optparse import OptionParser
+-
+-def generate(args):
+-    desc = LibDescriptor()
+-    for arg in args:
+-        if isObject(arg):
+-            if os.path.exists(arg):
+-                desc['OBJS'].append(os.path.abspath(arg))
+-            else:
+-                raise Exception("File not found: %s" % arg)
+-        elif os.path.splitext(arg)[1] == conf.LIB_SUFFIX:
+-            if os.path.exists(arg) or os.path.exists(arg + conf.LIBS_DESC_SUFFIX):
+-                desc['LIBS'].append(os.path.abspath(arg))
+-            else:
+-                raise Exception("File not found: %s" % arg)
+-    return desc
+-
+-if __name__ == '__main__':
+-    parser = OptionParser()
+-    parser.add_option("-o", dest="output", metavar="FILE",
+-        help="send output to the given file")
+-
+-    (options, args) = parser.parse_args()
+-    if not options.output:
+-        raise Exception("Missing option: -o")
+-
+-    ensureParentDir(options.output)
+-    with open(options.output, 'w') as outfile:
+-        print >>outfile, generate(args)
+diff --git a/config/rules.mk b/config/rules.mk
+--- a/config/rules.mk
++++ b/config/rules.mk
+@@ -96,19 +96,18 @@ endif # ENABLE_TESTS
+ #
+ # If FORCE_STATIC_LIB is set, build a static library.
+ # Otherwise, build a shared library.
+ #
+ 
+ ifndef LIBRARY
+ ifdef REAL_LIBRARY
+ ifdef NO_EXPAND_LIBS
++# Only build actual library if it is requested.
+ LIBRARY			:= $(REAL_LIBRARY)
+-else
+-LIBRARY			:= $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
+ endif
+ endif
+ endif
+ 
+ ifndef HOST_LIBRARY
+ ifdef HOST_LIBRARY_NAME
+ HOST_LIBRARY		:= $(LIB_PREFIX)$(HOST_LIBRARY_NAME).$(LIB_SUFFIX)
+ endif
+@@ -416,32 +415,35 @@ ECHO := true
+ QUIET := -q
+ endif
+ 
+ # Do everything from scratch
+ everything::
+ 	$(MAKE) clean
+ 	$(MAKE) all
+ 
+-STATIC_LIB_DEP = $(if $(wildcard $(1).$(LIBS_DESC_SUFFIX)),$(1).$(LIBS_DESC_SUFFIX),$(1))
+-STATIC_LIBS_DEPS := $(foreach l,$(STATIC_LIBS),$(call STATIC_LIB_DEP,$(l)))
+-
+ # Dependencies which, if modified, should cause everything to rebuild
+ GLOBAL_DEPS += Makefile $(addprefix $(DEPTH)/config/,$(INCLUDED_AUTOCONF_MK)) $(MOZILLA_DIR)/config/config.mk
+ 
+ ##############################################
+ ifdef COMPILE_ENVIRONMENT
+ OBJ_TARGETS = $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)
+ 
+ compile:: host target
+ 
+ host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS) $(HOST_RUST_LIBRARY_FILE)
+ 
+ target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(RUST_LIBRARY_FILE) $(RUST_PROGRAMS)
+ 
++ifndef LIBRARY
++ifdef OBJS
++target:: $(OBJS)
++endif
++endif
++
+ syms::
+ 
+ include $(MOZILLA_DIR)/config/makefiles/target_binaries.mk
+ endif
+ 
+ ##############################################
+ ifneq (1,$(NO_PROFILE_GUIDED_OPTIMIZE))
+ ifdef MOZ_PROFILE_USE
+@@ -515,35 +517,35 @@ distclean::
+ 	$(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \
+ 	$(wildcard *.$(IMPORT_LIB_SUFFIX))
+ 
+ alltags:
+ 	$(RM) TAGS
+ 	find $(topsrcdir) -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' -o -name '*.idl' \) -print | $(TAG_PROGRAM)
+ 
+ define EXPAND_CC_OR_CXX
+-$(if $(PROG_IS_C_ONLY_$(1)),$(EXPAND_CC),$(EXPAND_CCC))
++$(if $(PROG_IS_C_ONLY_$(1)),$(CC),$(CCC))
+ endef
+ 
+ # Workaround a bug of MSVC 2017 Update 8 (see bug 1485224)
+ ifeq ($(CC_TYPE)_$(HOST_OS_ARCH)_$(MOZ_PROFILE_GENERATE),msvc_WINNT_1)
+ LINKER_OUT=$(subst /,\,$1)
+ else
+ LINKER_OUT=$1
+ endif
+ 
+ #
+ # PROGRAM = Foo
+ # creates OBJS, links with LIBS to create Foo
+ #
+-$(PROGRAM): $(PROGOBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(RESFILE) $(GLOBAL_DEPS) $(call mkdir_deps,$(FINAL_TARGET))
++$(PROGRAM): $(PROGOBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(RESFILE) $(GLOBAL_DEPS) $(call mkdir_deps,$(FINAL_TARGET))
+ 	$(REPORT_BUILD)
+ 	@$(RM) $@.manifest
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+-	$(EXPAND_LINK) -NOLOGO -OUT:$(call LINKER_OUT,$@) -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
++	$(LINKER) -NOLOGO -OUT:$(call LINKER_OUT,$@) -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $($(notdir $@)_OBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
+ ifdef MSMANIFEST_TOOL
+ 	@if test -f $@.manifest; then \
+ 		if test -f '$(srcdir)/$(notdir $@).manifest'; then \
+ 			echo 'Embedding manifest from $(srcdir)/$(notdir $@).manifest and $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$(notdir $@).manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		else \
+ 			echo 'Embedding manifest from $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+@@ -554,140 +556,133 @@ ifdef MSMANIFEST_TOOL
+ 	fi
+ endif	# MSVC with manifest tool
+ ifdef MOZ_PROFILE_GENERATE
+ # touch it a few seconds into the future to work around FAT's
+ # 2-second granularity
+ 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
+ endif
+ else # !WINNT || GNU_CC
+-	$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
++	$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $($(notdir $@)_OBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ endif # WINNT && !GNU_CC
+ 
+ ifdef ENABLE_STRIP
+ 	$(STRIP) $(STRIP_FLAGS) $@
+ endif
+ ifdef MOZ_POST_PROGRAM_COMMAND
+ 	$(MOZ_POST_PROGRAM_COMMAND) $@
+ endif
+ 
+ $(HOST_PROGRAM): $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifeq (_WINNT,$(GNU_CC)_$(HOST_OS_ARCH))
+-	$(EXPAND_LIBS_EXEC) -- $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ ifdef MSMANIFEST_TOOL
+ 	@if test -f $@.manifest; then \
+ 		if test -f '$(srcdir)/$@.manifest'; then \
+ 			echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		else \
+ 			echo 'Embedding manifest from $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		fi; \
+ 	elif test -f '$(srcdir)/$@.manifest'; then \
+ 		echo 'Embedding manifest from $(srcdir)/$@.manifest'; \
+ 		$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' -OUTPUTRESOURCE:$@\;1; \
+ 	fi
+ endif	# MSVC with manifest tool
+ else
+ ifeq ($(HOST_CPP_PROG_LINK),1)
+-	$(EXPAND_LIBS_EXEC) -- $(HOST_CXX) -o $@ $(HOST_CXX_LDFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(HOST_CXX) -o $@ $(HOST_CXX_LDFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ else
+-	$(EXPAND_LIBS_EXEC) -- $(HOST_CC) -o $@ $(HOST_C_LDFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(HOST_CC) -o $@ $(HOST_C_LDFLAGS) $(HOST_LDFLAGS) $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ endif # HOST_CPP_PROG_LINK
+ endif
+ ifndef CROSS_COMPILE
+ 	$(call py_action,check_binary,--host $@)
+ endif
+ 
+ #
+ # This is an attempt to support generation of multiple binaries
+ # in one directory, it assumes everything to compile Foo is in
+ # Foo.o (from either Foo.c or Foo.cpp).
+ #
+ # SIMPLE_PROGRAMS = Foo Bar
+ # creates Foo.o Bar.o, links with LIBS to create Foo, Bar.
+ #
+-$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
++$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+-	$(EXPAND_LINK) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
++	$(LINKER) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $($@_OBJS) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
+ ifdef MSMANIFEST_TOOL
+ 	@if test -f $@.manifest; then \
+ 		$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		rm -f $@.manifest; \
+ 	fi
+ endif	# MSVC with manifest tool
+ else
+-	$(call EXPAND_CC_OR_CXX,$@) $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
++	$(call EXPAND_CC_OR_CXX,$@) $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) -o $@ $($@_OBJS) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ endif # WINNT && !GNU_CC
+ 
+ ifdef ENABLE_STRIP
+ 	$(STRIP) $(STRIP_FLAGS) $@
+ endif
+ ifdef MOZ_POST_PROGRAM_COMMAND
+ 	$(MOZ_POST_PROGRAM_COMMAND) $@
+ endif
+ 
+ $(HOST_SIMPLE_PROGRAMS): host_%$(HOST_BIN_SUFFIX): host_%.$(OBJ_SUFFIX) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC))
+-	$(EXPAND_LIBS_EXEC) -- $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ else
+ ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX))
+-	$(EXPAND_LIBS_EXEC) -- $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXX_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXX_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ else
+-	$(EXPAND_LIBS_EXEC) -- $(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_C_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
++	$(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_C_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+ endif
+ endif
+ ifndef CROSS_COMPILE
+ 	$(call py_action,check_binary,--host $@)
+ endif
+ 
+-$(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
++$(LIBRARY): $(OBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+-# Always remove both library and library descriptor
+-	$(RM) $(REAL_LIBRARY) $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
+-	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(STATIC_LIBS)
+-
+-$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+-# When we only build a library descriptor, blow out any existing library
+-	$(REPORT_BUILD)
+-	$(if $(filter %.$(LIB_SUFFIX),$(LIBRARY)),,$(RM) $(REAL_LIBRARY))
+-	$(EXPAND_LIBS_GEN) -o $@ $(OBJS) $(STATIC_LIBS)
++	$(RM) $(REAL_LIBRARY)
++	$(AR) $(AR_FLAGS) $(OBJS) $($@_OBJS)
+ 
+ ifeq ($(OS_ARCH),WINNT)
+ # Import libraries are created by the rules creating shared libraries.
+ # The rules to copy them to $(DIST)/lib depend on $(IMPORT_LIBRARY),
+ # but make will happily consider the import library before it is refreshed
+ # when rebuilding the corresponding shared library. Defining an empty recipe
+ # for import libraries forces make to wait for the shared library recipe to
+ # have run before considering other targets that depend on the import library.
+ # See bug 795204.
+ $(IMPORT_LIBRARY): $(SHARED_LIBRARY) ;
+ endif
+ 
+ $(HOST_LIBRARY): $(HOST_OBJS) Makefile
+ 	$(REPORT_BUILD)
+ 	$(RM) $@
+-	$(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
++	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
+ 
+ # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files,
+ # so instead of deleting .o files after repacking them into a dylib, we make
+ # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
+ # so no need to conditionalize on OS version or debugging format.
+ 
+-$(SHARED_LIBRARY): $(OBJS) $(RESFILE) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
++$(SHARED_LIBRARY): $(OBJS) $(RESFILE) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifndef INCREMENTAL_LINKER
+ 	$(RM) $@
+ endif
+-	$(EXPAND_MKSHLIB) $(OBJS) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
++	$(MKSHLIB) $($@_OBJS) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ 
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+ ifdef MSMANIFEST_TOOL
+ ifdef EMBED_MANIFEST_AT
+ 	@if test -f $@.manifest; then \
+ 		if test -f '$(srcdir)/$@.manifest'; then \
+ 			echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
+diff --git a/config/tests/python.ini b/config/tests/python.ini
+--- a/config/tests/python.ini
++++ b/config/tests/python.ini
+@@ -1,5 +1,4 @@
+ [test_mozbuild_reading.py]
+-[unit-expandlibs.py]
+ [unit-mozunit.py]
+ [unit-nsinstall.py]
+ [unit-printprereleasesuffix.py]
+diff --git a/config/tests/unit-expandlibs.py b/config/tests/unit-expandlibs.py
+deleted file mode 100644
+--- a/config/tests/unit-expandlibs.py
++++ /dev/null
+@@ -1,431 +0,0 @@
+-import subprocess
+-import unittest
+-import sys
+-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',
+-    'EXPAND_LIBS_LIST_STYLE': 'linkerscript',
+-}
+-
+-config = sys.modules['expandlibs_config'] = imp.new_module('expandlibs_config')
+-
+-from expandlibs import LibDescriptor, ExpandArgs, relativize
+-from expandlibs_gen import generate
+-from expandlibs_exec import ExpandArgsMore, SectionFinder
+-
+-def Lib(name):
+-    return config.LIB_PREFIX + name + config.LIB_SUFFIX
+-
+-def Obj(name):
+-    return name + config.OBJ_SUFFIX
+-
+-def Dll(name):
+-    return config.DLL_PREFIX + name + config.DLL_SUFFIX
+-
+-def ImportLib(name):
+-    if not len(config.IMPORT_LIB_SUFFIX): return Dll(name)
+-    return config.LIB_PREFIX + name + config.IMPORT_LIB_SUFFIX
+-
+-class TestRelativize(unittest.TestCase):
+-    def test_relativize(self):
+-        '''Test relativize()'''
+-        os_path_exists = os.path.exists
+-        def exists(path):
+-            return True
+-        os.path.exists = exists
+-        self.assertEqual(relativize(os.path.abspath(os.curdir)), os.curdir)
+-        self.assertEqual(relativize(os.path.abspath(os.pardir)), os.pardir)
+-        self.assertEqual(relativize(os.path.join(os.curdir, 'a')), 'a')
+-        self.assertEqual(relativize(os.path.join(os.path.abspath(os.curdir), 'a')), 'a')
+-        # relativize is expected to return the absolute path if it is shorter
+-        self.assertEqual(relativize(os.sep), os.sep)
+-        os.path.exists = os.path.exists
+-
+-class TestLibDescriptor(unittest.TestCase):
+-    def test_serialize(self):
+-        '''Test LibDescriptor's serialization'''
+-        desc = LibDescriptor()
+-        desc[LibDescriptor.KEYS[0]] = ['a', 'b']
+-        self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0]))
+-        desc['unsupported-key'] = ['a']
+-        self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0]))
+-        desc[LibDescriptor.KEYS[1]] = ['c', 'd', 'e']
+-        self.assertEqual(str(desc),
+-                         "{0} = a b\n{1} = c d e"
+-                         .format(LibDescriptor.KEYS[0], LibDescriptor.KEYS[1]))
+-        desc[LibDescriptor.KEYS[0]] = []
+-        self.assertEqual(str(desc), "{0} = c d e".format(LibDescriptor.KEYS[1]))
+-
+-    def test_read(self):
+-        '''Test LibDescriptor's initialization'''
+-        desc_list = ["# Comment",
+-                     "{0} = a b".format(LibDescriptor.KEYS[1]),
+-                     "", # Empty line
+-                     "foo = bar", # Should be discarded
+-                     "{0} = c d e".format(LibDescriptor.KEYS[0])]
+-        desc = LibDescriptor(desc_list)
+-        self.assertEqual(desc[LibDescriptor.KEYS[1]], ['a', 'b'])
+-        self.assertEqual(desc[LibDescriptor.KEYS[0]], ['c', 'd', 'e'])
+-        self.assertEqual(False, 'foo' in desc)
+-
+-def wrap_method(conf, wrapped_method):
+-    '''Wrapper used to call a test with a specific configuration'''
+-    def _method(self):
+-        for key in conf:
+-            setattr(config, key, conf[key])
+-        self.init()
+-        try:
+-            wrapped_method(self)
+-        except:
+-            raise
+-        finally:
+-            self.cleanup()
+-    return _method
+-
+-class ReplicateTests(type):
+-    '''Replicates tests for unix and windows variants'''
+-    def __new__(cls, clsName, bases, dict):
+-        for name in [key for key in dict if key.startswith('test_')]:
+-            dict[name + '_unix'] = wrap_method(config_unix, dict[name])
+-            dict[name + '_unix'].__doc__ = dict[name].__doc__ + ' (unix)'
+-            dict[name + '_win'] = wrap_method(config_win, dict[name])
+-            dict[name + '_win'].__doc__ = dict[name].__doc__ + ' (win)'
+-            del dict[name]
+-        return type.__new__(cls, clsName, bases, dict)
+-
+-class TestCaseWithTmpDir(unittest.TestCase):
+-    __metaclass__ = ReplicateTests
+-    def init(self):
+-        self.tmpdir = os.path.abspath(mkdtemp(dir=os.curdir))
+-
+-    def cleanup(self):
+-        rmtree(self.tmpdir)
+-
+-    def touch(self, files):
+-        for f in files:
+-            open(f, 'w').close()
+-
+-    def tmpfile(self, *args):
+-        return os.path.join(self.tmpdir, *args)
+-
+-class TestExpandLibsGen(TestCaseWithTmpDir):
+-    def test_generate(self):
+-        '''Test library descriptor generation'''
+-        files = [self.tmpfile(f) for f in
+-                 [Lib('a'), Obj('b'), Lib('c'), Obj('d'), Obj('e'), Lib('f')]]
+-        self.touch(files[:-1])
+-        self.touch([files[-1] + config.LIBS_DESC_SUFFIX])
+-
+-        desc = generate(files)
+-        self.assertEqual(desc['OBJS'], [self.tmpfile(Obj(s)) for s in ['b', 'd', 'e']])
+-        self.assertEqual(desc['LIBS'], [self.tmpfile(Lib(s)) for s in ['a', 'c', 'f']])
+-
+-        self.assertRaises(Exception, generate, files + [self.tmpfile(Obj('z'))])
+-        self.assertRaises(Exception, generate, files + [self.tmpfile(Lib('y'))])
+-
+-class TestExpandInit(TestCaseWithTmpDir):
+-    def init(self):
+-        ''' Initializes test environment for library expansion tests'''
+-        super(TestExpandInit, self).init()
+-        # Create 2 fake libraries, each containing 3 objects, and the second
+-        # including the first one and another library.
+-        os.mkdir(self.tmpfile('libx'))
+-        os.mkdir(self.tmpfile('liby'))
+-        self.libx_files = [self.tmpfile('libx', Obj(f)) for f in ['g', 'h', 'i']]
+-        self.liby_files = [self.tmpfile('liby', Obj(f)) for f in ['j', 'k', 'l']] + [self.tmpfile('liby', Lib('z'))]
+-        self.touch(self.libx_files + self.liby_files)
+-        with open(self.tmpfile('libx', Lib('x') + config.LIBS_DESC_SUFFIX), 'w') as f:
+-            f.write(str(generate(self.libx_files)))
+-        with open(self.tmpfile('liby', Lib('y') + config.LIBS_DESC_SUFFIX), 'w') as f:
+-            f.write(str(generate(self.liby_files + [self.tmpfile('libx', Lib('x'))])))
+-
+-        # Create various objects and libraries 
+-        self.arg_files = [self.tmpfile(f) for f in [Lib('a'), Obj('b'), Obj('c'), Lib('d'), Obj('e')]]
+-        # We always give library names (LIB_PREFIX/SUFFIX), even for
+-        # dynamic/import libraries
+-        self.files = self.arg_files + [self.tmpfile(ImportLib('f'))]
+-        self.arg_files += [self.tmpfile(Lib('f'))]
+-        self.touch(self.files)
+-
+-    def assertRelEqual(self, args1, args2):
+-        self.assertEqual(args1, [relativize(a) for a in args2])
+-
+-class TestExpandArgs(TestExpandInit):
+-    def test_expand(self):
+-        '''Test library expansion'''
+-        # Expanding arguments means libraries with a descriptor are expanded
+-        # with the descriptor content, and import libraries are used when
+-        # a library doesn't exist
+-        args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
+-        self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) 
+-
+-        # When a library exists at the same time as a descriptor, we still use
+-        # the descriptor.
+-        self.touch([self.tmpfile('libx', Lib('x'))])
+-        args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
+-        self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
+-
+-        self.touch([self.tmpfile('liby', Lib('y'))])
+-        args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
+-        self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
+-
+-class TestExpandArgsMore(TestExpandInit):
+-    def test_makelist(self):
+-        '''Test grouping object files in lists'''
+-        # 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) 
+-
+-            # But also has an extra method replacing object files with a list
+-            args.makelist()
+-            # self.files has objects at #1, #2, #4
+-            self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
+-            self.assertRelEqual(args[4:], [self.files[3]] + self.files[5:] + [self.tmpfile('liby', Lib('z'))])
+-
+-            # Check the list file content
+-            objs = [f for f in self.files + self.liby_files + self.libx_files if f.endswith(config.OBJ_SUFFIX)]
+-            if config.EXPAND_LIBS_LIST_STYLE == "linkerscript":
+-                self.assertNotEqual(args[3][0], '@')
+-                filename = args[3]
+-                content = ['INPUT("{0}")'.format(relativize(f)) for f in objs]
+-                with open(filename, 'r') as f:
+-                    self.assertEqual([l.strip() for l in f.readlines() if len(l.strip())], content)
+-            elif config.EXPAND_LIBS_LIST_STYLE == "list":
+-                self.assertEqual(args[3][0], '@')
+-                filename = args[3][1:]
+-                content = objs
+-                with open(filename, 'r') as f:
+-                    self.assertRelEqual([l.strip() for l in f.readlines() if len(l.strip())], content)
+-
+-            tmp = args.tmp
+-        # Check that all temporary files are properly removed
+-        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
+-        subprocess_check_output = subprocess.check_output
+-        def call(args, **kargs):
+-            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.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'))])
+-        for iteration in (1, 2):
+-            with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
+-                files = self.files + self.liby_files + self.libx_files
+-
+-                self.assertRelEqual(args, ['foo', '-bar'] + files)
+-
+-                extracted = {}
+-                # ExpandArgsMore also has an extra method extracting static libraries
+-                # when possible
+-                args.extract()
+-
+-                # 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):
+-                        base = os.path.splitext(os.path.basename(f))[0]
+-                        # On the first iteration, we test the behavior of
+-                        # extracting archives that don't have a copy of their
+-                        # contents next to them, which is to use the file
+-                        # extracted from the archive in a temporary directory.
+-                        # On the second iteration, we test extracting archives
+-                        # that do have a copy of their contents next to them,
+-                        # in which case those contents are used instead of the
+-                        # temporarily extracted files.
+-                        if iteration == 1:
+-                            extracted_args.extend(sorted(extracted[base]))
+-                        else:
+-                            dirname = os.path.dirname(f[len(self.tmpdir)+1:])
+-                            if base.endswith('f'):
+-                                dirname = os.path.join(dirname, 'foo', 'bar')
+-                            extracted_args.extend([self.tmpfile(dirname, Obj(base)), self.tmpfile(dirname, Obj(base + '2'))])
+-                    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]))
+-
+-            # Create archives contents next to them for the second iteration.
+-            base = os.path.splitext(Lib('_'))[0]
+-            self.touch(self.tmpfile(Obj(base.replace('_', suffix))) for suffix in ('a', 'a2', 'd', 'd2'))
+-            try:
+-                os.makedirs(self.tmpfile('foo', 'bar'))
+-            except:
+-                pass
+-            self.touch(self.tmpfile('foo', 'bar', Obj(base.replace('_', suffix))) for suffix in ('f', 'f2'))
+-            self.touch(self.tmpfile('liby', Obj(base.replace('_', suffix))) for suffix in ('z', 'z2'))
+-
+-        # Restore subprocess.call and subprocess.check_output
+-        subprocess.call = subprocess_call
+-        subprocess.check_output = subprocess_check_output
+-
+-class FakeProcess(object):
+-    def __init__(self, out, err = ''):
+-        self.out = out
+-        self.err = err
+-
+-    def communicate(self):
+-        return (self.out, self.err)
+-
+-OBJDUMPS = {
+-'foo.o': '''
+-00000000 g     F .text\t00000001 foo
+-00000000 g     F .text._Z6foobarv\t00000001 _Z6foobarv
+-00000000 g     F .text.hello\t00000001 hello
+-00000000 g     F .text._ZThn4_6foobarv\t00000001 _ZThn4_6foobarv
+-''',
+-'bar.o': '''
+-00000000 g     F .text.hi\t00000001 hi
+-00000000 g     F .text.hot._Z6barbazv\t00000001 .hidden _Z6barbazv
+-''',
+-}
+-
+-PRINT_ICF = '''
+-ld: ICF folding section '.text.hello' in file 'foo.o'into '.text.hi' in file 'bar.o'
+-ld: ICF folding section '.foo' in file 'foo.o'into '.foo' in file 'bar.o'
+-'''
+-
+-class SubprocessPopen(object):
+-    def __init__(self, test):
+-        self.test = test
+-
+-    def __call__(self, args, stdout = None, stderr = None):
+-        self.test.assertEqual(stdout, subprocess.PIPE)
+-        self.test.assertEqual(stderr, subprocess.PIPE)
+-        if args[0] == 'objdump':
+-            self.test.assertEqual(args[1], '-t')
+-            self.test.assertTrue(args[2] in OBJDUMPS)
+-            return FakeProcess(OBJDUMPS[args[2]])
+-        else:
+-            return FakeProcess('', PRINT_ICF)
+-
+-class TestSectionFinder(unittest.TestCase):
+-    def test_getSections(self):
+-        '''Test SectionFinder'''
+-        # Divert subprocess.Popen
+-        subprocess_popen = subprocess.Popen
+-        subprocess.Popen = SubprocessPopen(self)
+-        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+-        config.OBJ_SUFFIX = '.o'
+-        config.LIB_SUFFIX = '.a'
+-        finder = SectionFinder(['foo.o', 'bar.o'])
+-        self.assertEqual(finder.getSections('foobar'), [])
+-        self.assertEqual(finder.getSections('_Z6barbazv'), ['.text.hot._Z6barbazv'])
+-        self.assertEqual(finder.getSections('_Z6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
+-        self.assertEqual(finder.getSections('_ZThn4_6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
+-        subprocess.Popen = subprocess_popen
+-
+-class TestSymbolOrder(unittest.TestCase):
+-    def test_getOrderedSections(self):
+-        '''Test ExpandMoreArgs' _getOrderedSections'''
+-        # Divert subprocess.Popen
+-        subprocess_popen = subprocess.Popen
+-        subprocess.Popen = SubprocessPopen(self)
+-        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+-        config.OBJ_SUFFIX = '.o'
+-        config.LIB_SUFFIX = '.a'
+-        config.LD_PRINT_ICF_SECTIONS = ''
+-        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+-        self.assertEqual(args._getOrderedSections(['_Z6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
+-        self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
+-        subprocess.Popen = subprocess_popen
+-
+-    def test_getFoldedSections(self):
+-        '''Test ExpandMoreArgs' _getFoldedSections'''
+-        # Divert subprocess.Popen
+-        subprocess_popen = subprocess.Popen
+-        subprocess.Popen = SubprocessPopen(self)
+-        config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
+-        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+-        self.assertEqual(args._getFoldedSections(), {'.text.hello': ['.text.hi'], '.text.hi': ['.text.hello']})
+-        subprocess.Popen = subprocess_popen
+-
+-    def test_getOrderedSectionsWithICF(self):
+-        '''Test ExpandMoreArgs' _getOrderedSections, with ICF'''
+-        # Divert subprocess.Popen
+-        subprocess_popen = subprocess.Popen
+-        subprocess.Popen = SubprocessPopen(self)
+-        config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
+-        config.OBJ_SUFFIX = '.o'
+-        config.LIB_SUFFIX = '.a'
+-        config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
+-        args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
+-        self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hello', '.text.hi', '.text.hot._Z6barbazv'])
+-        self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
+-        subprocess.Popen = subprocess_popen
+-
+-
+-if __name__ == '__main__':
+-    mozunit.main(runwith='unittest')
+diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py
+--- a/python/mozbuild/mozbuild/backend/common.py
++++ b/python/mozbuild/mozbuild/backend/common.py
+@@ -27,32 +27,39 @@ from mozbuild.frontend.data import (
+     Exports,
+     IPDLFile,
+     FinalTargetPreprocessedFiles,
+     FinalTargetFiles,
+     GeneratedEventWebIDLFile,
+     GeneratedSources,
+     GeneratedWebIDLFile,
+     GnProjectData,
++    HostLibrary,
++    HostRustLibrary,
+     PreprocessedTestWebIDLFile,
+     PreprocessedWebIDLFile,
++    RustLibrary,
+     SharedLibrary,
++    StaticLibrary,
+     TestWebIDLFile,
+     UnifiedSources,
+     XPIDLFile,
+     WebIDLFile,
+ )
+ from mozbuild.jar import (
+     DeprecatedJarManifest,
+     JarManifestParser,
+ )
+ from mozbuild.preprocessor import Preprocessor
+ from mozpack.chrome.manifest import parse_manifest_line
+ 
+-from mozbuild.util import group_unified_files
++from mozbuild.util import (
++    group_unified_files,
++    mkdir,
++)
+ 
+ class XPIDLManager(object):
+     """Helps manage XPCOM IDLs in the context of the build system."""
+     def __init__(self, config):
+         self.config = config
+         self.topsrcdir = config.topsrcdir
+         self.topobjdir = config.topobjdir
+ 
+@@ -349,16 +356,97 @@ class CommonBackend(BuildBackend):
+ 
+         # Write out a file listing generated sources.
+         with self._write_file(mozpath.join(topobjdir, 'generated-sources.json')) as fh:
+             d = {
+                 'sources': sorted(self._generated_sources),
+             }
+             json.dump(d, fh, sort_keys=True, indent=4)
+ 
++    def _expand_libs(self, input_bin):
++        os_libs = []
++        shared_libs = []
++        static_libs = []
++        objs = []
++
++        seen_objs = set()
++        seen_libs = set()
++
++        def add_objs(lib):
++            for o in lib.objs:
++                if o not in seen_objs:
++                    seen_objs.add(o)
++                    objs.append(o)
++
++        def expand(lib, recurse_objs, system_libs):
++            if isinstance(lib, StaticLibrary):
++                if lib.no_expand_lib:
++                    static_libs.append(lib)
++                    recurse_objs = False
++                elif recurse_objs:
++                    add_objs(lib)
++
++                for l in lib.linked_libraries:
++                    expand(l, recurse_objs, system_libs)
++
++                if system_libs:
++                    for l in lib.linked_system_libs:
++                        if l not in seen_libs:
++                            seen_libs.add(l)
++                            os_libs.append(l)
++
++            elif isinstance(lib, SharedLibrary):
++                if lib not in seen_libs:
++                    seen_libs.add(lib)
++                    shared_libs.append(lib)
++
++        add_objs(input_bin)
++
++        system_libs = not isinstance(input_bin, StaticLibrary)
++        for lib in input_bin.linked_libraries:
++            if isinstance(lib, RustLibrary):
++                continue
++            elif isinstance(lib, StaticLibrary):
++                expand(lib, True, system_libs)
++            elif isinstance(lib, SharedLibrary):
++                if lib not in seen_libs:
++                    seen_libs.add(lib)
++                    shared_libs.append(lib)
++
++        for lib in input_bin.linked_system_libs:
++            if lib not in seen_libs:
++                seen_libs.add(lib)
++                os_libs.append(lib)
++
++        return objs, shared_libs, os_libs, static_libs
++
++    def _make_list_file(self, objdir, objs, name):
++        if not objs:
++            return None
++        list_style = self.environment.substs.get('EXPAND_LIBS_LIST_STYLE')
++        list_file_path = mozpath.join(objdir, name)
++        objs = [os.path.relpath(o, objdir) for o in objs]
++        if list_style == 'linkerscript':
++            ref = list_file_path
++            content = '\n'.join('INPUT("%s")' % o for o in objs)
++        elif list_style == 'filelist':
++            ref = "-Wl,-filelist," + list_file_path
++            content = '\n'.join(objs)
++        elif list_style == 'list':
++            ref = "@" + list_file_path
++            content = '\n'.join(objs)
++        else:
++            return None
++
++        mkdir(objdir)
++        with self._write_file(list_file_path) as fh:
++            fh.write(content)
++
++        return ref
++
+     def _handle_generated_sources(self, files):
+         self._generated_sources.update(mozpath.relpath(f, self.environment.topobjdir) for f in files)
+ 
+     def _handle_webidl_collection(self, webidls):
+         if not webidls.all_stems():
+             return
+ 
+         bindings_dir = mozpath.join(self.environment.topobjdir, 'dom', 'bindings')
+diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py
+--- a/python/mozbuild/mozbuild/backend/recursivemake.py
++++ b/python/mozbuild/mozbuild/backend/recursivemake.py
+@@ -1282,77 +1282,78 @@ class RecursiveMakeBackend(CommonBackend
+     def _process_host_library(self, libdef, backend_file):
+         backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
+ 
+     def _build_target_for_obj(self, obj):
+         return '%s/%s' % (mozpath.relpath(obj.objdir,
+             self.environment.topobjdir), obj.KIND)
+ 
+     def _process_linked_libraries(self, obj, backend_file):
+-        def write_shared_and_system_libs(lib):
+-            for l in lib.linked_libraries:
+-                if isinstance(l, (StaticLibrary, RustLibrary)):
+-                    write_shared_and_system_libs(l)
+-                else:
+-                    backend_file.write_once('SHARED_LIBS += %s/%s\n'
+-                        % (pretty_relpath(l), l.import_name))
+-            for l in lib.linked_system_libs:
+-                backend_file.write_once('OS_LIBS += %s\n' % l)
+-
+         def pretty_relpath(lib):
+             return '$(DEPTH)/%s' % mozpath.relpath(lib.objdir, topobjdir)
+ 
+         topobjdir = mozpath.normsep(obj.topobjdir)
+         # This will create the node even if there aren't any linked libraries.
+         build_target = self._build_target_for_obj(obj)
+         self._compile_graph[build_target]
+ 
++        objs, shared_libs, os_libs, static_libs = self._expand_libs(obj)
++
++        if obj.KIND == 'target':
++            obj_target = obj.name
++            if isinstance(obj, Program):
++                obj_target = self._pretty_path(obj.output_path, backend_file)
++
++            objs_ref = ' \\\n    '.join(os.path.relpath(o, obj.objdir)
++                                        for o in objs)
++            # Don't bother with a list file if we're only linking objects built
++            # in this directory or building a real static library. This
++            # accommodates clang-plugin, where we would otherwise pass an
++            # incorrect list file format to the host compiler as well as when
++            # creating an archive with AR, which doesn't understand list files.
++            if (objs == obj.objs and not isinstance(obj, StaticLibrary) or
++                isinstance(obj, StaticLibrary) and obj.no_expand_lib):
++                backend_file.write_once('%s_OBJS := %s\n' %
++                                        (obj.name, objs_ref))
++                backend_file.write_once('%s: %s\n' % (obj_target, objs_ref))
++            elif not isinstance(obj, StaticLibrary):
++                list_file_path = '%s.list' % obj.name.replace('.', '_')
++                list_file_ref = self._make_list_file(obj.objdir, objs,
++                                                     list_file_path)
++                backend_file.write_once('%s_OBJS := %s\n' %
++                                        (obj.name, list_file_ref))
++                backend_file.write_once('%s: %s\n' % (obj_target, list_file_path))
++                backend_file.write_once('%s: %s\n' % (obj_target, objs_ref))
++
++        for lib in shared_libs:
++            backend_file.write_once('SHARED_LIBS += %s/%s\n' %
++                                    (pretty_relpath(lib), lib.import_name))
++        for lib in static_libs:
++            backend_file.write_once('STATIC_LIBS += %s/%s\n' %
++                                    (pretty_relpath(lib), lib.import_name))
++        for lib in os_libs:
++            if obj.KIND == 'target':
++                backend_file.write_once('OS_LIBS += %s\n' % lib)
++            else:
++                backend_file.write_once('HOST_EXTRA_LIBS += %s\n' % lib)
++
+         for lib in obj.linked_libraries:
+             if not isinstance(lib, ExternalLibrary):
+                 self._compile_graph[build_target].add(
+                     self._build_target_for_obj(lib))
+-            relpath = pretty_relpath(lib)
+-            if isinstance(obj, Library):
+-                if isinstance(lib, RustLibrary):
+-                    # We don't need to do anything here; we will handle
+-                    # linkage for any RustLibrary elsewhere.
+-                    continue
+-                elif isinstance(lib, StaticLibrary):
+-                    backend_file.write_once('STATIC_LIBS += %s/%s\n'
+-                                        % (relpath, lib.import_name))
+-                    if isinstance(obj, SharedLibrary):
+-                        write_shared_and_system_libs(lib)
+-                elif isinstance(obj, SharedLibrary):
+-                    backend_file.write_once('SHARED_LIBS += %s/%s\n'
+-                                        % (relpath, lib.import_name))
+-            elif isinstance(obj, (Program, SimpleProgram)):
+-                if isinstance(lib, StaticLibrary):
+-                    backend_file.write_once('STATIC_LIBS += %s/%s\n'
+-                                        % (relpath, lib.import_name))
+-                    write_shared_and_system_libs(lib)
+-                else:
+-                    backend_file.write_once('SHARED_LIBS += %s/%s\n'
+-                                        % (relpath, lib.import_name))
+-            elif isinstance(obj, (HostLibrary, HostProgram, HostSimpleProgram)):
+-                assert isinstance(lib, (HostLibrary, HostRustLibrary))
+-                backend_file.write_once('HOST_LIBS += %s/%s\n'
+-                                   % (relpath, lib.import_name))
++            if isinstance(lib, (HostLibrary, HostRustLibrary)):
++                backend_file.write_once('HOST_LIBS += %s/%s\n' %
++                                        (pretty_relpath(lib), lib.import_name))
+ 
+         # We have to link any Rust libraries after all intermediate static
+         # libraries have been listed to ensure that the Rust libraries are
+         # searched after the C/C++ objects that might reference Rust symbols.
+         if isinstance(obj, SharedLibrary):
+             self._process_rust_libraries(obj, backend_file, pretty_relpath)
+ 
+-        for lib in obj.linked_system_libs:
+-            if obj.KIND == 'target':
+-                backend_file.write_once('OS_LIBS += %s\n' % lib)
+-            else:
+-                backend_file.write_once('HOST_EXTRA_LIBS += %s\n' % lib)
+-
+         # Process library-based defines
+         self._process_defines(obj.lib_defines, backend_file)
+ 
+     def _process_rust_libraries(self, obj, backend_file, pretty_relpath):
+         assert isinstance(obj, SharedLibrary)
+ 
+         # If this library does not depend on any Rust libraries, then we are done.
+         direct_linked = [l for l in obj.linked_libraries if isinstance(l, RustLibrary)]
+diff --git a/python/mozbuild/mozbuild/test/backend/common.py b/python/mozbuild/mozbuild/test/backend/common.py
+--- a/python/mozbuild/mozbuild/test/backend/common.py
++++ b/python/mozbuild/mozbuild/test/backend/common.py
+@@ -200,16 +200,17 @@ CONFIGS = defaultdict(lambda: {
+         'defines': {},
+         'non_global_defines': [],
+         'substs': {
+             'COMPILE_ENVIRONMENT': '1',
+             'LIB_SUFFIX': 'a',
+             'BIN_SUFFIX': '.exe',
+             'DLL_SUFFIX': '.so',
+             'OBJ_SUFFIX': 'o',
++            'EXPAND_LIBS_LIST_STYLE': 'list',
+         },
+     },
+ })
+ 
+ 
+ class BackendTester(unittest.TestCase):
+     def setUp(self):
+         self._old_env = dict(os.environ)
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar2.cc b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar2.cc
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar_helper/bar_helper1.cpp b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar_helper/bar_helper1.cpp
+new file mode 100644
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar_helper/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar_helper/moz.build
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/bar_helper/moz.build
+@@ -0,0 +1,8 @@
++# Any copyright is dedicated to the Public Domain.
++# http://creativecommons.org/publicdomain/zero/1.0/
++
++SOURCES += [
++    'bar_helper1.cpp',
++]
++
++FINAL_LIBRARY = 'bar'
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build
+--- a/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build
++++ b/python/mozbuild/mozbuild/test/backend/data/linkage/static/bar/moz.build
+@@ -1,8 +1,13 @@
+ # Any copyright is dedicated to the Public Domain.
+ # http://creativecommons.org/publicdomain/zero/1.0/
+ 
+ SOURCES += [
+     'bar1.cc',
++    'bar2.cc',
++]
++
++DIRS += [
++    'bar_helper',
+ ]
+ 
+ FINAL_LIBRARY = 'bar'
+\ No newline at end of file
+diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
++++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+@@ -986,40 +986,34 @@ class TestRecursiveMakeBackend(BackendTe
+ 
+             for line in lines:
+                 self.assertNotIn('LIB_IS_C_ONLY', line)
+ 
+     def test_linkage(self):
+         env = self._consume('linkage', RecursiveMakeBackend)
+         expected_linkage = {
+             'prog': {
+-                'SHARED_LIBS': ['$(DEPTH)/shared/baz', '$(DEPTH)/prog/qux/qux'],
+-                'STATIC_LIBS': ['$(DEPTH)/static/bar%s' % env.lib_suffix],
++                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux.so',
++                                '$(DEPTH)/shared/baz.so'],
++                'STATIC_LIBS': ['$(DEPTH)/real/foo.a'],
+                 'OS_LIBS': ['-lfoo', '-lbaz', '-lbar'],
+             },
+             'shared': {
+                 'OS_LIBS': ['-lfoo'],
+-                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux'],
+-                'STATIC_LIBS': ['$(DEPTH)/shared/baz/shared_baz%s' %
+-                                env.lib_suffix],
++                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux.so'],
++                'STATIC_LIBS': [],
+             },
+             'static': {
+-                'STATIC_LIBS': [
+-                    '$(DEPTH)/static/bar/static_bar.a',
+-                    '$(DEPTH)/real/foo.a',
+-                ],
++                'STATIC_LIBS': ['$(DEPTH)/real/foo.a'],
+                 'OS_LIBS': ['-lbar'],
+-                'SHARED_LIBS': [],
++                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux.so'],
+             },
+             'real': {
+-                'STATIC_LIBS': [
+-                    '$(DEPTH)/shared/baz_s%s' % env.lib_suffix,
+-                    '$(DEPTH)/real/foo/real_foo%s' % env.lib_suffix,
+-                ],
+-                'SHARED_LIBS': [],
++                'STATIC_LIBS': [],
++                'SHARED_LIBS': ['$(DEPTH)/prog/qux/qux.so'],
+                 'OS_LIBS': ['-lbaz'],
+             }
+         }
+         actual_linkage = {}
+         for name in expected_linkage.keys():
+             with open(os.path.join(env.topobjdir, name, 'backend.mk'), 'rb') as fh:
+                 actual_linkage[name] = [line.rstrip() for line in fh.readlines()]
+         for name in expected_linkage:
+@@ -1027,16 +1021,44 @@ class TestRecursiveMakeBackend(BackendTe
+                 for val in expected_linkage[name][var]:
+                     line = '%s += %s' % (var, val)
+                     self.assertIn(line,
+                                   actual_linkage[name])
+                     actual_linkage[name].remove(line)
+                 for line in actual_linkage[name]:
+                     self.assertNotIn('%s +=' % var, line)
+ 
++    def test_list_files(self):
++        env = self._consume('linkage', RecursiveMakeBackend)
++        expected_list_files = {
++            'prog/MyProgram_exe.list': [
++                '../static/bar/bar1.o',
++                '../static/bar/bar2.o',
++                '../static/bar/bar_helper/bar_helper1.o',
++            ],
++            'shared/baz_so.list': [
++                'baz/baz1.o',
++            ],
++        }
++        actual_list_files = {}
++        for name in expected_list_files.keys():
++            with open(os.path.join(env.topobjdir, name), 'rb') as fh:
++                actual_list_files[name] = [mozpath.normsep(line.rstrip())
++                                           for line in fh.readlines()]
++        for name in expected_list_files:
++            self.assertEqual(actual_list_files[name],
++                             expected_list_files[name])
++
++        # We don't produce a list file for a shared library composed only of
++        # object files in its directory, but instead list them in a variable.
++        with open(os.path.join(env.topobjdir, 'prog', 'qux', 'backend.mk'), 'rb') as fh:
++            lines = [line.rstrip() for line in fh.readlines()]
++
++        self.assertIn('qux.so_OBJS := qux1.o', lines)
++
+     def test_jar_manifests(self):
+         env = self._consume('jar-manifests', RecursiveMakeBackend)
+ 
+         with open(os.path.join(env.topobjdir, 'backend.mk'), 'rb') as fh:
+             lines = fh.readlines()
+ 
+         lines = [line.rstrip() for line in lines]
+ 

+ 313 - 0
bug1240930-253/mozilla/1429875-5-PARTIAL-61a1.patch

@@ -0,0 +1,313 @@
+# HG changeset patch
+# User Chris Manchester <cmanchester@mozilla.com>
+# Date 1521589452 25200
+# Node ID cd90d8ccc5be982afb1bab0a2f2a649e10491817
+# Parent  e52da97ac23e05403df80f3f8b2f6ceef06c27f8
+Bug 1429875 - Implement OBJ_SUFFIX overriding for the profile generation phase on linux in mozbuild. r=glandium
+
+MozReview-Commit-ID: 8PtgxfbxuE
+
+diff --git a/config/config.mk b/config/config.mk
+--- a/config/config.mk
++++ b/config/config.mk
+@@ -436,25 +436,28 @@ endif
+ 
+ # MDDEPDIR is the subdirectory where dependency files are stored
+ MDDEPDIR := .deps
+ 
+ # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
+ # this file
+ OBJ_SUFFIX := $(_OBJ_SUFFIX)
+ 
++OBJS_VAR_SUFFIX := OBJS
++
+ # PGO builds with GCC build objects with instrumentation in a first pass,
+ # then objects optimized, without instrumentation, in a second pass. If
+ # we overwrite the objects from the first pass with those from the second,
+ # we end up not getting instrumentation data for better optimization on
+ # incremental builds. As a consequence, we use a different object suffix
+ # for the first pass.
+-ifndef NO_PROFILE_GUIDED_OPTIMIZE
+ ifdef MOZ_PROFILE_GENERATE
+ ifdef GNU_CC
++OBJS_VAR_SUFFIX := PGO_OBJS
++ifndef NO_PROFILE_GUIDED_OPTIMIZE
+ OBJ_SUFFIX := i_o
+ endif
+ endif
+ endif
+ 
+ PLY_INCLUDE = -I$(MOZILLA_DIR)/other-licenses/ply
+ 
+ export CL_INCLUDES_PREFIX
+diff --git a/config/rules.mk b/config/rules.mk
+--- a/config/rules.mk
++++ b/config/rules.mk
+@@ -535,17 +535,17 @@ endif
+ #
+ # PROGRAM = Foo
+ # creates OBJS, links with LIBS to create Foo
+ #
+ $(PROGRAM): $(PROGOBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(RESFILE) $(GLOBAL_DEPS) $(call mkdir_deps,$(FINAL_TARGET))
+ 	$(REPORT_BUILD)
+ 	@$(RM) $@.manifest
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+-	$(LINKER) -NOLOGO -OUT:$(call LINKER_OUT,$@) -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $($(notdir $@)_OBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
++	$(LINKER) -NOLOGO -OUT:$(call LINKER_OUT,$@) -PDB:$(LINK_PDBFILE) -IMPLIB:$(basename $(@F)).lib $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
+ ifdef MSMANIFEST_TOOL
+ 	@if test -f $@.manifest; then \
+ 		if test -f '$(srcdir)/$(notdir $@).manifest'; then \
+ 			echo 'Embedding manifest from $(srcdir)/$(notdir $@).manifest and $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$(notdir $@).manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		else \
+ 			echo 'Embedding manifest from $@.manifest'; \
+ 			$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+@@ -556,17 +556,17 @@ ifdef MSMANIFEST_TOOL
+ 	fi
+ endif	# MSVC with manifest tool
+ ifdef MOZ_PROFILE_GENERATE
+ # touch it a few seconds into the future to work around FAT's
+ # 2-second granularity
+ 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
+ endif
+ else # !WINNT || GNU_CC
+-	$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $($(notdir $@)_OBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
++	$(call EXPAND_CC_OR_CXX,$@) -o $@ $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) $($(notdir $@)_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ endif # WINNT && !GNU_CC
+ 
+ ifdef ENABLE_STRIP
+ 	$(STRIP) $(STRIP_FLAGS) $@
+ endif
+ ifdef MOZ_POST_PROGRAM_COMMAND
+ 	$(MOZ_POST_PROGRAM_COMMAND) $@
+@@ -607,25 +607,25 @@ endif
+ # Foo.o (from either Foo.c or Foo.cpp).
+ #
+ # SIMPLE_PROGRAMS = Foo Bar
+ # creates Foo.o Bar.o, links with LIBS to create Foo, Bar.
+ #
+ $(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+-	$(LINKER) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $($@_OBJS) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
++	$(LINKER) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $($@_$(OBJS_VAR_SUFFIX)) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
+ ifdef MSMANIFEST_TOOL
+ 	@if test -f $@.manifest; then \
+ 		$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
+ 		rm -f $@.manifest; \
+ 	fi
+ endif	# MSVC with manifest tool
+ else
+-	$(call EXPAND_CC_OR_CXX,$@) $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) -o $@ $($@_OBJS) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
++	$(call EXPAND_CC_OR_CXX,$@) $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) -o $@ $($@_$(OBJS_VAR_SUFFIX)) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ endif # WINNT && !GNU_CC
+ 
+ ifdef ENABLE_STRIP
+ 	$(STRIP) $(STRIP_FLAGS) $@
+ endif
+ ifdef MOZ_POST_PROGRAM_COMMAND
+ 	$(MOZ_POST_PROGRAM_COMMAND) $@
+@@ -644,17 +644,17 @@ endif
+ endif
+ ifndef CROSS_COMPILE
+ 	$(call py_action,check_binary,--host $@)
+ endif
+ 
+ $(LIBRARY): $(OBJS) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ 	$(RM) $(REAL_LIBRARY)
+-	$(AR) $(AR_FLAGS) $(OBJS) $($@_OBJS)
++	$(AR) $(AR_FLAGS) $(OBJS) $($@_$(OBJS_VAR_SUFFIX))
+ 
+ ifeq ($(OS_ARCH),WINNT)
+ # Import libraries are created by the rules creating shared libraries.
+ # The rules to copy them to $(DIST)/lib depend on $(IMPORT_LIBRARY),
+ # but make will happily consider the import library before it is refreshed
+ # when rebuilding the corresponding shared library. Defining an empty recipe
+ # for import libraries forces make to wait for the shared library recipe to
+ # have run before considering other targets that depend on the import library.
+@@ -672,17 +672,17 @@ endif
+ # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
+ # so no need to conditionalize on OS version or debugging format.
+ 
+ $(SHARED_LIBRARY): $(OBJS) $(RESFILE) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
+ 	$(REPORT_BUILD)
+ ifndef INCREMENTAL_LINKER
+ 	$(RM) $@
+ endif
+-	$(MKSHLIB) $($@_OBJS) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
++	$(MKSHLIB) $($@_$(OBJS_VAR_SUFFIX)) $(RESFILE) $(LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
+ 	$(call py_action,check_binary,--target $@)
+ 
+ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
+ ifdef MSMANIFEST_TOOL
+ ifdef EMBED_MANIFEST_AT
+ 	@if test -f $@.manifest; then \
+ 		if test -f '$(srcdir)/$@.manifest'; then \
+ 			echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
+diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py
+--- a/python/mozbuild/mozbuild/backend/common.py
++++ b/python/mozbuild/mozbuild/backend/common.py
+@@ -361,25 +361,31 @@ class CommonBackend(BuildBackend):
+             }
+             json.dump(d, fh, sort_keys=True, indent=4)
+ 
+     def _expand_libs(self, input_bin):
+         os_libs = []
+         shared_libs = []
+         static_libs = []
+         objs = []
++        no_pgo_objs = []
+ 
+         seen_objs = set()
+         seen_libs = set()
+ 
+         def add_objs(lib):
+             for o in lib.objs:
+                 if o not in seen_objs:
+                     seen_objs.add(o)
+                     objs.append(o)
++                    # This is slightly odd, buf for consistency with the
++                    # recursivemake backend we don't replace OBJ_SUFFIX if any
++                    # object in a library has `no_pgo` set.
++                    if lib.no_pgo_objs or lib.no_pgo:
++                        no_pgo_objs.append(o)
+ 
+         def expand(lib, recurse_objs, system_libs):
+             if isinstance(lib, StaticLibrary):
+                 if lib.no_expand_lib:
+                     static_libs.append(lib)
+                     recurse_objs = False
+                 elif recurse_objs:
+                     add_objs(lib)
+@@ -411,17 +417,17 @@ class CommonBackend(BuildBackend):
+                     seen_libs.add(lib)
+                     shared_libs.append(lib)
+ 
+         for lib in input_bin.linked_system_libs:
+             if lib not in seen_libs:
+                 seen_libs.add(lib)
+                 os_libs.append(lib)
+ 
+-        return objs, shared_libs, os_libs, static_libs
++        return objs, no_pgo_objs, shared_libs, os_libs, static_libs
+ 
+     def _make_list_file(self, objdir, objs, name):
+         if not objs:
+             return None
+         list_style = self.environment.substs.get('EXPAND_LIBS_LIST_STYLE')
+         list_file_path = mozpath.join(objdir, name)
+         objs = [os.path.relpath(o, objdir) for o in objs]
+         if list_style == 'linkerscript':
+diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py
+--- a/python/mozbuild/mozbuild/backend/recursivemake.py
++++ b/python/mozbuild/mozbuild/backend/recursivemake.py
+@@ -1290,43 +1290,78 @@ class RecursiveMakeBackend(CommonBackend
+         def pretty_relpath(lib):
+             return '$(DEPTH)/%s' % mozpath.relpath(lib.objdir, topobjdir)
+ 
+         topobjdir = mozpath.normsep(obj.topobjdir)
+         # This will create the node even if there aren't any linked libraries.
+         build_target = self._build_target_for_obj(obj)
+         self._compile_graph[build_target]
+ 
+-        objs, shared_libs, os_libs, static_libs = self._expand_libs(obj)
++        objs, no_pgo_objs, shared_libs, os_libs, static_libs = self._expand_libs(obj)
+ 
+         if obj.KIND == 'target':
+             obj_target = obj.name
+             if isinstance(obj, Program):
+                 obj_target = self._pretty_path(obj.output_path, backend_file)
+ 
++            is_unit_test = isinstance(obj, BaseProgram) and obj.is_unit_test
++            profile_gen_objs = []
++
++            if (self.environment.substs.get('MOZ_PGO') and
++                self.environment.substs.get('GNU_CC')):
++                # We use a different OBJ_SUFFIX for the profile generate phase on
++                # linux. These get picked up via OBJS_VAR_SUFFIX in config.mk.
++                if not is_unit_test and not isinstance(obj, SimpleProgram):
++                    profile_gen_objs = [o if o in no_pgo_objs else '%s.%s' %
++                                        (mozpath.splitext(o)[0], 'i_o') for o in objs]
++
++            def write_obj_deps(target, objs_ref, pgo_objs_ref):
++                if pgo_objs_ref:
++                    backend_file.write('ifdef MOZ_PROFILE_GENERATE\n')
++                    backend_file.write('%s: %s\n' % (target, pgo_objs_ref))
++                    backend_file.write('else\n')
++                    backend_file.write('%s: %s\n' % (target, objs_ref))
++                    backend_file.write('endif\n')
++                else:
++                    backend_file.write('%s: %s\n' % (target, objs_ref))
++
+             objs_ref = ' \\\n    '.join(os.path.relpath(o, obj.objdir)
+                                         for o in objs)
++            pgo_objs_ref = ' \\\n    '.join(os.path.relpath(o, obj.objdir)
++                                            for o in profile_gen_objs)
+             # Don't bother with a list file if we're only linking objects built
+             # in this directory or building a real static library. This
+             # accommodates clang-plugin, where we would otherwise pass an
+             # incorrect list file format to the host compiler as well as when
+             # creating an archive with AR, which doesn't understand list files.
+             if (objs == obj.objs and not isinstance(obj, StaticLibrary) or
+-                isinstance(obj, StaticLibrary) and obj.no_expand_lib):
+-                backend_file.write_once('%s_OBJS := %s\n' %
+-                                        (obj.name, objs_ref))
+-                backend_file.write_once('%s: %s\n' % (obj_target, objs_ref))
++              isinstance(obj, StaticLibrary) and obj.no_expand_lib):
++                backend_file.write_once('%s_OBJS := %s\n' % (obj.name,
++                                                             objs_ref))
++                if profile_gen_objs:
++                    backend_file.write_once('%s_PGO_OBJS := %s\n' % (obj.name,
++                                                                     pgo_objs_ref))
++                write_obj_deps(obj_target, objs_ref, pgo_objs_ref)
+             elif not isinstance(obj, StaticLibrary):
+                 list_file_path = '%s.list' % obj.name.replace('.', '_')
+                 list_file_ref = self._make_list_file(obj.objdir, objs,
+                                                      list_file_path)
+                 backend_file.write_once('%s_OBJS := %s\n' %
+                                         (obj.name, list_file_ref))
+                 backend_file.write_once('%s: %s\n' % (obj_target, list_file_path))
+-                backend_file.write_once('%s: %s\n' % (obj_target, objs_ref))
++                if profile_gen_objs:
++                    pgo_list_file_path = '%s_pgo.list' % obj.name.replace('.', '_')
++                    pgo_list_file_ref = self._make_list_file(obj.objdir,
++                                                             profile_gen_objs,
++                                                             pgo_list_file_path)
++                    backend_file.write_once('%s_PGO_OBJS := %s\n' %
++                                            (obj.name, pgo_list_file_ref))
++                    backend_file.write_once('%s: %s\n' % (obj_target,
++                                                          pgo_list_file_path))
++                write_obj_deps(obj_target, objs_ref, pgo_objs_ref)
+ 
+         for lib in shared_libs:
+             backend_file.write_once('SHARED_LIBS += %s/%s\n' %
+                                     (pretty_relpath(lib), lib.import_name))
+         for lib in static_libs:
+             backend_file.write_once('STATIC_LIBS += %s/%s\n' %
+                                     (pretty_relpath(lib), lib.import_name))
+         for lib in os_libs:
+diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py
+--- a/python/mozbuild/mozbuild/frontend/data.py
++++ b/python/mozbuild/mozbuild/frontend/data.py
+@@ -347,16 +347,18 @@ class LinkageMultipleRustLibrariesError(
+ 
+ class Linkable(ContextDerived):
+     """Generic context derived container object for programs and libraries"""
+     __slots__ = (
+         'cxx_link',
+         'lib_defines',
+         'linked_libraries',
+         'linked_system_libs',
++        'no_pgo_sources',
++        'no_pgo',
+     )
+ 
+     def __init__(self, context):
+         ContextDerived.__init__(self, context)
+         self.cxx_link = False
+         self.linked_libraries = []
+         self.linked_system_libs = []
+         self.lib_defines = Defines(context, {})

+ 1 - 8
bug1240930-253/mozilla/series-append

@@ -1,15 +1,8 @@
-1443204-1only-60a1.patch
-1255485-1-61a1.patch
-1255485-2-61a1.patch
-1255485-3-61a1.patch
-1255485-4-61a1.patch
-1255485-5-61a1.patch
-1255485-6-61a1.patch
 1429875-1-61a1.patch
 1429875-2-61a1.patch
 1429875-3-61a1.patch
 1429875-4-61a1.patch
-1429875-5-61a1.patch
+1429875-5-PARTIAL-61a1.patch
 1443208-1only-62a1.patch
 1455504-62a1.patch
 1454912-2no1-62a1.patch