https://hg.mozilla.org/mozilla-central/rev/e8c173a632a4 https://hg.mozilla.org/mozilla-central/rev/dbeb248015cc https://hg.mozilla.org/mozilla-central/rev/de7abe2c2b3e --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -1331,10 +1331,6 @@ def lto(value, c_compiler): # clang and clang-cl if c_compiler.type in ('clang', 'clang-cl'): - # Until Bug 1457168 is fixed, we have to hardcode -fuse-ld=lld here - if c_compiler.type == 'clang': - flags.append("-fuse-ld=lld") - if len(value) and value[0].lower() == 'full': flags.append("-flto") ldflags.append("-flto") @@ -1362,8 +1358,6 @@ add_old_configure_assignment('MOZ_LTO', lto.enabled) add_old_configure_assignment('MOZ_LTO_CFLAGS', lto.flags) add_old_configure_assignment('MOZ_LTO_LDFLAGS', lto.ldflags) -imply_option('--enable-linker', 'lld', when='--enable-lto') - # ASAN # ============================================================== @@ -1566,7 +1560,7 @@ set_config('CARGO_INCREMENTAL', cargo_incremental) @depends(target) def is_linker_option_enabled(target): - if target.kernel not in ('Darwin', 'WINNT', 'SunOS'): + if target.kernel not in ('WINNT', 'SunOS'): return True @@ -1578,21 +1572,40 @@ option('--enable-gold', imply_option('--enable-linker', 'gold', when='--enable-gold') js_option('--enable-linker', nargs=1, - help='Select the linker {bfd, gold, lld, lld-*}', + help='Select the linker {bfd, gold, ld64, lld, lld-*}', when=is_linker_option_enabled) @depends('--enable-linker', c_compiler, developer_options, '--enable-gold', - extra_toolchain_flags, when=is_linker_option_enabled) + extra_toolchain_flags, target, lto.enabled, + when=is_linker_option_enabled) @checking('for linker', lambda x: x.KIND) @imports('os') @imports('shutil') def select_linker(linker, c_compiler, developer_options, enable_gold, - toolchain_flags): - - linker = linker[0] if linker else None + toolchain_flags, target, lto): + + if linker: + linker = linker[0] + elif lto and c_compiler.type == 'clang' and target.kernel != 'Darwin': + # If no linker was explicitly given, and building with clang for non-macOS, + # prefer lld. For macOS, we prefer ld64, or whatever the default linker is. + linker = 'lld' + else: + linker = None - if linker not in ('bfd', 'gold', 'lld', None) and not linker.startswith("lld-"): + def is_valid_linker(linker): + if target.kernel == 'Darwin': + valid_linkers = ('ld64', 'lld') + else: + valid_linkers = ('bfd', 'gold', 'lld') + if linker in valid_linkers: + return True + if 'lld' in valid_linkers and linker.startswith('lld-'): + return True + return False + + if linker and not is_valid_linker(linker): # Check that we are trying to use a supported linker die('Unsupported linker ' + linker) @@ -1602,13 +1615,34 @@ def select_linker(linker, c_compiler, developer_options, enable_gold, def try_linker(linker): # Generate the compiler flag - linker_flag = ["-fuse-ld=" + linker] if linker else [] + if linker == 'ld64': + linker_flag = ['-fuse-ld=ld'] + elif linker: + linker_flag = ["-fuse-ld=" + linker] + else: + linker_flag = [] cmd = cmd_base + linker_flag + version_check if toolchain_flags: cmd += toolchain_flags - cmd_output = check_cmd_output(*cmd).decode('utf-8') - if 'GNU ld' in cmd_output: + # ld64 doesn't have anything to print out a version. It does print out + # "ld64: For information on command line options please use 'man ld'." + # but that would require doing two attempts, one with --version, that + # would fail, and another with --help. + # Instead, abuse its LD_PRINT_OPTIONS feature to detect a message + # specific to it on stderr when it fails to process --version. + env = dict(os.environ) + env['LD_PRINT_OPTIONS'] = '1' + retcode, stdout, stderr = get_cmd_output(*cmd, env=env) + cmd_output = stdout.decode('utf-8') + stderr = stderr.decode('utf-8') + if retcode == 1 and 'Logging ld64 options' in stderr: + kind = 'ld64' + + elif retcode != 0: + return None + + elif 'GNU ld' in cmd_output: # We are using the normal linker kind = 'bfd' @@ -1627,13 +1661,21 @@ def select_linker(linker, c_compiler, developer_options, enable_gold, ) result = try_linker(linker) + if result is None: + if linker: + die("Could not use {} as linker".format(linker)) + die("Failed to find a linker") if (linker is None and enable_gold.origin == 'default' and developer_options and result.KIND == 'bfd'): - gold = try_linker('gold') - - if gold.KIND == 'gold': - result = gold + # try and use lld if available. + tried = try_linker('lld') + if tried is None or tried.KIND != 'lld': + tried = try_linker('gold') + if tried is None or tried.KIND != 'gold': + tried = None + if tried: + result = tried # If an explicit linker was given, error out if what we found is different. if linker and not linker.startswith(result.KIND): @@ -1644,7 +1686,7 @@ def select_linker(linker, c_compiler, developer_options, enable_gold, set_config('LD_IS_BFD', depends(select_linker.KIND) (lambda x: x == 'bfd' or None)) -set_config('LINKER_LDFLAGS', select_linker.LINKER_FLAG) +add_old_configure_assignment('LINKER_LDFLAGS', select_linker.LINKER_FLAG) js_option('--enable-clang-plugin', env='ENABLE_CLANG_PLUGIN', --- a/build/moz.configure/util.configure +++ b/build/moz.configure/util.configure @@ -19,20 +19,13 @@ def configure_error(message): their inputs from moz.configure usage.''' raise ConfigureError(message) -# A wrapper to obtain a process' output that returns the output generated -# by running the given command if it exits normally, and streams that -# output to log.debug and calls die or the given error callback if it -# does not. - +# A wrapper to obtain a process' output and return code. +# Returns a tuple (retcode, stdout, stderr). @imports(_from='__builtin__', _import='unicode') @imports('subprocess') -@imports('sys') -@imports(_from='mozbuild.configure.util', _import='LineIO') @imports(_from='mozbuild.shellutil', _import='quote') -def check_cmd_output(*args, **kwargs): - onerror = kwargs.pop('onerror', None) - +def get_cmd_output(*args, **kwargs): # subprocess on older Pythons can't handle unicode keys or values in # environment dicts. Normalize automagically so callers don't have to # deal with this. @@ -49,12 +42,24 @@ def check_cmd_output(*args, **kwargs): kwargs['env'] = normalized_env + log.debug('Executing: `%s`', quote(*args)) + proc = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, **kwargs) + stdout, stderr = proc.communicate() + return proc.wait(), stdout, stderr + + +# A wrapper to obtain a process' output that returns the output generated +# by running the given command if it exits normally, and streams that +# output to log.debug and calls die or the given error callback if it +# does not. +@imports(_from='mozbuild.configure.util', _import='LineIO') +@imports(_from='mozbuild.shellutil', _import='quote') +def check_cmd_output(*args, **kwargs): + onerror = kwargs.pop('onerror', None) + with log.queue_debug(): - log.debug('Executing: `%s`', quote(*args)) - proc = subprocess.Popen(args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, **kwargs) - stdout, stderr = proc.communicate() - retcode = proc.wait() + retcode, stdout, stderr = get_cmd_output(*args, **kwargs) if retcode == 0: return stdout --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -63,6 +63,8 @@ dnl ======================================================== USE_PTHREADS= _PTHREAD_LDFLAGS="" +LDFLAGS="$LDFLAGS $LINKER_LDFLAGS" + MOZ_DEFAULT_COMPILER if test -z "$JS_STANDALONE"; then --- a/old-configure.in +++ b/old-configure.in @@ -78,6 +78,8 @@ dnl ======================================================== MOZ_USE_PTHREADS= _PTHREAD_LDFLAGS="" +LDFLAGS="$LDFLAGS $LINKER_LDFLAGS" + MOZ_DEFAULT_COMPILER if test "$COMPILE_ENVIRONMENT"; then --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -384,8 +384,6 @@ class LinkFlags(BaseCompileFlags): self.flag_variables = ( ('OS', self._os_ldflags(), ('LDFLAGS',)), - ('LINKER', context.config.substs.get('LINKER_LDFLAGS'), - ('LDFLAGS',)), ('DEFFILE', None, ('LDFLAGS',)), ('MOZBUILD', None, ('LDFLAGS',)), ('FIX_LINK_PATHS', context.config.substs.get('MOZ_FIX_LINK_PATHS'), --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -242,7 +242,6 @@ class TestEmitterBasic(unittest.TestCase): def test_link_flags(self): reader = self.reader('link-flags', extra_substs={ 'OS_LDFLAGS': ['-Wl,rpath-link=/usr/lib'], - 'LINKER_LDFLAGS': ['-fuse-ld=gold'], 'MOZ_OPTIMIZE': '', 'MOZ_OPTIMIZE_LDFLAGS': ['-Wl,-dead_strip'], 'MOZ_DEBUG_LDFLAGS': ['-framework ExceptionHandling'], @@ -250,7 +249,6 @@ class TestEmitterBasic(unittest.TestCase): sources, ldflags, lib, compile_flags = self.read_topsrcdir(reader) self.assertIsInstance(ldflags, ComputedFlags) self.assertEqual(ldflags.flags['OS'], reader.config.substs['OS_LDFLAGS']) - self.assertEqual(ldflags.flags['LINKER'], reader.config.substs['LINKER_LDFLAGS']) self.assertEqual(ldflags.flags['MOZBUILD'], ['-Wl,-U_foo', '-framework Foo', '-x']) self.assertEqual(ldflags.flags['OPTIMIZE'], [])