Bug 1416059 - Move ASFLAGS logic from config.mk to mozbuild. draft
authorChris Manchester <cmanchester@mozilla.com>
Fri, 10 Nov 2017 16:58:16 -0800
changeset 697813 706124f3dfb35b5a5bae4fd913b61bde612167f0
parent 697803 889748ea77336f996ebc7684f920f8b32229ed8c
child 740213 6555a74002c405d2e672e86b4a910ee7651fc0d5
push id89103
push userbmo:cmanchester@mozilla.com
push dateTue, 14 Nov 2017 18:52:26 +0000
bugs1416059
milestone59.0a1
Bug 1416059 - Move ASFLAGS logic from config.mk to mozbuild. MozReview-Commit-ID: L7RSijG9uA
config/config.mk
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build
python/mozbuild/mozbuild/test/frontend/data/asflags/test1.S
python/mozbuild/mozbuild/test/frontend/data/asflags/test1.c
python/mozbuild/mozbuild/test/frontend/data/use-yasm/moz.build
python/mozbuild/mozbuild/test/frontend/data/use-yasm/test1.S
python/mozbuild/mozbuild/test/frontend/test_emitter.py
--- a/config/config.mk
+++ b/config/config.mk
@@ -127,35 +127,16 @@ endif # _MSC_VER
 CC := $(CC_WRAPPER) $(CC)
 CXX := $(CXX_WRAPPER) $(CXX)
 MKDIR ?= mkdir
 SLEEP ?= sleep
 TOUCH ?= touch
 
 PYTHON_PATH = $(PYTHON) $(topsrcdir)/config/pythonpath.py
 
-# determine debug-related options
-_DEBUG_ASFLAGS :=
-
-ifneq (,$(MOZ_DEBUG)$(MOZ_DEBUG_SYMBOLS))
-  ifeq ($(AS),$(YASM))
-    ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
-      _DEBUG_ASFLAGS += -g cv8
-    else
-      ifneq ($(OS_ARCH),Darwin)
-        _DEBUG_ASFLAGS += -g dwarf2
-      endif
-    endif
-  else
-    _DEBUG_ASFLAGS += $(MOZ_DEBUG_FLAGS)
-  endif
-endif
-
-ASFLAGS += $(_DEBUG_ASFLAGS)
-
 #
 # Build using PIC by default
 #
 _ENABLE_PIC=1
 
 # Don't build SIMPLE_PROGRAMS with PGO, since they don't need it anyway,
 # and we don't have the same build logic to re-link them in the second pass.
 ifdef SIMPLE_PROGRAMS
@@ -218,17 +199,17 @@ INCLUDES = \
 include $(MOZILLA_DIR)/config/static-checking-config.mk
 
 LDFLAGS		= $(COMPUTED_LDFLAGS) $(PGO_LDFLAGS) $(MK_LDFLAGS)
 
 COMPILE_CFLAGS	= $(COMPUTED_CFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
 COMPILE_CXXFLAGS = $(COMPUTED_CXXFLAGS) $(PGO_CFLAGS) $(_DEPEND_CFLAGS) $(MK_COMPILE_DEFINES)
 COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS)
 COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
-ASFLAGS += $(MOZBUILD_ASFLAGS)
+ASFLAGS = $(COMPUTED_ASFLAGS)
 
 HOST_CFLAGS = $(COMPUTED_HOST_CFLAGS) $(_DEPEND_CFLAGS)
 HOST_CXXFLAGS = $(COMPUTED_HOST_CXXFLAGS) $(_DEPEND_CFLAGS)
 
 # We only add color flags if neither the flag to disable color
 # (e.g. "-fno-color-diagnostics" nor a flag to control color
 # (e.g. "-fcolor-diagnostics=never") is present.
 define colorize_flags
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -339,16 +339,41 @@ class HostCompileFlags(BaseCompileFlags)
         optimize_flags = []
         if self._context.config.substs.get('CROSS_COMPILE'):
             optimize_flags += self._context.config.substs.get('HOST_OPTIMIZE_FLAGS')
         elif self._context.config.substs.get('MOZ_OPTIMIZE'):
             optimize_flags += self._context.config.substs.get('MOZ_OPTIMIZE_FLAGS')
         return optimize_flags
 
 
+class AsmFlags(BaseCompileFlags):
+    def __init__(self, context):
+        self._context = context
+        self.flag_variables = (
+            ('OS', context.config.substs.get('ASFLAGS'), ('ASFLAGS',)),
+            ('DEBUG', self._debug_flags(), ('ASFLAGS',)),
+            ('MOZBUILD', None, ('ASFLAGS',)),
+        )
+        BaseCompileFlags.__init__(self, context)
+
+    def _debug_flags(self):
+        debug_flags = []
+        if (self._context.config.substs.get('MOZ_DEBUG') or
+            self._context.config.substs.get('MOZ_DEBUG_SYMBOLS')):
+            if self._context.get('USE_YASM'):
+                if (self._context.config.substs.get('OS_ARCH') == 'WINNT' and
+                    not self._context.config.substs.get('GNU_CC')):
+                    debug_flags += ['-g', 'cv8']
+                elif self._context.config.substs.get('OS_ARCH') != 'Darwin':
+                    debug_flags += ['-g', 'dwarf2']
+            else:
+                debug_flags += self._context.config.substs.get('MOZ_DEBUG_FLAGS', '').split()
+        return debug_flags
+
+
 class LinkFlags(BaseCompileFlags):
     def __init__(self, context):
         self._context = context
 
         self.flag_variables = (
             ('OS', self._os_ldflags(), ('LDFLAGS',)),
             ('LINKER', context.config.substs.get('LINKER_LDFLAGS'),
              ('LDFLAGS',)),
@@ -1950,16 +1975,21 @@ VARIABLES = {
         directly.
         """),
 
     'LINK_FLAGS': (LinkFlags, dict,
         """Recipe for linker flags for this context. Not to be manipulated
         directly.
         """),
 
+    'ASM_FLAGS': (AsmFlags, dict,
+        """Recipe for linker 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.
 
            Note that the ordering of flags matters here, these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
@@ -2405,16 +2435,25 @@ SPECIAL_VARIABLES = {
         This variable may go away once the transition away from Makefiles is
         complete.
         """),
 
 }
 
 # Deprecation hints.
 DEPRECATION_HINTS = {
+
+    'ASM_FLAGS': '''
+        Please use
+
+            ASFLAGS
+
+        instead of manipulating ASM_FLAGS directly.
+        ''',
+
     'CPP_UNIT_TESTS': '''
         Please use'
 
             CppUnitTests(['foo', 'bar'])
 
         instead of
 
             CPP_UNIT_TESTS += ['foo', 'bar']
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -128,16 +128,17 @@ class TreeMetadataEmitter(LoggingMixin):
                 k = k.encode('ascii')
             self.info[k] = v
 
         self._libs = OrderedDefaultDict(list)
         self._binaries = OrderedDict()
         self._compile_dirs = set()
         self._host_compile_dirs = set()
         self._rust_compile_dirs = set()
+        self._asm_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
@@ -883,16 +884,18 @@ class TreeMetadataEmitter(LoggingMixin):
             for srcs, cls in ((sources[variable], klass),
                               (gen_sources[variable], gen_klass)):
                 # Now sort the files to let groupby work.
                 sorted_files = sorted(srcs, key=canonical_suffix_for_file)
                 for canonical_suffix, files in itertools.groupby(
                         sorted_files, canonical_suffix_for_file):
                     if canonical_suffix in ('.cpp', '.mm'):
                         cxx_sources[variable] = True
+                    elif canonical_suffix in ('.s', '.S'):
+                        self._asm_compile_dirs.add(context.objdir)
                     arglist = [context, list(files), canonical_suffix]
                     if variable.startswith('UNIFIED_'):
                         arglist.append(context.get('FILES_PER_UNIFIED_FILE', 16))
                     obj = cls(*arglist)
                     yield obj
 
         for f, flags in all_flags.iteritems():
             if flags.flags:
@@ -928,16 +931,17 @@ class TreeMetadataEmitter(LoggingMixin):
         for o in self._emit_directory_traversal_from_context(context): yield o
 
         for obj in self._process_xpidl(context):
             yield obj
 
         computed_flags = ComputedFlags(context, context['COMPILE_FLAGS'])
         computed_link_flags = ComputedFlags(context, context['LINK_FLAGS'])
         computed_host_flags = ComputedFlags(context, context['HOST_COMPILE_FLAGS'])
+        computed_as_flags = ComputedFlags(context, context['ASM_FLAGS'])
 
         # Proxy some variables as-is until we have richer classes to represent
         # them. We should aim to keep this set small because it violates the
         # desired abstraction of the build definition away from makefiles.
         passthru = VariablePassthru(context)
         varlist = [
             'ANDROID_APK_NAME',
             'ANDROID_APK_PACKAGE',
@@ -957,17 +961,17 @@ class TreeMetadataEmitter(LoggingMixin):
                 passthru.variables[v] = context[v]
 
         if context.config.substs.get('OS_TARGET') == 'WINNT' and \
                 context['DELAYLOAD_DLLS']:
             context['LDFLAGS'].extend([('-DELAYLOAD:%s' % dll)
                 for dll in context['DELAYLOAD_DLLS']])
             context['OS_LIBS'].append('delayimp')
 
-        for v in ['CMFLAGS', 'CMMFLAGS', 'ASFLAGS']:
+        for v in ['CMFLAGS', 'CMMFLAGS']:
             if v in context and context[v]:
                 passthru.variables['MOZBUILD_' + v] = context[v]
 
         for v in ['CXXFLAGS', 'CFLAGS']:
             if v in context and context[v]:
                 computed_flags.resolve_flags('MOZBUILD_%s' % v, context[v])
 
         for v in ['HOST_CXXFLAGS', 'HOST_CFLAGS']:
@@ -1170,23 +1174,28 @@ class TreeMetadataEmitter(LoggingMixin):
             yield obj
 
         for obj in self._process_jar_manifests(context):
             yield obj
 
         for name, jar in context.get('JAVA_JAR_TARGETS', {}).items():
             yield ContextWrapped(context, jar)
 
+        computed_as_flags.resolve_flags('MOZBUILD',
+                                        context.get('ASFLAGS'))
+
         if context.get('USE_YASM') is True:
             yasm = context.config.substs.get('YASM')
             if not yasm:
                 raise SandboxValidationError('yasm is not available', context)
             passthru.variables['AS'] = yasm
-            passthru.variables['ASFLAGS'] = context.config.substs.get('YASM_ASFLAGS')
             passthru.variables['AS_DASH_C_FLAG'] = ''
+            computed_as_flags.resolve_flags('OS',
+                                            context.config.substs.get('YASM_ASFLAGS', []))
+
 
         for (symbol, cls) in [
                 ('ANDROID_RES_DIRS', AndroidResDirs),
                 ('ANDROID_EXTRA_RES_DIRS', AndroidExtraResDirs),
                 ('ANDROID_ASSETS_DIRS', AndroidAssetsDirs)]:
             paths = context.get(symbol)
             if not paths:
                 continue
@@ -1205,16 +1214,19 @@ class TreeMetadataEmitter(LoggingMixin):
             yield passthru
 
         if context.objdir in self._compile_dirs:
             self._compile_flags[context.objdir] = computed_flags
             yield computed_link_flags
         elif context.objdir in self._rust_compile_dirs:
             yield computed_link_flags
 
+        if context.objdir in self._asm_compile_dirs:
+            yield computed_as_flags
+
         if context.objdir in self._host_compile_dirs:
             yield computed_host_flags
 
 
     def _create_substitution(self, cls, context, path):
         sub = cls(context)
         sub.input_path = '%s.in' % path.full_path
         sub.output_path = path.translated
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/asflags/moz.build
@@ -0,0 +1,16 @@
+# 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')
+
+SOURCES += [
+    'test1.c',
+    'test1.S'
+]
+
+ASFLAGS += ['-no-integrated-as']
\ No newline at end of file
new file mode 100644
new file mode 100644
--- a/python/mozbuild/mozbuild/test/frontend/data/use-yasm/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/use-yasm/moz.build
@@ -1,5 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
+@template
+def Library(name):
+    LIBRARY_NAME = name
+
+Library('dummy')
+
 USE_YASM = True
+
+SOURCES += ['test1.S']
new file mode 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -204,16 +204,25 @@ class TestEmitterBasic(unittest.TestCase
         sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['STL'], reader.config.substs['STL_FLAGS'])
         self.assertEqual(flags.flags['VISIBILITY'], reader.config.substs['VISIBILITY_FLAGS'])
         self.assertEqual(flags.flags['WARNINGS_AS_ERRORS'], ['-Werror'])
         self.assertEqual(flags.flags['MOZBUILD_CFLAGS'], ['-Wall', '-funroll-loops'])
         self.assertEqual(flags.flags['MOZBUILD_CXXFLAGS'], ['-funroll-loops', '-Wall'])
 
+    def test_asflags(self):
+        reader = self.reader('asflags', extra_substs={
+            'ASFLAGS': ['-safeseh'],
+        })
+        as_sources, sources, ldflags, asflags, lib, flags = self.read_topsrcdir(reader)
+        self.assertIsInstance(asflags, ComputedFlags)
+        self.assertEqual(asflags.flags['OS'], reader.config.substs['ASFLAGS'])
+        self.assertEqual(asflags.flags['MOZBUILD'], ['-no-integrated-as'])
+
     def test_debug_flags(self):
         reader = self.reader('compile-flags', extra_substs={
             'MOZ_DEBUG_FLAGS': '-g',
             'MOZ_DEBUG_SYMBOLS': '1',
         })
         sources, ldflags, lib, flags = self.read_topsrcdir(reader)
         self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(flags.flags['DEBUG'], ['-g'])
@@ -420,25 +429,30 @@ class TestEmitterBasic(unittest.TestCase
             self.read_topsrcdir(reader)
 
         # When yasm is available, this should work.
         reader = self.reader('use-yasm',
                              extra_substs=dict(
                                  YASM='yasm',
                                  YASM_ASFLAGS='-foo',
                              ))
-        objs = self.read_topsrcdir(reader)
+
+        sources, passthru, ldflags, asflags, lib, flags = self.read_topsrcdir(reader)
 
-        self.assertEqual(len(objs), 1)
-        self.assertIsInstance(objs[0], VariablePassthru)
+        self.assertIsInstance(passthru, VariablePassthru)
+        self.assertIsInstance(ldflags, ComputedFlags)
+        self.assertIsInstance(asflags, ComputedFlags)
+        self.assertIsInstance(flags, ComputedFlags)
+
+        self.assertEqual(asflags.flags['OS'], reader.config.substs['YASM_ASFLAGS'])
+
         maxDiff = self.maxDiff
         self.maxDiff = None
-        self.assertEqual(objs[0].variables,
+        self.assertEqual(passthru.variables,
                          {'AS': 'yasm',
-                          'ASFLAGS': '-foo',
                           'AS_DASH_C_FLAG': ''})
         self.maxDiff = maxDiff
 
 
     def test_generated_files(self):
         reader = self.reader('generated-files')
         objs = self.read_topsrcdir(reader)
 
@@ -1011,16 +1025,18 @@ class TestEmitterBasic(unittest.TestCase
         reader = self.reader('sources')
         objs = self.read_topsrcdir(reader)
 
         computed_flags = objs.pop()
         self.assertIsInstance(computed_flags, ComputedFlags)
         # The second to last object is a Linkable.
         linkable = objs.pop()
         self.assertTrue(linkable.cxx_link)
+        as_flags = objs.pop()
+        self.assertIsInstance(as_flags, ComputedFlags)
         ld_flags = objs.pop()
         self.assertIsInstance(ld_flags, ComputedFlags)
         self.assertEqual(len(objs), 6)
         for o in objs:
             self.assertIsInstance(o, Sources)
 
         suffix_map = {obj.canonical_suffix: obj for obj in objs}
         self.assertEqual(len(suffix_map), 6)
@@ -1069,16 +1085,18 @@ class TestEmitterBasic(unittest.TestCase
         reader = self.reader('generated-sources')
         objs = self.read_topsrcdir(reader)
 
         flags = objs.pop()
         self.assertIsInstance(flags, ComputedFlags)
         # The second to last object is a Linkable.
         linkable = objs.pop()
         self.assertTrue(linkable.cxx_link)
+        flags = objs.pop()
+        self.assertIsInstance(flags, ComputedFlags)
         self.assertEqual(len(objs), 7)
 
         generated_sources = [o for o in objs if isinstance(o, GeneratedSources)]
         self.assertEqual(len(generated_sources), 6)
 
         suffix_map = {obj.canonical_suffix: obj for obj in generated_sources}
         self.assertEqual(len(suffix_map), 6)