diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index 4f51baf25531..51b368417576 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -365,6 +365,7 @@ class Linkable(ContextDerived): 'lib_defines', 'linked_libraries', 'linked_system_libs', + 'sources', ) def __init__(self, context): @@ -373,6 +374,7 @@ class Linkable(ContextDerived): self.linked_libraries = [] self.linked_system_libs = [] self.lib_defines = Defines(context, {}) + self.sources = defaultdict(list) def link_library(self, obj): assert isinstance(obj, BaseLibrary) @@ -404,6 +406,26 @@ class Linkable(ContextDerived): ) self.linked_system_libs.append(lib) + def source_files(self): + all_sources = [] + # This is ordered for reproducibility and consistently w/ + # config/rules.mk + for suffix in ('.c', '.S', '.cpp', '.m', '.mm', '.s'): + all_sources += self.sources.get(suffix, []) + return all_sources + + @property + def objs(self): + obj_prefix = '' + if self.KIND == 'host': + obj_prefix = 'host_' + + return [mozpath.join(self.objdir, '%s%s.%s' % (obj_prefix, + mozpath.splitext(mozpath.basename(f))[0], + self.config.substs.get('OBJ_SUFFIX', ''))) + for f in self.source_files()] + + class BaseProgram(Linkable): """Context derived container object for programs, which is a unicode string. @@ -453,6 +475,13 @@ class SimpleProgram(BaseProgram): SUFFIX_VAR = 'BIN_SUFFIX' KIND = 'target' + def source_files(self): + for srcs in self.sources.values(): + for f in srcs: + if mozpath.basename(mozpath.splitext(f)[0]) == mozpath.splitext(self.program)[0]: + return [f] + return [] + class HostSimpleProgram(HostMixin, BaseProgram): """Context derived container object for each program in diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index 852b410ddf19..d0e91bc8a593 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -947,6 +947,9 @@ class TreeMetadataEmitter(LoggingMixin): # a directory with mixed C and C++ source, but it's not that important. cxx_sources = defaultdict(bool) + # Source files to track for linkables associated with this context. + ctxt_sources = defaultdict(lambda: defaultdict(list)) + for variable, (klass, gen_klass, suffixes) in varmap.items(): allowed_suffixes = set().union(*[suffix_map[s] for s in suffixes]) @@ -972,8 +975,21 @@ class TreeMetadataEmitter(LoggingMixin): if variable.startswith('UNIFIED_'): arglist.append(context.get('FILES_PER_UNIFIED_FILE', 16)) obj = cls(*arglist) + srcs = obj.files + if isinstance(obj, UnifiedSources) and obj.have_unified_mapping: + srcs = dict(obj.unified_source_mapping).keys() + ctxt_sources[variable][canonical_suffix] += sorted(srcs) yield obj + if ctxt_sources: + for linkable in linkables: + for target_var in ('SOURCES', 'UNIFIED_SOURCES'): + for suffix, srcs in ctxt_sources[target_var].items(): + linkable.sources[suffix] += srcs + for host_linkable in host_linkables: + for suffix, srcs in ctxt_sources['HOST_SOURCES'].items(): + host_linkable.sources[suffix] += srcs + for f, flags in all_flags.iteritems(): if flags.flags: ext = mozpath.splitext(f)[1] diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/moz.build b/python/mozbuild/mozbuild/test/frontend/data/program/moz.build index 4c19b90cd542..2c6224ee756a 100644 --- a/python/mozbuild/mozbuild/test/frontend/data/program/moz.build +++ b/python/mozbuild/mozbuild/test/frontend/data/program/moz.build @@ -7,8 +7,9 @@ def Program(name): @template -def SimplePrograms(names): +def SimplePrograms(names, ext='.cpp'): SIMPLE_PROGRAMS += names + SOURCES += ['%s%s' % (name, ext) for name in names] Program('test_program') diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp b/python/mozbuild/mozbuild/test/frontend/data/program/test_program1.cpp new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp b/python/mozbuild/mozbuild/test/frontend/data/program/test_program2.cpp new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index 8d5db0401aa1..7c0e2e07684f 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -81,6 +81,7 @@ class TestEmitterBasic(unittest.TestCase): STL_FLAGS=['-I/path/to/topobjdir/dist/stl_wrappers'], VISIBILITY_FLAGS=['-include', '$(topsrcdir)/config/gcc_hidden.h'], + OBJ_SUFFIX='obj', ) if extra_substs: substs.update(extra_substs) @@ -642,16 +643,26 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('program') objs = self.read_topsrcdir(reader) - self.assertEqual(len(objs), 5) - self.assertIsInstance(objs[0], ComputedFlags) + self.assertEqual(len(objs), 6) + self.assertIsInstance(objs[0], Sources) self.assertIsInstance(objs[1], ComputedFlags) - self.assertIsInstance(objs[2], Program) - self.assertIsInstance(objs[3], SimpleProgram) + self.assertIsInstance(objs[2], ComputedFlags) + self.assertIsInstance(objs[3], Program) self.assertIsInstance(objs[4], SimpleProgram) + self.assertIsInstance(objs[5], SimpleProgram) - self.assertEqual(objs[2].program, 'test_program.prog') - self.assertEqual(objs[3].program, 'test_program1.prog') - self.assertEqual(objs[4].program, 'test_program2.prog') + self.assertEqual(objs[3].program, 'test_program.prog') + self.assertEqual(objs[4].program, 'test_program1.prog') + self.assertEqual(objs[5].program, 'test_program2.prog') + + self.assertEqual(objs[4].objs, + [mozpath.join(reader.config.topobjdir, + 'test_program1.%s' % + reader.config.substs['OBJ_SUFFIX'])]) + self.assertEqual(objs[5].objs, + [mozpath.join(reader.config.topobjdir, + 'test_program2.%s' % + reader.config.substs['OBJ_SUFFIX'])]) def test_test_manifest_missing_manifest(self): """A missing manifest file should result in an error.""" @@ -1132,6 +1143,12 @@ class TestEmitterBasic(unittest.TestCase): sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]) + for f in files: + self.assertIn(mozpath.join(reader.config.topobjdir, + '%s.%s' % (mozpath.splitext(f)[0], + reader.config.substs['OBJ_SUFFIX'])), + linkable.objs) + def test_sources_just_c(self): """Test that a linkable with no C++ sources doesn't have cxx_link set.""" reader = self.reader('sources-just-c') @@ -1195,6 +1212,12 @@ class TestEmitterBasic(unittest.TestCase): sources.files, [mozpath.join(reader.config.topobjdir, f) for f in files]) + for f in files: + self.assertIn(mozpath.join(reader.config.topobjdir, + '%s.%s' % (mozpath.splitext(f)[0], + reader.config.substs['OBJ_SUFFIX'])), + linkable.objs) + def test_host_sources(self): """Test that HOST_SOURCES works properly.""" reader = self.reader('host-sources') @@ -1230,13 +1253,21 @@ class TestEmitterBasic(unittest.TestCase): sources.files, [mozpath.join(reader.config.topsrcdir, f) for f in files]) + for f in files: + self.assertIn(mozpath.join(reader.config.topobjdir, + 'host_%s.%s' % (mozpath.splitext(f)[0], + reader.config.substs['OBJ_SUFFIX'])), + linkable.objs) + + def test_unified_sources(self): """Test that UNIFIED_SOURCES works properly.""" reader = self.reader('unified-sources') objs = self.read_topsrcdir(reader) - # The last object is a Linkable, the second to last ComputedFlags, + # The last object is a ComputedFlags, the second to last a Linkable, # followed by ldflags, ignore them. + linkable = objs[-2] objs = objs[:-3] self.assertEqual(len(objs), 3) for o in objs: @@ -1257,6 +1288,13 @@ class TestEmitterBasic(unittest.TestCase): [mozpath.join(reader.config.topsrcdir, f) for f in files]) self.assertTrue(sources.have_unified_mapping) + for f in dict(sources.unified_source_mapping).keys(): + self.assertIn(mozpath.join(reader.config.topobjdir, + '%s.%s' % (mozpath.splitext(f)[0], + reader.config.substs['OBJ_SUFFIX'])), + linkable.objs) + + def test_unified_sources_non_unified(self): """Test that UNIFIED_SOURCES with FILES_PER_UNIFIED_FILE=1 works properly.""" reader = self.reader('unified-sources-non-unified')