mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1041936 - Allow static library definitions to depend on shared libraries. r=gps
This commit is contained in:
parent
d78e98cd89
commit
ad2b8b8346
@ -68,6 +68,10 @@ Note that currently, the build system may not create an actual library for
|
||||
static libraries. It is an implementation detail that shouldn't need to be
|
||||
worried about.
|
||||
|
||||
As a special rule, USE_LIBS is allowed to contain references to shared
|
||||
libraries. In such cases, programs and shared libraries linking this static
|
||||
library will inherit those shared library dependencies.
|
||||
|
||||
|
||||
Intermediate (Static) Libraries
|
||||
===============================
|
||||
|
@ -136,12 +136,17 @@ endif # ENABLE_TESTS
|
||||
|
||||
ifndef LIBRARY
|
||||
ifdef REAL_LIBRARY
|
||||
# Don't build actual static library if a shared library is also built
|
||||
ifdef FORCE_SHARED_LIB
|
||||
LIBRARY := $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
|
||||
else
|
||||
# Only build actual library if it is installed in DIST/lib or SDK
|
||||
ifeq (,$(SDK_LIBRARY)$(DIST_INSTALL)$(NO_EXPAND_LIBS))
|
||||
LIBRARY := $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
|
||||
else
|
||||
LIBRARY := $(REAL_LIBRARY) $(REAL_LIBRARY).$(LIBS_DESC_SUFFIX)
|
||||
endif
|
||||
endif
|
||||
endif # REAL_LIBRARY
|
||||
endif # LIBRARY
|
||||
|
||||
|
@ -1145,20 +1145,33 @@ class RecursiveMakeBackend(CommonBackend):
|
||||
backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
|
||||
|
||||
def _process_linked_libraries(self, obj, backend_file):
|
||||
topobjdir = mozpath.normsep(obj.topobjdir)
|
||||
for lib in obj.linked_libraries:
|
||||
def recurse_lib(lib):
|
||||
for l in lib.linked_libraries:
|
||||
if isinstance(l, StaticLibrary):
|
||||
for q in recurse_lib(l):
|
||||
yield q
|
||||
else:
|
||||
yield l
|
||||
|
||||
def pretty_relpath(lib):
|
||||
# If this is an external objdir (i.e., comm-central), use the other
|
||||
# directory instead of $(DEPTH).
|
||||
if lib.objdir.startswith(topobjdir + '/'):
|
||||
relpath = '$(DEPTH)/%s' % mozpath.relpath(lib.objdir, topobjdir)
|
||||
return '$(DEPTH)/%s' % mozpath.relpath(lib.objdir, topobjdir)
|
||||
else:
|
||||
relpath = mozpath.relpath(lib.objdir, obj.objdir)
|
||||
return mozpath.relpath(lib.objdir, obj.objdir)
|
||||
|
||||
topobjdir = mozpath.normsep(obj.topobjdir)
|
||||
for lib in obj.linked_libraries:
|
||||
relpath = pretty_relpath(lib)
|
||||
if isinstance(obj, Library):
|
||||
if isinstance(lib, StaticLibrary):
|
||||
backend_file.write_once('SHARED_LIBRARY_LIBS += %s/%s\n'
|
||||
% (relpath, lib.lib_name))
|
||||
else:
|
||||
assert isinstance(obj, SharedLibrary)
|
||||
for l in recurse_lib(lib):
|
||||
backend_file.write_once('EXTRA_DSO_LDOPTS += %s/%s\n'
|
||||
% (pretty_relpath(l), l.import_name))
|
||||
elif isinstance(obj, SharedLibrary):
|
||||
assert lib.variant != lib.COMPONENT
|
||||
backend_file.write_once('EXTRA_DSO_LDOPTS += %s/%s\n'
|
||||
% (relpath, lib.import_name))
|
||||
@ -1166,6 +1179,13 @@ class RecursiveMakeBackend(CommonBackend):
|
||||
if isinstance(lib, StaticLibrary):
|
||||
backend_file.write_once('LIBS += %s/%s\n'
|
||||
% (relpath, lib.lib_name))
|
||||
for l in recurse_lib(lib):
|
||||
backend_file.write_once('LIBS += %s/%s\n'
|
||||
% (pretty_relpath(l), l.import_name))
|
||||
elif isinstance(obj, SharedLibrary):
|
||||
assert lib.variant != lib.COMPONENT
|
||||
backend_file.write_once('EXTRA_DSO_LDOPTS += %s/%s\n'
|
||||
% (relpath, lib.import_name))
|
||||
else:
|
||||
assert lib.variant != lib.COMPONENT
|
||||
backend_file.write_once('LIBS += %s/%s\n'
|
||||
|
@ -348,7 +348,7 @@ class Linkable(SandboxDerived):
|
||||
if obj.KIND != self.KIND:
|
||||
raise LinkageWrongKindError('%s != %s' % (obj.KIND, self.KIND))
|
||||
self.linked_libraries.append(obj)
|
||||
obj.refcount += 1
|
||||
obj.refs.append(self)
|
||||
|
||||
|
||||
class BaseProgram(Linkable):
|
||||
@ -402,7 +402,7 @@ class BaseLibrary(Linkable):
|
||||
'basename',
|
||||
'lib_name',
|
||||
'import_name',
|
||||
'refcount',
|
||||
'refs',
|
||||
)
|
||||
|
||||
def __init__(self, sandbox, basename):
|
||||
@ -417,7 +417,7 @@ class BaseLibrary(Linkable):
|
||||
)
|
||||
self.import_name = self.lib_name
|
||||
|
||||
self.refcount = 0
|
||||
self.refs = []
|
||||
|
||||
|
||||
class Library(BaseLibrary):
|
||||
|
@ -93,6 +93,7 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
self._libs = OrderedDefaultDict(list)
|
||||
self._binaries = OrderedDict()
|
||||
self._linkage = []
|
||||
self._static_linking_shared = set()
|
||||
|
||||
def emit(self, output):
|
||||
"""Convert the BuildReader output into data structures.
|
||||
@ -139,22 +140,56 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
yield ReaderSummary(file_count, sandbox_execution_time, emitter_time)
|
||||
|
||||
def _emit_libs_derived(self, sandboxes):
|
||||
for sandbox, obj, variable in self._linkage:
|
||||
self._link_libraries(sandbox, obj, variable)
|
||||
|
||||
# First do FINAL_LIBRARY linkage.
|
||||
for lib in (l for libs in self._libs.values() for l in libs):
|
||||
if not isinstance(lib, StaticLibrary) or not lib.link_into:
|
||||
continue
|
||||
if lib.link_into not in self._libs:
|
||||
raise Exception('FINAL_LIBRARY in %s (%s) does not match any '
|
||||
'LIBRARY_NAME' % (lib.objdir, lib.link_info))
|
||||
raise SandboxValidationError(
|
||||
'FINAL_LIBRARY ("%s") does not match any LIBRARY_NAME'
|
||||
% lib.link_into, sandboxes[lib.objdir])
|
||||
candidates = self._libs[lib.link_into]
|
||||
if len(candidates) > 1:
|
||||
raise Exception('FINAL_LIBRARY in %s (%s) matches a '
|
||||
'LIBRARY_NAME defined in multiple places (%s)' %
|
||||
(lib.objdir, lib.link_into,
|
||||
', '.join(l.objdir for l in candidates)))
|
||||
candidates[0].link_library(lib)
|
||||
|
||||
# When there are multiple candidates, but all are in the same
|
||||
# directory and have a different type, we want all of them to
|
||||
# have the library linked. The typical usecase is when building
|
||||
# both a static and a shared library in a directory, and having
|
||||
# that as a FINAL_LIBRARY.
|
||||
if len(set(type(l) for l in candidates)) == len(candidates) and \
|
||||
len(set(l.objdir for l in candidates)) == 1:
|
||||
for c in candidates:
|
||||
c.link_library(lib)
|
||||
else:
|
||||
raise SandboxValidationError(
|
||||
'FINAL_LIBRARY ("%s") matches a LIBRARY_NAME defined in '
|
||||
'multiple places:\n %s' % (lib.link_into,
|
||||
'\n '.join(l.objdir for l in candidates)),
|
||||
sandboxes[lib.objdir])
|
||||
|
||||
# Next, USE_LIBS linkage.
|
||||
for sandbox, obj, variable in self._linkage:
|
||||
self._link_libraries(sandbox, obj, variable)
|
||||
|
||||
def recurse_refs(lib):
|
||||
for o in lib.refs:
|
||||
yield o
|
||||
if isinstance(o, StaticLibrary):
|
||||
for q in recurse_refs(o):
|
||||
yield q
|
||||
|
||||
# Check that all static libraries refering shared libraries in
|
||||
# USE_LIBS are linked into a shared library or program.
|
||||
for lib in self._static_linking_shared:
|
||||
if all(isinstance(o, StaticLibrary) for o in recurse_refs(lib)):
|
||||
shared_libs = sorted(l.basename for l in lib.linked_libraries
|
||||
if isinstance(l, SharedLibrary))
|
||||
raise SandboxValidationError(
|
||||
'The static "%s" library is not used in a shared library '
|
||||
'or a program, but USE_LIBS contains the following shared '
|
||||
'library names:\n %s\n\nMaybe you can remove the '
|
||||
'static "%s" library?' % (lib.basename,
|
||||
'\n '.join(shared_libs), lib.basename),
|
||||
sandboxes[lib.objdir])
|
||||
|
||||
def recurse_libs(lib):
|
||||
for obj in lib.linked_libraries:
|
||||
@ -164,6 +199,7 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
for q in recurse_libs(obj):
|
||||
yield q
|
||||
|
||||
sent_passthru = set()
|
||||
for lib in (l for libs in self._libs.values() for l in libs):
|
||||
# For all root libraries (i.e. libraries that don't have a
|
||||
# FINAL_LIBRARY), record, for each static library it links
|
||||
@ -171,6 +207,9 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
if isinstance(lib, Library):
|
||||
if isinstance(lib, SharedLibrary) or not lib.link_into:
|
||||
for p in recurse_libs(lib):
|
||||
if p in sent_passthru:
|
||||
continue
|
||||
sent_passthru.add(p)
|
||||
passthru = VariablePassthru(sandboxes[p])
|
||||
passthru.variables['FINAL_LIBRARY'] = lib.basename
|
||||
yield passthru
|
||||
@ -261,13 +300,7 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
|
||||
elif isinstance(obj, StaticLibrary) and isinstance(candidates[0],
|
||||
SharedLibrary):
|
||||
raise SandboxValidationError(
|
||||
'%s contains "%s", but there is only a shared "%s" '
|
||||
'in %s, and "%s" is built static. You may want to '
|
||||
'add FORCE_STATIC_LIB=True in %s/moz.build, or remove '
|
||||
'"%s" from USE_LIBS.' % (variable, path, name,
|
||||
candidates[0].relobjdir, obj.basename,
|
||||
candidates[0].relobjdir, path), sandbox)
|
||||
self._static_linking_shared.add(obj)
|
||||
obj.link_library(candidates[0])
|
||||
|
||||
def emit_from_sandbox(self, sandbox):
|
||||
@ -559,10 +592,6 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
raise SandboxValidationError(
|
||||
'IS_FRAMEWORK implies FORCE_SHARED_LIB. '
|
||||
'Please remove the latter.', sandbox)
|
||||
if static_lib:
|
||||
raise SandboxValidationError(
|
||||
'IS_FRAMEWORK conflicts with FORCE_STATIC_LIB. '
|
||||
'Please remove one.', sandbox)
|
||||
if soname:
|
||||
raise SandboxValidationError(
|
||||
'IS_FRAMEWORK conflicts with SONAME. '
|
||||
|
Loading…
Reference in New Issue
Block a user