Bug 1386876 - Add classes to handle compile flags computed by moz.build with templates, convert 'DISABLE_STL_WRAPPING' to use them. r=glandium

MozReview-Commit-ID: 3PYOtX4E8OC

--HG--
extra : rebase_source : 162999582bc2ef078680ce6feae628d5b1f4e857
This commit is contained in:
Chris Manchester 2017-04-28 16:35:19 -07:00
Родитель cea42033ef
Коммит e059037e2b
23 изменённых файлов: 204 добавлений и 44 удалений

Просмотреть файл

@ -101,7 +101,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
DISABLE_STL_WRAPPING = True
DisableStlWrapping()
if CONFIG['MOZ_LINKER']:
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']

Просмотреть файл

@ -146,6 +146,10 @@ def HostRustLibrary(name, features=None):
if features:
HOST_RUST_LIBRARY_FEATURES = features
@template
def DisableStlWrapping():
COMPILE_FLAGS['STL'] = []
include('gecko_templates.mozbuild')
include('test_templates.mozbuild')

Просмотреть файл

@ -329,7 +329,7 @@ CFLAGS += $(WARNINGS_AS_ERRORS)
endif # ALLOW_COMPILER_WARNINGS
COMPILE_CFLAGS = $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CXXFLAGS = $(if $(DISABLE_STL_WRAPPING),,$(STL_FLAGS)) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(MK_COMPILE_DEFINES)
COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
ASFLAGS += $(MOZBUILD_ASFLAGS)

Просмотреть файл

@ -368,7 +368,7 @@ AC_SUBST(GNU_AS)
AC_SUBST(GNU_CC)
AC_SUBST(GNU_CXX)
AC_SUBST(STL_FLAGS)
AC_SUBST_LIST(STL_FLAGS)
AC_SUBST(WRAP_STL_INCLUDES)
AC_SUBST(MOZ_MSVC_STL_WRAP_RAISE)

Просмотреть файл

@ -36,6 +36,7 @@ from ..frontend.data import (
BaseLibrary,
BaseProgram,
ChromeManifestEntry,
ComputedFlags,
ConfigFileSubstitution,
ContextDerived,
ContextWrapped,
@ -594,6 +595,9 @@ class RecursiveMakeBackend(CommonBackend):
elif isinstance(obj, PerSourceFlag):
self._process_per_source_flag(obj, backend_file)
elif isinstance(obj, ComputedFlags):
self._process_computed_flags(obj, backend_file)
elif isinstance(obj, InstallationTarget):
self._process_installation_target(obj, backend_file)
@ -1214,6 +1218,10 @@ class RecursiveMakeBackend(CommonBackend):
for flag in per_source_flag.flags:
backend_file.write('%s_FLAGS += %s\n' % (mozpath.basename(per_source_flag.file_name), flag))
def _process_computed_flags(self, computed_flags, backend_file):
for var, flags in computed_flags.get_flags():
backend_file.write('COMPUTED_%s += %s\n' % (var, make_quote(' '.join(flags))))
def _process_java_jar_data(self, jar, backend_file):
target = jar.name
backend_file.write('JAVA_JAR_TARGETS += %s\n' % target)

Просмотреть файл

@ -10,6 +10,7 @@ import types
from mozbuild.compilation import util
from mozbuild.backend.common import CommonBackend
from mozbuild.frontend.data import (
ComputedFlags,
Sources,
GeneratedSources,
DirectoryTraversal,
@ -70,7 +71,7 @@ class CompileDBBackend(CommonBackend):
if isinstance(obj, DirectoryTraversal):
self._envs[obj.objdir] = obj.config
for var in ('STL_FLAGS', 'VISIBILITY_FLAGS', 'WARNINGS_AS_ERRORS'):
for var in ('VISIBILITY_FLAGS', 'WARNINGS_AS_ERRORS'):
value = obj.config.substs.get(var)
if value:
self._local_flags[obj.objdir][var] = value
@ -105,9 +106,6 @@ class CompileDBBackend(CommonBackend):
'RTL_FLAGS', 'VISIBILITY_FLAGS'):
if var in obj.variables:
self._local_flags[obj.objdir][var] = obj.variables[var]
if (obj.variables.get('DISABLE_STL_WRAPPING') and
'STL_FLAGS' in self._local_flags[obj.objdir]):
del self._local_flags[obj.objdir]['STL_FLAGS']
if (obj.variables.get('ALLOW_COMPILER_WARNINGS') and
'WARNINGS_AS_ERRORS' in self._local_flags[obj.objdir]):
del self._local_flags[obj.objdir]['WARNINGS_AS_ERRORS']
@ -115,6 +113,10 @@ class CompileDBBackend(CommonBackend):
elif isinstance(obj, PerSourceFlag):
self._per_source_flags[obj.file_name].extend(obj.flags)
elif isinstance(obj, ComputedFlags):
for var, flags in obj.get_flags():
self._local_flags[obj.objdir]['COMPUTED_%s' % var] = flags
return True
def consume_finished(self):
@ -235,7 +237,7 @@ class CompileDBBackend(CommonBackend):
db.extend(value)
if canonical_suffix in ('.mm', '.cpp'):
db.append('$(STL_FLAGS)')
db.append('$(COMPUTED_CXXFLAGS)')
db.extend((
'$(VISIBILITY_FLAGS)',

Просмотреть файл

@ -297,6 +297,26 @@ class InitializedDefines(ContextDerivedValue, OrderedDict):
self.update(value)
class CompileFlags(ContextDerivedValue, dict):
def __init__(self, context):
self.flag_variables = (
('STL', context.config.substs.get('STL_FLAGS'), ('CXXFLAGS',)),
)
self._known_keys = set(k for k, v, _ in self.flag_variables)
dict.__init__(self,
((k, TypedList(unicode)(v)) for k, v, _ in self.flag_variables))
def __setitem__(self, key, value):
if key not in self._known_keys:
raise ValueError('Invalid value. `%s` is not a compile flags '
'category.' % key)
if not (isinstance(value, list) and all(isinstance(v, unicode) for v in value)):
raise ValueError('A list of strings must be provided as a value for a '
'compile flags category.')
dict.__setitem__(self, key, value)
class FinalTargetValue(ContextDerivedValue, unicode):
def __new__(cls, context, value=""):
if not value:
@ -1688,6 +1708,11 @@ VARIABLES = {
"""Directories containing Python packages that Sphinx documents.
"""),
'COMPILE_FLAGS': (CompileFlags, dict,
"""Recipe for compile flags for this context. Not to be manipulated
directly.
"""),
'CFLAGS': (List, list,
"""Flags passed to the C compiler for all of the C source files
declared in this directory.

Просмотреть файл

@ -23,6 +23,8 @@ from mozpack.chrome.manifest import ManifestEntry
import mozpack.path as mozpath
from .context import FinalTargetValue
from collections import defaultdict, OrderedDict
from ..util import (
group_unified_files,
)
@ -157,6 +159,25 @@ class VariablePassthru(ContextDerived):
ContextDerived.__init__(self, context)
self.variables = {}
class ComputedFlags(ContextDerived):
"""Aggregate flags for consumption by various backends.
"""
__slots__ = ('flags',)
def __init__(self, context, reader_flags):
ContextDerived.__init__(self, context)
self.flags = reader_flags
def get_flags(self):
flags = defaultdict(list)
for key, _, dest_vars in self.flags.flag_variables:
value = self.flags.get(key)
if value:
for dest_var in dest_vars:
flags[dest_var].extend(value)
return flags.items()
class XPIDLFile(ContextDerived):
"""Describes an XPIDL file to be compiled."""

Просмотреть файл

@ -30,6 +30,7 @@ from .data import (
BaseSources,
BrandingFiles,
ChromeManifestEntry,
ComputedFlags,
ConfigFileSubstitution,
ContextWrapped,
Defines,
@ -128,6 +129,7 @@ class TreeMetadataEmitter(LoggingMixin):
self._libs = OrderedDefaultDict(list)
self._binaries = OrderedDict()
self._compile_dirs = set()
self._linkage = []
self._static_linking_shared = set()
self._crate_verified_local = set()
@ -757,6 +759,8 @@ class TreeMetadataEmitter(LoggingMixin):
if not (linkables or host_linkables):
return
self._compile_dirs.add(context.objdir)
sources = defaultdict(list)
gen_sources = defaultdict(list)
all_flags = {}
@ -905,7 +909,6 @@ class TreeMetadataEmitter(LoggingMixin):
'ANDROID_APK_NAME',
'ANDROID_APK_PACKAGE',
'ANDROID_GENERATED_RESFILES',
'DISABLE_STL_WRAPPING',
'EXTRA_DSO_LDOPTS',
'RCFILE',
'RESFILE',
@ -1133,6 +1136,9 @@ class TreeMetadataEmitter(LoggingMixin):
if passthru.variables:
yield passthru
if context.objdir in self._compile_dirs:
yield ComputedFlags(context, context['COMPILE_FLAGS'])
def _create_substitution(self, cls, context, path):
sub = cls(context)
sub.input_path = '%s.in' % path.full_path

Просмотреть файл

@ -326,7 +326,7 @@ def process_gyp_result(gyp_result, gyp_dir_attrs, path, config, output,
if config.substs['OS_TARGET'] == 'WINNT':
context['DEFINES']['UNICODE'] = True
context['DEFINES']['_UNICODE'] = True
context['DISABLE_STL_WRAPPING'] = True
context['COMPILE_FLAGS']['STL'] = []
for key, value in gyp_dir_attrs.sandbox_vars.items():
if context.get(key) and isinstance(context[key], list):

Просмотреть файл

@ -18,6 +18,4 @@ HOST_CFLAGS += ['-funroll-loops', '-wall']
HOST_CXXFLAGS += ['-funroll-loops-harder', '-wall-day-everyday']
WIN32_EXE_LDFLAGS += ['-subsystem:console']
DISABLE_STL_WRAPPING = True
ALLOW_COMPILER_WARNINGS = True

Просмотреть файл

@ -319,9 +319,6 @@ class TestRecursiveMakeBackend(BackendTester):
'ALLOW_COMPILER_WARNINGS': [
'ALLOW_COMPILER_WARNINGS := 1',
],
'DISABLE_STL_WRAPPING': [
'DISABLE_STL_WRAPPING := 1',
],
'VISIBILITY_FLAGS': [
'VISIBILITY_FLAGS :=',
],

Просмотреть файл

@ -35,8 +35,13 @@ class MockConfig(object):
'DLL_SUFFIX': '.so'
}, **extra_substs)
self.substs_unicode = ReadOnlyDict({k.decode('utf-8'): v.decode('utf-8',
'replace') for k, v in self.substs.items()})
def decode_value(value):
if isinstance(value, list):
return [v.decode('utf-8', 'replace') for v in value]
return value.decode('utf-8', 'replace')
self.substs_unicode = ReadOnlyDict({k.decode('utf-8'): decode_value(v)
for k, v in self.substs.items()})
self.defines = self.substs

Просмотреть файл

@ -0,0 +1,13 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
@template
def Library(name):
'''Template for libraries.'''
LIBRARY_NAME = name
Library('dummy')
COMPILE_FLAGS['STL_FLAGS'] = []
UNIFIED_SOURCES += ['test1.c']

Просмотреть файл

Просмотреть файл

@ -0,0 +1,13 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
@template
def Library(name):
'''Template for libraries.'''
LIBRARY_NAME = name
Library('dummy')
COMPILE_FLAGS['STL'] = [None, 123]
UNIFIED_SOURCES += ['test1.c']

Просмотреть файл

Просмотреть файл

@ -0,0 +1,15 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
@template
def Library(name):
'''Template for libraries.'''
LIBRARY_NAME = name
Library('dummy')
@template
def DisableStlWrapping():
COMPILE_FLAGS['STL'] = []
UNIFIED_SOURCES += ['test1.c']

Просмотреть файл

Просмотреть файл

@ -0,0 +1,17 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
@template
def Library(name):
'''Template for libraries.'''
LIBRARY_NAME = name
Library('dummy')
@template
def DisableStlWrapping():
COMPILE_FLAGS['STL'] = []
UNIFIED_SOURCES += ['test1.c']
DisableStlWrapping()

Просмотреть файл

Просмотреть файл

@ -20,6 +20,4 @@ HOST_CFLAGS += ['-funroll-loops', '-wall']
HOST_CXXFLAGS += ['-funroll-loops-harder', '-wall-day-everyday']
WIN32_EXE_LDFLAGS += ['-subsystem:console']
DISABLE_STL_WRAPPING = True
ALLOW_COMPILER_WARNINGS = True

Просмотреть файл

@ -17,6 +17,7 @@ from mozbuild.frontend.data import (
AndroidResDirs,
BrandingFiles,
ChromeManifestEntry,
ComputedFlags,
ConfigFileSubstitution,
Defines,
DirectoryTraversal,
@ -180,7 +181,6 @@ class TestEmitterBasic(unittest.TestCase):
wanted = {
'ALLOW_COMPILER_WARNINGS': True,
'DISABLE_STL_WRAPPING': True,
'NO_DIST_INSTALL': True,
'VISIBILITY_FLAGS': '',
'RCFILE': 'foo.rc',
@ -203,6 +203,32 @@ class TestEmitterBasic(unittest.TestCase):
self.assertEqual(wanted, variables)
self.maxDiff = maxDiff
def test_compile_flags(self):
reader = self.reader('compile-flags',
extra_substs={'STL_FLAGS': ['-I/path/to/objdir/dist/stl_wrappers']})
sources, flags, lib = self.read_topsrcdir(reader)
self.assertIsInstance(flags, ComputedFlags)
self.assertEqual(flags.flags['STL'], reader.config.substs['STL_FLAGS'])
def test_compile_flags_validation(self):
reader = self.reader('compile-flags-field-validation')
with self.assertRaisesRegexp(BuildReaderError, 'Invalid value.'):
self.read_topsrcdir(reader)
reader = self.reader('compile-flags-type-validation')
with self.assertRaisesRegexp(BuildReaderError,
'A list of strings must be provided'):
self.read_topsrcdir(reader)
def test_disable_stl_wrapping(self):
reader = self.reader('disable-stl-wrapping',
extra_substs={'STL_FLAGS': ['-I/path/to/objdir/dist/stl_wrappers']})
sources, flags, lib = self.read_topsrcdir(reader)
self.assertIsInstance(flags, ComputedFlags)
self.assertEqual(flags.flags['STL'], [])
def test_use_yasm(self):
# When yasm is not available, this should raise.
reader = self.reader('use-yasm')
@ -386,14 +412,15 @@ class TestEmitterBasic(unittest.TestCase):
reader = self.reader('program')
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 3)
self.assertIsInstance(objs[0], Program)
self.assertIsInstance(objs[1], SimpleProgram)
self.assertEqual(len(objs), 4)
self.assertIsInstance(objs[0], ComputedFlags)
self.assertIsInstance(objs[1], Program)
self.assertIsInstance(objs[2], SimpleProgram)
self.assertIsInstance(objs[3], SimpleProgram)
self.assertEqual(objs[0].program, 'test_program.prog')
self.assertEqual(objs[1].program, 'test_program1.prog')
self.assertEqual(objs[2].program, 'test_program2.prog')
self.assertEqual(objs[1].program, 'test_program.prog')
self.assertEqual(objs[2].program, 'test_program1.prog')
self.assertEqual(objs[3].program, 'test_program2.prog')
def test_test_manifest_missing_manifest(self):
"""A missing manifest file should result in an error."""
@ -816,6 +843,8 @@ class TestEmitterBasic(unittest.TestCase):
# The last object is a Linkable.
linkable = objs.pop()
self.assertTrue(linkable.cxx_link)
computed_flags = objs.pop()
self.assertIsInstance(computed_flags, ComputedFlags)
self.assertEqual(len(objs), 6)
for o in objs:
self.assertIsInstance(o, Sources)
@ -868,7 +897,7 @@ class TestEmitterBasic(unittest.TestCase):
# The last object is a Linkable.
linkable = objs.pop()
self.assertTrue(linkable.cxx_link)
self.assertEqual(len(objs), 6)
self.assertEqual(len(objs), 7)
generated_sources = [o for o in objs if isinstance(o, GeneratedSources)]
self.assertEqual(len(generated_sources), 6)
@ -898,6 +927,8 @@ class TestEmitterBasic(unittest.TestCase):
# The last object is a Linkable
linkable = objs.pop()
self.assertTrue(linkable.cxx_link)
computed_flags = objs.pop()
self.assertIsInstance(computed_flags, ComputedFlags)
self.assertEqual(len(objs), 3)
for o in objs:
self.assertIsInstance(o, HostSources)
@ -921,8 +952,9 @@ class TestEmitterBasic(unittest.TestCase):
reader = self.reader('unified-sources')
objs = self.read_topsrcdir(reader)
# The last object is a Linkable, ignore it
objs = objs[:-1]
# The last object is a Linkable, the second to last ComputedFlags,
# ignore them.
objs = objs[:-2]
self.assertEqual(len(objs), 3)
for o in objs:
self.assertIsInstance(o, UnifiedSources)
@ -947,8 +979,9 @@ class TestEmitterBasic(unittest.TestCase):
reader = self.reader('unified-sources-non-unified')
objs = self.read_topsrcdir(reader)
# The last object is a Linkable, ignore it
objs = objs[:-1]
# The last object is a Linkable, the second to last ComputedFlags,
# ignore them.
objs = objs[:-2]
self.assertEqual(len(objs), 3)
for o in objs:
self.assertIsInstance(o, UnifiedSources)
@ -1048,8 +1081,9 @@ class TestEmitterBasic(unittest.TestCase):
extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
lib = objs[0]
self.assertEqual(len(objs), 2)
flags, lib = objs
self.assertIsInstance(flags, ComputedFlags)
self.assertIsInstance(lib, RustLibrary)
self.assertRegexpMatches(lib.lib_name, "random_crate")
self.assertRegexpMatches(lib.import_name, "random_crate")
@ -1068,8 +1102,9 @@ class TestEmitterBasic(unittest.TestCase):
reader = self.reader('rust-library-features',
extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
lib = objs[0]
self.assertEqual(len(objs), 2)
flags, lib = objs
self.assertIsInstance(flags, ComputedFlags)
self.assertIsInstance(lib, RustLibrary)
self.assertEqual(lib.features, ['musthave', 'cantlivewithout'])
@ -1138,10 +1173,10 @@ class TestEmitterBasic(unittest.TestCase):
extra_substs=dict(RUST_HOST_TARGET='i686-pc-windows-msvc',
HOST_BIN_SUFFIX='.exe'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
self.assertIsInstance(objs[0], HostRustLibrary)
self.assertRegexpMatches(objs[0].lib_name, 'host_lib')
self.assertRegexpMatches(objs[0].import_name, 'host_lib')
self.assertEqual(len(objs), 2)
self.assertIsInstance(objs[1], HostRustLibrary)
self.assertRegexpMatches(objs[1].lib_name, 'host_lib')
self.assertRegexpMatches(objs[1].import_name, 'host_lib')
def test_crate_dependency_path_resolution(self):
'''Test recursive dependencies resolve with the correct paths.'''
@ -1149,8 +1184,8 @@ class TestEmitterBasic(unittest.TestCase):
extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
objs = self.read_topsrcdir(reader)
self.assertEqual(len(objs), 1)
self.assertIsInstance(objs[0], RustLibrary)
self.assertEqual(len(objs), 2)
self.assertIsInstance(objs[1], RustLibrary)
def test_android_res_dirs(self):
"""Test that ANDROID_RES_DIRS works properly."""
@ -1174,7 +1209,8 @@ class TestEmitterBasic(unittest.TestCase):
objs = self.read_topsrcdir(reader)
self.assertIsInstance(objs[0], TestHarnessFiles)
self.assertIsInstance(objs[1], VariablePassthru)
self.assertIsInstance(objs[2], SharedLibrary)
self.assertIsInstance(objs[2], ComputedFlags)
self.assertIsInstance(objs[3], SharedLibrary)
for path, files in objs[0].files.walk():
for f in files:
self.assertEqual(str(f), '!libfoo.so')
@ -1183,8 +1219,9 @@ class TestEmitterBasic(unittest.TestCase):
def test_symbols_file(self):
"""Test that SYMBOLS_FILE works"""
reader = self.reader('test-symbols-file')
genfile, shlib = self.read_topsrcdir(reader)
genfile, flags, shlib = self.read_topsrcdir(reader)
self.assertIsInstance(genfile, GeneratedFile)
self.assertIsInstance(flags, ComputedFlags)
self.assertIsInstance(shlib, SharedLibrary)
# This looks weird but MockConfig sets DLL_{PREFIX,SUFFIX} and
# the reader method in this class sets OS_TARGET=WINNT.
@ -1193,10 +1230,11 @@ class TestEmitterBasic(unittest.TestCase):
def test_symbols_file_objdir(self):
"""Test that a SYMBOLS_FILE in the objdir works"""
reader = self.reader('test-symbols-file-objdir')
genfile, shlib = self.read_topsrcdir(reader)
genfile, flags, shlib = self.read_topsrcdir(reader)
self.assertIsInstance(genfile, GeneratedFile)
self.assertEqual(genfile.script,
mozpath.join(reader.config.topsrcdir, 'foo.py'))
self.assertIsInstance(flags, ComputedFlags)
self.assertIsInstance(shlib, SharedLibrary)
self.assertEqual(shlib.symbols_file, 'foo.symbols')