SCons: Refactor Linux linker options with linker=<bfd|gold|lld|mold>

The new option is `linker` and lets the user specify the argument to
the`-fuse_ld=` linker flag directly. The supported options are:

- `default`: No change, typically uses GNU ld (bfd) unless the user or
  distro picked a different default `/usr/bin/ld`.
- `bfd`: GNU ld from binutils
- `gold`: GNU gold from binutils
- `lld`: lld from LLVM
- `mold`: mold, an extremely fast modern linker, not (yet) intended for
  use in production but great for development speed. Provided by distro
  `mold` package or needs to be compiled from source and installed to
  `/usr` otherwise.

Deprecates the `use_lld=yes` option, and make lld actually usable with
GCC too.

Not all the above are compatible or recommend for LTO, we recommend
using GNU ld with GCC LTO, or lld with LLVM ThinLTO.

(cherry picked from commit 534f85add1daec0669a1f18edd2cc456f9a296ef)
This commit is contained in:
Rémi Verschelde 2022-07-21 11:35:38 +02:00
parent e71cf7c560
commit 5bb3063eec
2 changed files with 41 additions and 18 deletions

View file

@ -27,11 +27,11 @@ jobs:
build-mono: true
artifact: true
- name: Editor and sanitizers (target=debug, tools=yes, use_asan=yes, use_ubsan=yes)
- name: Editor and sanitizers (target=debug, tools=yes, use_asan=yes, use_ubsan=yes, linker=gold)
cache-name: linux-editor-sanitizers
target: debug
tools: true
sconsflags: use_asan=yes use_ubsan=yes
sconsflags: use_asan=yes use_ubsan=yes linker=gold
test: true
bin: "./bin/godot.x11.tools.64s"
build-mono: false

View file

@ -64,9 +64,10 @@ def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
return [
EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_lld", "Use the LLD linker", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
BoolVariable("use_lld", "Use the LLD linker (deprecated, use `linker=lld` instead).", False),
BoolVariable("use_thinlto", "Use ThinLTO (LLVM only, requires linker=lld, implies use_lto=yes)", False),
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
@ -146,14 +147,37 @@ def configure(env):
env.extra_suffix = ".llvm" + env.extra_suffix
if env["use_lld"]:
if env["use_llvm"]:
env.Append(LINKFLAGS=["-fuse-ld=lld"])
if env["use_thinlto"]:
# A convenience so you don't need to write use_lto too when using SCons
env["use_lto"] = True
else:
print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.")
if env["linker"] != "default":
print("Can't specify both `use_lld=yes` and a non-default `linker`. Remove `use_lld=yes`.")
sys.exit(255)
print("The `use_lld=yes` option is deprecated, use `linker=lld` instead.")
env["linker"] == "lld"
if env["linker"] != "default":
print("Using linker program: " + env["linker"])
if env["linker"] == "mold" and using_gcc(env): # GCC < 12.1 doesn't support -fuse-ld=mold.
cc_semver = tuple(get_compiler_version(env))
if cc_semver < (12, 1):
found_wrapper = False
for path in ["/usr/libexec", "/usr/local/libexec", "/usr/lib", "/usr/local/lib"]:
if os.path.isfile(path + "/mold/ld"):
env.Append(LINKFLAGS=["-B" + path + "/mold"])
found_wrapper = True
break
if not found_wrapper:
print("Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local.")
sys.exit(255)
else:
env.Append(LINKFLAGS=["-fuse-ld=mold"])
else:
env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]])
if env["use_thinlto"]:
if not env["use_llvm"] or env["linker"] != "lld":
print("ThinLTO is only compatible with LLVM and the LLD linker, use `use_llvm=yes linker=lld`.")
sys.exit(255)
else:
env["use_lto"] = True # ThinLTO implies LTO
if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]:
env.extra_suffix += "s"
@ -192,16 +216,15 @@ def configure(env):
env.Append(LINKFLAGS=["-fsanitize=memory"])
if env["use_lto"]:
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
if env["use_thinlto"]:
env.Append(CCFLAGS=["-flto=thin"])
env.Append(LINKFLAGS=["-flto=thin"])
elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
else:
if env["use_lld"] and env["use_thinlto"]:
env.Append(CCFLAGS=["-flto=thin"])
env.Append(LINKFLAGS=["-flto=thin"])
else:
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
if not env["use_llvm"]:
env["RANLIB"] = "gcc-ranlib"