From c8479c0d4dd930d87d98dc237e5f2413748673cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Thu, 21 Jul 2022 11:35:38 +0200 Subject: [PATCH] SCons: Refactor Linux linker options with `linker=` 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. Removes 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. --- .github/workflows/linux_builds.yml | 8 ++--- platform/linuxbsd/detect.py | 49 ++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 82e58434167..4e4a143f88d 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -31,12 +31,12 @@ jobs: proj-conv: true artifact: true - - name: Editor with doubles and GCC sanitizers (target=debug, tools=yes, float=64, tests=yes, use_asan=yes, use_ubsan=yes, ld.gold) + - name: Editor with doubles and GCC sanitizers (target=debug, tools=yes, float=64, tests=yes, use_asan=yes, use_ubsan=yes, linker=gold) cache-name: linux-editor-double-sanitizers target: debug tools: true tests: true - sconsflags: float=64 use_asan=yes use_ubsan=yes LINKFLAGS="-fuse-ld=gold" + sconsflags: float=64 use_asan=yes use_ubsan=yes linker=gold proj-test: true # Can be turned off for PRs that intentionally break compat with godot-cpp, # until both the upstream PR and the matching godot-cpp changes are merged. @@ -46,12 +46,12 @@ jobs: # Skip 2GiB artifact speeding up action. artifact: false - - name: Editor with clang sanitizers (target=debug, tools=yes, use_asan=yes, use_ubsan=yes, use_llvm=yes, use_lld=yes) + - name: Editor with clang sanitizers (target=debug, tools=yes, use_asan=yes, use_ubsan=yes, use_llvm=yes, linker=lld) cache-name: linux-editor-llvm-sanitizers target: debug tools: true tests: true - sconsflags: use_asan=yes use_ubsan=yes use_llvm=yes use_lld=yes + sconsflags: use_asan=yes use_ubsan=yes use_llvm=yes linker=lld bin: "./bin/godot.linuxbsd.tools.64.llvm.san" build-mono: false # Skip 2GiB artifact speeding up action. diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 63f0b7b3b9d..065250c40ea 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -1,6 +1,7 @@ import os import platform import sys +from methods import get_compiler_version, using_gcc def is_active(): @@ -27,9 +28,9 @@ 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_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_coverage", "Test Godot coverage", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), @@ -111,15 +112,32 @@ def configure(env): env["CXX"] = "clang++" 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 + 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_version = get_compiler_version(env) + cc_semver = (int(cc_version["major"]), int(cc_version["minor"])) + 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: - print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.") + 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_coverage"]: env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) @@ -164,16 +182,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"