From 4bcc171bd247a02ff211051fa2b08fd625864299 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 25 Sep 2022 15:09:46 +0200 Subject: [PATCH] buildsystem: support choosing default linker Default linker can be set with DEFAULT_LINKER in options. Packages can influence linker selection both by positive and/or negative PKG_BUILD_FLAGS, eg +bfd or -gold. Positive build flags take priority over the default linker so eg DEFAULT_LINKER="gold" and PKG_BUILD_FLAGS="+bfd" will select bfd. Negative flags mean a specific linker should not be used, eg -gold prevents using gold. If the default linker is disabled via a build flag then any other available linker will be used. Optional linkers like gold have to be enabled with eg GOLD_SUPPORT="yes" in options. If an optional linker is not enabled it won't be a candidate for linker selection. So eg "+mold" will have no effect if MOLD_SUPPORT isn't set to "yes". Signed-off-by: Matthias Reichl --- config/functions | 55 ++++++++++++++++++++++++++++----- config/optimize | 6 ++-- config/show_config | 1 + distributions/LibreELEC/options | 3 ++ packages/readme.md | 3 +- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/config/functions b/config/functions index a377454622..459df94541 100644 --- a/config/functions +++ b/config/functions @@ -254,8 +254,50 @@ check_toolchain_config() { done } +# args: linker, default availability yes/no +linker_allowed() { + if flag_enabled "$1" "$2"; then + # bfd is always available, others need to be enabled with _SUPPORT="yes" + local linker_support="${1^^}_SUPPORT" + if [ "$1" = "bfd" ] || [ "${!linker_support}" = "yes" ]; then + return 0 + fi + fi + return 1 +} + +# return target linker to use for a package +get_target_linker() { + # all known linkers, in descending order of priority + # those are candidates for explicit opt-in via PKG_BUILD_FLAGS + local all_linkers="gold bfd" + + # linkers to choose from unless disabled via PKG_BUILD_FLAGS + local linker_candidates="${DEFAULT_LINKER:-bfd} ${all_linkers}" + + local linker + + # check if package prefers a specific linker + for linker in ${all_linkers}; do + if linker_allowed "${linker}" "no"; then + echo "${linker}" + return + fi + done + + # select linker which isn't disabled by PKG_BUILD_FLAGS + for linker in ${linker_candidates}; do + if linker_allowed "${linker}" "yes"; then + echo "${linker}" + return + fi + done + + # none of our linkers matched, use the compiler's default linker + echo "compiler_default" +} + setup_toolchain() { - local have_gold="no" if [ "$LTO_SUPPORT" = "yes" ]; then if flag_enabled "lto-parallel" "no"; then TARGET_CFLAGS+=" $FLAGS_OPTIM_LTO_PARALLEL $FLAGS_OPTIM_LTO_NO_FAT" @@ -278,15 +320,14 @@ setup_toolchain() { TARGET_LDFLAGS+=" $FLAGS_OPTIM_LTO_OFF" fi - # gold flag - if flag_enabled "gold" "$GOLD_SUPPORT" "only-disable"; then - TARGET_LDFLAGS+=" $LDFLAGS_OPTIM_GOLD" - have_gold="yes" - fi + local linker="$(get_target_linker)" + local linker_opts="LDFLAGS_OPTIM_LINKER_${linker^^}" + + TARGET_LDFLAGS+=" ${!linker_opts}" # compiler optimization, descending priority: speed, size, default if [ "${BUILD_WITH_DEBUG}" = "yes" ]; then - if [ "${SPLIT_DEBUG_INFO}" = "yes" -a "${have_gold}" = "yes" ]; then + if [ "${SPLIT_DEBUG_INFO}" = "yes" -a "${linker}" = "gold" ]; then TARGET_CFLAGS+=" $CFLAGS_OPTIM_DEBUG_SPLIT" TARGET_CXXFLAGS+=" $CXXFLAGS_OPTIM_DEBUG_SPLIT" TARGET_LDFLAGS+=" $LDFLAGS_OPTIM_DEBUG_SPLIT" diff --git a/config/optimize b/config/optimize index fe5f8ec625..14eb946aca 100644 --- a/config/optimize +++ b/config/optimize @@ -27,8 +27,10 @@ FLAGS_OPTIM_LTO_FAT="-ffat-lto-objects" FLAGS_OPTIM_LTO_OFF="-fno-lto" LDFLAGS_OPTIM_LTO_COMMON="-fuse-linker-plugin" -# gold flags -LDFLAGS_OPTIM_GOLD="-fuse-ld=gold" +# linker specific flags +LDFLAGS_OPTIM_LINKER_COMPILER_DEFAULT="" +LDFLAGS_OPTIM_LINKER_BFD="-fuse-ld=bfd" +LDFLAGS_OPTIM_LINKER_GOLD="-fuse-ld=gold" # default compiler optimization CFLAGS_OPTIM_DEFAULT="-O2 -fomit-frame-pointer -DNDEBUG" diff --git a/config/show_config b/config/show_config index edb636e1e2..7b7628465b 100644 --- a/config/show_config +++ b/config/show_config @@ -31,6 +31,7 @@ show_config() { config_message+="\n - CPU features:\t\t\t ${TARGET_FEATURES}" config_message+="\n - LTO (Link Time Optimization) support: ${LTO_SUPPORT}" config_message+="\n - GOLD (Google Linker) Support:\t ${GOLD_SUPPORT}" + config_message+="\n - Default Linker:\t\t\t ${DEFAULT_LINKER}" config_message+="\n - LLVM support:\t\t\t ${LLVM_SUPPORT}" config_message+="\n - DEBUG:\t\t\t\t ${DEBUG:-no}" config_message+="\n - CFLAGS:\t\t\t\t ${TARGET_CFLAGS}" diff --git a/distributions/LibreELEC/options b/distributions/LibreELEC/options index 2cfe469d4a..ccbd590a48 100644 --- a/distributions/LibreELEC/options +++ b/distributions/LibreELEC/options @@ -32,6 +32,9 @@ # GOLD (Google Linker) support GOLD_SUPPORT="yes" +# default linker (bfd / gold) + DEFAULT_LINKER="gold" + # HARDENING (security relevant linker and compiler flags) support HARDENING_SUPPORT="no" diff --git a/packages/readme.md b/packages/readme.md index 3724b7a329..c284c5f005 100644 --- a/packages/readme.md +++ b/packages/readme.md @@ -126,7 +126,8 @@ Set the variable `PKG_BUILD_FLAGS` in the `package.mk` to enable/disable the sin | lto-parallel | disabled | target, init | same as `lto` but enables parallel optimization at link stage. Only enable this if the package build doesn't run multiple linkers in parallel otherwise this can result in lots of parallel processes! | | lto-fat | disabled | target, init | same as `lto` but compile fat LTO objects (bytecode plus optimized assembly). This increases compile time but can be useful to create static libraries suitable both for LTO and non-LTO linking | | lto-off | disabled | target, init | explicitly disable LTO in the compiler and linker | -| gold | enabled by `GOLD_SUPPORT` | target, init | do not use GOLD-Llinker (can only disable) | +| bfd | - | target, init | `+bfd` prefers bfd linker over default linker, `-bfd` disables using bfd | +| gold | - | target, init | `+gold` prefers gold linker over default linker, `-gold` disables using gold | | parallel | enabled | all | `make` or `ninja` builds with multiple threads/processes (or not) | | strip | enabled | target | strips executables (or not) | | sysroot | enabled | target | installs the package to the sysroot folder (or not) |