Bug 1802228 - Select a host linker in the same manner we do for the target linker. r=firefox-build-system-reviewers,ahochheiden

Differential Revision: https://phabricator.services.mozilla.com/D162912
This commit is contained in:
Mike Hommey 2022-11-25 01:56:38 +00:00
parent 29ab6a0f40
commit b2cc8ec2c0
3 changed files with 215 additions and 171 deletions

View file

@ -1545,192 +1545,234 @@ def enable_linker(linker):
return linker return linker
@depends( @template
"--enable-linker", def select_linker_tmpl(host_or_target):
c_compiler, if host_or_target is target:
developer_options, deps = depends(
extra_toolchain_flags, "--enable-linker",
target, c_compiler,
when=is_linker_option_enabled, developer_options,
) extra_toolchain_flags,
@checking("for linker", lambda x: x.KIND) target,
@imports("os") when=is_linker_option_enabled,
@imports("shutil")
def select_linker(linker, c_compiler, developer_options, toolchain_flags, target):
if linker:
linker = linker[0]
else:
linker = None
def is_valid_linker(linker):
if target.kernel == "Darwin":
valid_linkers = ("ld64", "lld")
else:
valid_linkers = ("bfd", "gold", "lld", "mold")
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)
# Check the kind of linker
version_check = ["-Wl,--version"]
cmd_base = c_compiler.wrapper + [c_compiler.compiler] + c_compiler.flags
def try_linker(linker):
# Generate the compiler flag
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
# 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"
# Some locales might not print out the strings we are looking for, so
# ensure consistent output.
env["LC_ALL"] = "C"
retcode, stdout, stderr = get_cmd_output(*cmd, env=env)
if retcode == 1 and "Logging ld64 options" in stderr:
kind = "ld64"
elif retcode != 0:
return None
elif "mold" in stdout:
kind = "mold"
elif "GNU ld" in stdout:
# We are using the normal linker
kind = "bfd"
elif "GNU gold" in stdout:
kind = "gold"
elif "LLD" in stdout:
kind = "lld"
else:
kind = "unknown"
if kind == "unknown" or is_valid_linker(kind):
return namespace(
KIND=kind,
LINKER_FLAG=linker_flag,
)
result = try_linker(linker)
if result is None and linker:
die("Could not use {} as linker".format(linker))
if (
linker is None
and target.kernel == "Darwin"
and c_compiler.type == "clang"
and (
(developer_options and c_compiler.version >= "13.0")
or c_compiler.version >= "15.0"
) )
): host_or_target_str = "target"
result = try_linker("lld") else:
elif ( deps = depends(
linker is None dependable(None),
and developer_options host_c_compiler,
and (result is None or result.KIND in ("bfd", "gold")) developer_options,
): dependable(None),
# try and use lld if available. host,
tried = try_linker("lld") )
if (result is None or result.KIND != "gold") and ( host_or_target_str = "host"
tried is None or tried.KIND != "lld"
@deps
@checking(f"for {host_or_target_str} linker", lambda x: x.KIND)
@imports("os")
@imports("shutil")
def select_linker(linker, c_compiler, developer_options, toolchain_flags, target):
if linker:
linker = linker[0]
else:
linker = None
def is_valid_linker(linker):
if target.kernel == "Darwin":
valid_linkers = ("ld64", "lld")
else:
valid_linkers = ("bfd", "gold", "lld", "mold")
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)
# Check the kind of linker
version_check = ["-Wl,--version"]
cmd_base = c_compiler.wrapper + [c_compiler.compiler] + c_compiler.flags
def try_linker(linker):
# Generate the compiler flag
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
# 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"
# Some locales might not print out the strings we are looking for, so
# ensure consistent output.
env["LC_ALL"] = "C"
retcode, stdout, stderr = get_cmd_output(*cmd, env=env)
if retcode == 1 and "Logging ld64 options" in stderr:
kind = "ld64"
elif retcode != 0:
return None
elif "mold" in stdout:
kind = "mold"
elif "GNU ld" in stdout:
# We are using the normal linker
kind = "bfd"
elif "GNU gold" in stdout:
kind = "gold"
elif "LLD" in stdout:
kind = "lld"
else:
kind = "unknown"
if kind == "unknown" or is_valid_linker(kind):
return namespace(
KIND=kind,
LINKER_FLAG=linker_flag,
)
result = try_linker(linker)
if result is None and linker:
die("Could not use {} as linker".format(linker))
if (
linker is None
and target.kernel == "Darwin"
and c_compiler.type == "clang"
and (
(developer_options and c_compiler.version >= "13.0")
or c_compiler.version >= "15.0"
)
): ):
tried = try_linker("gold") result = try_linker("lld")
if tried is None or tried.KIND != "gold": elif (
tried = None linker is None
if tried: and developer_options
result = tried and (result is None or result.KIND in ("bfd", "gold"))
):
# try and use lld if available.
tried = try_linker("lld")
if (result is None or result.KIND != "gold") and (
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 result is None: if result is None:
die("Failed to find an adequate linker") die("Failed to find an adequate linker")
# If an explicit linker was given, error out if what we found is different. # If an explicit linker was given, error out if what we found is different.
if linker and not linker.startswith(result.KIND): if linker and not linker.startswith(result.KIND):
die("Could not use {} as linker".format(linker)) die("Could not use {} as linker".format(linker))
return result return result
return select_linker
select_linker = select_linker_tmpl(target)
set_config("LINKER_KIND", select_linker.KIND) set_config("LINKER_KIND", select_linker.KIND)
@depends_if( @template
select_linker, def linker_ldflags_tmpl(host_or_target):
target, if host_or_target is target:
target_sysroot, deps = depends_if(
target_multiarch_dir, select_linker,
android_platform, target,
c_compiler, target_sysroot,
developer_options, target_multiarch_dir,
) android_platform,
@imports("os") c_compiler,
def linker_ldflags( developer_options,
linker, )
target, else:
sysroot, deps = depends_if(
multiarch_dir, select_linker_tmpl(host),
android_platform, host,
c_compiler, host_sysroot,
developer_options, host_multiarch_dir,
): dependable(None),
flags = list((linker and linker.LINKER_FLAG) or []) host_c_compiler,
# rpath-link is irrelevant to wasm, see for more info https://github.com/emscripten-core/emscripten/issues/11076. developer_options,
if sysroot.path and multiarch_dir and target.os != "WASI": )
for d in ("lib", "usr/lib"):
multiarch_lib_dir = os.path.join(sysroot.path, d, multiarch_dir) @deps
if os.path.exists(multiarch_lib_dir): @imports("os")
# Non-Debian-patched binutils linkers (both BFD and gold) don't lookup def linker_ldflags(
# in multi-arch directories. linker,
flags.append("-Wl,-rpath-link,%s" % multiarch_lib_dir) target,
# GCC also needs -L. sysroot,
if c_compiler.type == "gcc": multiarch_dir,
flags.append("-L%s" % multiarch_lib_dir) android_platform,
if c_compiler.type == "gcc" and sysroot.bootstrapped and sysroot.stdcxx_version: c_compiler,
flags.append( developer_options,
"-L{}/usr/lib/gcc/{}/{}".format(
sysroot.path, multiarch_dir, sysroot.stdcxx_version
)
)
if android_platform:
flags.append("-L{}/usr/lib".format(android_platform))
flags.append("-Wl,--rpath-link={}/usr/lib".format(android_platform))
flags.append("--sysroot")
flags.append(android_platform)
if (
developer_options
and linker
and linker.KIND == "lld"
and target.kernel != "WINNT"
): ):
flags.append("-Wl,-O0") flags = list((linker and linker.LINKER_FLAG) or [])
return flags # rpath-link is irrelevant to wasm, see for more info https://github.com/emscripten-core/emscripten/issues/11076.
if sysroot.path and multiarch_dir and target.os != "WASI":
for d in ("lib", "usr/lib"):
multiarch_lib_dir = os.path.join(sysroot.path, d, multiarch_dir)
if os.path.exists(multiarch_lib_dir):
# Non-Debian-patched binutils linkers (both BFD and gold) don't lookup
# in multi-arch directories.
flags.append("-Wl,-rpath-link,%s" % multiarch_lib_dir)
# GCC also needs -L.
if c_compiler.type == "gcc":
flags.append("-L%s" % multiarch_lib_dir)
if (
c_compiler.type == "gcc"
and sysroot.bootstrapped
and sysroot.stdcxx_version
):
flags.append(
"-L{}/usr/lib/gcc/{}/{}".format(
sysroot.path, multiarch_dir, sysroot.stdcxx_version
)
)
if android_platform:
flags.append("-L{}/usr/lib".format(android_platform))
flags.append("-Wl,--rpath-link={}/usr/lib".format(android_platform))
flags.append("--sysroot")
flags.append(android_platform)
if (
developer_options
and linker
and linker.KIND == "lld"
and target.kernel != "WINNT"
):
flags.append("-Wl,-O0")
return flags
return linker_ldflags
linker_ldflags = linker_ldflags_tmpl(target)
add_old_configure_assignment("LINKER_LDFLAGS", linker_ldflags) add_old_configure_assignment("LINKER_LDFLAGS", linker_ldflags)
add_old_configure_assignment("HOST_LINKER_LDFLAGS", linker_ldflags_tmpl(host))
# There's a wrinkle with MinGW: linker configuration is not enabled, so # There's a wrinkle with MinGW: linker configuration is not enabled, so
# `select_linker` is never invoked. Hard-code around it. # `select_linker` is never invoked. Hard-code around it.

View file

@ -58,6 +58,7 @@ USE_PTHREADS=
_PTHREAD_LDFLAGS="" _PTHREAD_LDFLAGS=""
LDFLAGS="$LDFLAGS $LINKER_LDFLAGS" LDFLAGS="$LDFLAGS $LINKER_LDFLAGS"
HOST_LDFLAGS="$HOST_LDFLAGS $HOST_LINKER_LDFLAGS"
if test -z "$JS_STANDALONE"; then if test -z "$JS_STANDALONE"; then
autoconfmk=autoconf-js.mk autoconfmk=autoconf-js.mk

View file

@ -58,6 +58,7 @@ MOZ_USE_PTHREADS=
_PTHREAD_LDFLAGS="" _PTHREAD_LDFLAGS=""
LDFLAGS="$LDFLAGS $LINKER_LDFLAGS" LDFLAGS="$LDFLAGS $LINKER_LDFLAGS"
HOST_LDFLAGS="$HOST_LDFLAGS $HOST_LINKER_LDFLAGS"
if test "$COMPILE_ENVIRONMENT"; then if test "$COMPILE_ENVIRONMENT"; then
MOZ_ANDROID_NDK MOZ_ANDROID_NDK