Bug 1362612 - Move defines to computed compile flags. draft
authorChris Manchester <cmanchester@mozilla.com>
Mon, 01 May 2017 18:13:48 -0700
changeset 586730 8097e8167ddfe4c1a30dd4463ae2b2c0d616fd91
parent 586729 dc3caa21d06a5cc3875b8f62b97639028ffa1be0
child 631084 77bb061767bb8d72181b0657ac423bebd5124a7f
push id61508
push userbmo:cmanchester@mozilla.com
push dateWed, 31 May 2017 00:27:20 +0000
bugs1362612
milestone55.0a1
Bug 1362612 - Move defines to computed compile flags. MozReview-Commit-ID: CgQv79dYj7Y
config/config.mk
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/compilation/database.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
--- a/config/config.mk
+++ b/config/config.mk
@@ -320,18 +320,18 @@ endif # CLANG_CL
 
 # Use warnings-as-errors if ALLOW_COMPILER_WARNINGS is not set to 1 (which
 # includes the case where it's undefined).
 ifneq (1,$(ALLOW_COMPILER_WARNINGS))
 CXXFLAGS += $(WARNINGS_AS_ERRORS)
 CFLAGS   += $(WARNINGS_AS_ERRORS)
 endif # ALLOW_COMPILER_WARNINGS
 
-COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS)
-COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(DEFINES) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS)
+COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CFLAGS) $(_DEPEND_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS)
+COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(INCLUDES) $(OS_INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_COMPILE_CXXFLAGS) $(_DEPEND_CFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS)
 COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
 COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
 ASFLAGS += $(MOZBUILD_ASFLAGS)
 
 ifndef CROSS_COMPILE
 HOST_CFLAGS += $(RTL_FLAGS)
 endif
 
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1194,17 +1194,18 @@ class RecursiveMakeBackend(CommonBackend
         backend_file.write('LOCAL_INCLUDES += -I%s\n' % path)
 
     def _process_per_source_flag(self, per_source_flag, backend_file):
         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))))
+            backend_file.write('COMPUTED_%s += %s\n' % (var,
+                                                        ' '.join(make_quote(shell_quote(f)) for f in flags)))
 
     def _process_java_jar_data(self, jar, backend_file):
         target = jar.name
         backend_file.write('JAVA_JAR_TARGETS += %s\n' % target)
         backend_file.write('%s_DEST := %s.jar\n' % (target, jar.name))
         if jar.sources:
             backend_file.write('%s_JAVAFILES := %s\n' %
                 (target, ' '.join(jar.sources)))
--- a/python/mozbuild/mozbuild/compilation/database.py
+++ b/python/mozbuild/mozbuild/compilation/database.py
@@ -9,17 +9,16 @@ import types
 
 from mozbuild.compilation import util
 from mozbuild.backend.common import CommonBackend
 from mozbuild.frontend.data import (
     ComputedFlags,
     Sources,
     GeneratedSources,
     DirectoryTraversal,
-    Defines,
     Linkable,
     LocalInclude,
     PerSourceFlag,
     VariablePassthru,
     SimpleProgram,
 )
 from mozbuild.shellutil import (
     quote as shell_quote,
@@ -41,17 +40,16 @@ class CompileDBBackend(CommonBackend):
         # The database we're going to dump out to.
         self._db = OrderedDict()
 
         # The cache for per-directory flags
         self._flags = {}
 
         self._envs = {}
         self._includes = defaultdict(list)
-        self._defines = defaultdict(list)
         self._local_flags = defaultdict(dict)
         self._per_source_flags = defaultdict(list)
         self._extra_includes = defaultdict(list)
         self._gyp_dirs = set()
         self._dist_include_testing = '-I%s' % mozpath.join(
             self.environment.topobjdir, 'dist', 'include', 'testing')
 
     def consume_object(self, obj):
@@ -82,21 +80,16 @@ class CompileDBBackend(CommonBackend):
                 self._build_db_line(obj.objdir, obj.relativedir, obj.config, f,
                                     obj.canonical_suffix)
 
         elif isinstance(obj, LocalInclude):
             self._includes[obj.objdir].append('-I%s' % mozpath.normpath(
                 obj.path.full_path))
 
         elif isinstance(obj, Linkable):
-            if isinstance(obj.defines, Defines): # As opposed to HostDefines
-                for d in obj.defines.get_defines():
-                    if d not in self._defines[obj.objdir]:
-                        self._defines[obj.objdir].append(d)
-            self._defines[obj.objdir].extend(obj.lib_defines.get_defines())
             if isinstance(obj, SimpleProgram) and obj.is_unit_test:
                 if (self._dist_include_testing not in
                         self._extra_includes[obj.objdir]):
                     self._extra_includes[obj.objdir].append(
                         self._dist_include_testing)
 
         elif isinstance(obj, VariablePassthru):
             if obj.variables.get('IS_GYP_DIR'):
@@ -141,17 +134,16 @@ class CompileDBBackend(CommonBackend):
                     'MOZ_ZLIB_CFLAGS',
                     'MOZ_PIXMAN_CFLAGS',
                 ):
                     f = env.substs.get(var)
                     if f:
                         local_extra.extend(f)
             variables = {
                 'LOCAL_INCLUDES': self._includes[directory],
-                'DEFINES': self._defines[directory],
                 'EXTRA_INCLUDES': local_extra,
                 'DIST': mozpath.join(env.topobjdir, 'dist'),
                 'DEPTH': env.topobjdir,
                 'MOZILLA_DIR': env.topsrcdir,
                 'topsrcdir': env.topsrcdir,
                 'topobjdir': env.topobjdir,
             }
             variables.update(self._local_flags[directory])
@@ -234,17 +226,16 @@ class CompileDBBackend(CommonBackend):
                 return
             if isinstance(value, types.StringTypes):
                 value = value.split()
             db.extend(value)
 
         db.append('$(COMPUTED_%s)' % self.CFLAGS[canonical_suffix])
 
         db.extend((
-            '$(DEFINES)',
             '-I%s' % mozpath.join(cenv.topsrcdir, reldir),
             '-I%s' % objdir,
             '$(LOCAL_INCLUDES)',
             '-I%s/dist/include' % cenv.topobjdir,
             '$(EXTRA_INCLUDES)',
         ))
         append_var('DSO_CFLAGS')
         append_var('DSO_PIC_CFLAGS')
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -158,45 +158,58 @@ class VariablePassthru(ContextDerived):
     def __init__(self, context):
         ContextDerived.__init__(self, context)
         self.variables = {}
 
 
 class ComputedFlags(ContextDerived):
     """Computed flags for convenient consumption by various backends.
     """
-    __slots__ = ('variables')
+    __slots__ = ('variables', '_resolved')
 
     def __init__(self, context):
         ContextDerived.__init__(self, context)
 
+        self._resolved = {}
+
         # Variables that will contribute to flags for this context.
         self.variables = OrderedDict([
             ('STL_FLAGS', self.cxx_config_var),
             ('VISIBILITY_FLAGS', self.common_config_var),
+            ('DEFINES', self.common_resolved_var),
+            ('LIBRARY_DEFINES', self.common_resolved_var),
         ])
 
     def _get_value(self, variable, getter, target_variables=('CXXFLAGS', 'CFLAGS')):
         value = getter(variable)
         if value:
             return [(v, value) for v in target_variables]
         return []
 
     def cxx_config_var(self, var):
         return self._get_value(var, self.config.substs.get, ('CXXFLAGS',))
 
     def common_config_var(self, var):
         return self._get_value(var, self.config.substs.get)
 
+    def common_resolved_var(self, var):
+        return self._get_value(var, self._resolved.get)
+
     def exclude_variable(self, excluded_variable):
         # Prevents the given variable from contributing to compile flags for
         # this context.
         assert excluded_variable in self.variables
         del self.variables[excluded_variable]
 
+    def resolve_variable(self, var, value):
+        # Sets the final value for the given variable.
+        assert var in self.variables
+        assert var not in self._resolved
+        self._resolved[var] = value
+
     def get_flags(self):
         flags = defaultdict(list)
         for origin_var, func in self.variables.items():
             for flags_var, value in func(origin_var):
                 flags[flags_var].extend(value)
         return flags.items()
 
 class XPIDLFile(ContextDerived):
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -126,16 +126,17 @@ class TreeMetadataEmitter(LoggingMixin):
         for k, v in mozinfo.info.items():
             if isinstance(k, unicode):
                 k = k.encode('ascii')
             self.info[k] = v
 
         self._libs = OrderedDefaultDict(list)
         self._binaries = OrderedDict()
         self._compile_dirs = set()
+        self._compile_flags = dict()
         self._linkage = []
         self._static_linking_shared = set()
         self._crate_verified_local = set()
         self._crate_directories = dict()
 
         # Keep track of external paths (third party build systems), starting
         # from what we run a subconfigure in. We'll eliminate some directories
         # as we traverse them with moz.build (e.g. js/src).
@@ -260,16 +261,28 @@ class TreeMetadataEmitter(LoggingMixin):
                         lib.link_into == outerlib.basename):
                     propagate_defines(lib, defines)
 
         for lib in (l for libs in self._libs.values() for l in libs):
             if isinstance(lib, Library):
                 propagate_defines(lib, lib.lib_defines)
             yield lib
 
+
+        for lib in (l for libs in self._libs.values() for l in libs):
+            lib_defines = list(lib.lib_defines.get_defines())
+            if lib_defines:
+                if lib.objdir not in self._compile_flags:
+                    self._compile_flags[lib.objdir] = ComputedFlags(contexts[lib.objdir])
+                objdir_flags = self._compile_flags[lib.objdir]
+                objdir_flags.resolve_variable('LIBRARY_DEFINES', lib_defines)
+
+        for flags_obj in self._compile_flags.values():
+            yield flags_obj
+
         for obj in self._binaries.values():
             yield obj
 
     LIBRARY_NAME_VAR = {
         'host': 'HOST_LIBRARY_NAME',
         'target': 'LIBRARY_NAME',
     }
 
@@ -995,23 +1008,33 @@ class TreeMetadataEmitter(LoggingMixin):
             yield obj
 
         for path in context['CONFIGURE_SUBST_FILES']:
             sub = self._create_substitution(ConfigFileSubstitution, context,
                 path)
             generated_files.add(str(sub.relpath))
             yield sub
 
-        defines = context.get('DEFINES')
-        if defines:
-            yield Defines(context, defines)
 
-        host_defines = context.get('HOST_DEFINES')
-        if host_defines:
-            yield HostDefines(context, host_defines)
+        for defines_var, cls in (('DEFINES', Defines),
+                                 ('HOST_DEFINES', HostDefines)):
+            defines = context.get(defines_var)
+            if defines:
+                defines_obj = cls(context, defines)
+                yield defines_obj
+            else:
+                # If we don't have explicitly set defines we need to make sure
+                # initialized values if present end up in computed flags.
+                defines_obj = cls(context, context[defines_var])
+
+            if isinstance(defines_obj, Defines):
+                defines_from_obj = list(defines_obj.get_defines())
+                if defines_from_obj:
+                    computed_flags.resolve_variable('DEFINES',
+                                                    defines_from_obj)
 
         simple_lists = [
             ('GENERATED_EVENTS_WEBIDL_FILES', GeneratedEventWebIDLFile),
             ('GENERATED_WEBIDL_FILES', GeneratedWebIDLFile),
             ('IPDL_SOURCES', IPDLFile),
             ('PREPROCESSED_TEST_WEBIDL_FILES', PreprocessedTestWebIDLFile),
             ('PREPROCESSED_WEBIDL_FILES', PreprocessedWebIDLFile),
             ('TEST_WEBIDL_FILES', TestWebIDLFile),
@@ -1157,17 +1180,17 @@ class TreeMetadataEmitter(LoggingMixin):
         android_extra_packages = context.get('ANDROID_EXTRA_PACKAGES')
         if android_extra_packages:
             yield AndroidExtraPackages(context, android_extra_packages)
 
         if passthru.variables:
             yield passthru
 
         if context.objdir in self._compile_dirs:
-            yield computed_flags
+            self._compile_flags[context.objdir] = computed_flags
 
     def _create_substitution(self, cls, context, path):
         sub = cls(context)
         sub.input_path = '%s.in' % path.full_path
         sub.output_path = path.translated
         sub.relpath = path
 
         return sub