From 8b3d798374a2c6b5026791e8ef5ce4fe6494f801 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 12 Jan 2022 13:35:07 +1100 Subject: [PATCH] CMake: add WITH_LINKER_MOLD option for GCC/Clang Unix platforms Can give considerably faster linking, especially on system with many cores. The mold linker recently reached 1.0, see: https://github.com/rui314/mold The current stable release of GCC can't use this linker via -fuse-ld=mold, so this patch uses the "-B" argument to add a binary directory containing an alternate "ld" command that points to "mold" (which is part of the default mold installation). Some timing tests for linking full builds for AMD TR 3970X: - BFD: 20.78 seconds. - LLD: 12.16 seconds. - GOLD: 7.21 seconds. - MOLD: 2.53 seconds. Ref D13807 Reviewed by: sergey, brecht --- CMakeLists.txt | 4 ++ .../cmake/platform/platform_unix.cmake | 69 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88c71899f8e..5d796a5c140 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -567,6 +567,10 @@ if(UNIX AND NOT APPLE) option(WITH_LINKER_LLD "Use ld.lld linker which is usually faster than ld.gold" OFF) mark_as_advanced(WITH_LINKER_LLD) endif() + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") + option(WITH_LINKER_MOLD "Use ld.mold linker which is usually faster than ld.gold & ld.lld." OFF) + mark_as_advanced(WITH_LINKER_MOLD) + endif() endif() option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 317ea0af4ae..4ba3f81fe93 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -692,9 +692,78 @@ if(CMAKE_COMPILER_IS_GNUCC) unset(LD_VERSION) endif() + # NOTE(@campbellbarton): Eventually mold will be able to use `-fuse-ld=mold`, + # however at the moment this only works for GCC 12.1+ (unreleased at time of writing). + # So a workaround is used here "-B" which points to another path to find system commands + # such as `ld`. + if(WITH_LINKER_MOLD) + find_program(MOLD_BIN "mold") + mark_as_advanced(MOLD_BIN) + if(NOT MOLD_BIN) + message(STATUS "The \"mold\" binary could not be found, using system linker!") + set(WITH_LINKER_MOLD OFF) + else() + # By default mold installs the binary to: + # - `{PREFIX}/bin/mold` as well as a symbolic-link in... + # - `{PREFIX}/lib/mold/ld`. + # (where `PREFIX` is typically `/usr/`). + # + # This block of code finds `{PREFIX}/lib/mold` from the `mold` binary. + # Other methods of searching for the path could also be made to work, + # we could even make our own directory and symbolic-link, however it's more + # convenient to use the one provided by mold. + # + # Use the binary path to "mold", to find the common prefix which contains "lib/mold". + # The parent directory: e.g. `/usr/bin/mold` -> `/usr/bin/`. + get_filename_component(MOLD_PREFIX "${MOLD_BIN}" DIRECTORY) + # The common prefix path: e.g. `/usr/bin/` -> `/usr/` to use as a hint. + get_filename_component(MOLD_PREFIX "${MOLD_PREFIX}" DIRECTORY) + # Find `{PREFIX}/lib/mold/ld`, store the directory component (without the `ld`). + # Then pass `-B {PREFIX}/lib/mold` to GCC so the `ld` located there overrides the default. + find_path( + MOLD_BIN_DIR "ld" + HINTS "${MOLD_PREFIX}" + PATH_SUFFIXES "lib/mold" "lib64/mold" + NO_DEFAULT_PATH + NO_CACHE + ) + if(NOT MOLD_BIN_DIR) + message(STATUS + "The mold linker could not find the directory containing the linker command " + "(typically \"${MOLD_PREFIX}/lib/mold\"), using system linker!") + set(WITH_LINKER_MOLD OFF) + endif() + unset(MOLD_PREFIX) + endif() + + if(WITH_LINKER_MOLD) + # GCC will search for `ld` in this directory first. + string(APPEND CMAKE_CXX_FLAGS " -B \"${MOLD_BIN_DIR}\"") + string(APPEND CMAKE_C_FLAGS " -B \"${MOLD_BIN_DIR}\"") + endif() + unset(MOLD_BIN) + unset(MOLD_BIN_DIR) + endif() + # CLang is the same as GCC for now. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") + + if(WITH_LINKER_MOLD) + find_program(MOLD_BIN "mold") + mark_as_advanced(MOLD_BIN) + if(NOT MOLD_BIN) + message(STATUS "The \"mold\" binary could not be found, using system linker!") + set(WITH_LINKER_MOLD OFF) + else() + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0) + string(APPEND CMAKE_EXE_LINKER_FLAGS " --ld-path=\"${MOLD_BIN}\"") + else() + string(APPEND CMAKE_EXE_LINKER_FLAGS " -fuse-ld=\"${MOLD_BIN}\"") + endif() + endif() + endif() + # Intel C++ Compiler elseif(CMAKE_C_COMPILER_ID MATCHES "Intel") # think these next two are broken