|
@@ -1,1777 +0,0 @@
|
|
-# HG changeset patch
|
|
|
|
-# User Chris Manchester <cmanchester@mozilla.com>
|
|
|
|
-# Date 1521588665 25200
|
|
|
|
-# Node ID 7547d66e0f518d20f61b492eac027d5a34ac6fb4
|
|
|
|
-# Parent 69a2fcd14b36bab49849d2f63507b8ad7e0b0a7c
|
|
|
|
-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
|
|
|
|
-@@ -411,28 +411,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
|
|
|
|
-@@ -426,32 +425,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
|
|
|
|
-@@ -525,35 +527,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'; \
|
|
|
|
-@@ -565,140 +567,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) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE)
|
|
|
|
-+ $(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) $(EXTRA_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) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS)
|
|
|
|
-+ $(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) $(filter %.$(LIB_SUFFIX),$(EXTRA_LIBS)) $(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 %.$(LIB_SUFFIX),$(EXTRA_LIBS))
|
|
|
|
--
|
|
|
|
--$(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(STATIC_LIBS_DEPS) $(filter %.$(LIB_SUFFIX),$(EXTRA_LIBS)) $(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) $(filter %.$(LIB_SUFFIX),$(EXTRA_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) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE)
|
|
|
|
-+ $(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
|
|
|
|
-@@ -1307,77 +1307,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
|
|
|
|
-@@ -209,16 +209,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]
|
|
|
|
-
|
|
|