Magnus pushed to branch wip/mangoiv/improve-linker-discovery at Glasgow Haskell Compiler / GHC Commits: e55e16b2 by mangoiv at 2026-07-15T13:39:12+02:00 configure: implement a saner linker discovery algorithm in dist/configure - - - - - bd3bfcf2 by mangoiv at 2026-07-15T14:59:05+02:00 hadrian: allow building binary dist tar without compression - - - - - 4 changed files: - distrib/configure.ac.in - hadrian/src/Rules/BinaryDist.hs - + m4/bindist_determine_linker.m4 - m4/find_merge_objects.m4 Changes: ===================================== distrib/configure.ac.in ===================================== @@ -175,7 +175,11 @@ AC_SUBST([CmmCPPSupportsG0]) dnl ** Which ld to use? dnl -------------------------------------------------------------- -FIND_LD([$target],[GccUseLdOpt]) +dnl currently if you pass $LD=foo, merge objs command will be set to $(which foo) +dnl which is not required by GHC and also wrong. +BINDIST_DETERMINE_LINKER([$target],[GccUseLdOpt]) +dnl at this point, we should have set LD in all cases, so FIND_MERGE_OBJECTS command can +dnl go off and do it's thing FIND_MERGE_OBJECTS() CONF_GCC_LINKER_OPTS_STAGE1="$CONF_GCC_LINKER_OPTS_STAGE1 $GccUseLdOpt" CONF_GCC_LINKER_OPTS_STAGE2="$CONF_GCC_LINKER_OPTS_STAGE2 $GccUseLdOpt" ===================================== hadrian/src/Rules/BinaryDist.hs ===================================== @@ -365,16 +365,17 @@ bindistRules = do -- Finally, we create the archive <root>/bindist/ghc-X.Y.Z-platform.tar.xz tarPath <- builderPath (Tar Create) - cmd [Cwd $ root -/- bindist_folder] tarPath - [ "-c", compressorTarFlag compressor, "-f" - , ghcVersionPretty <.> "tar" <.> compressorExtension compressor - , ghcVersionPretty ] + cmd [Cwd $ root -/- bindist_folder] tarPath $ + [ "-c" + , "-f" , compressorExtension compressor $ ghcVersionPretty <.> "tar" + , ghcVersionPretty ] <> compressorTarFlag compressor forM_ [("binary", buildBinDist), ("reloc-binary", buildBinDistReloc)] $ \(name, mk_bindist) -> do phony (name <> "-dist") $ mk_bindist Xz phony (name <> "-dist-gzip") $ mk_bindist Gzip phony (name <> "-dist-bzip2") $ mk_bindist Bzip2 phony (name <> "-dist-xz") $ mk_bindist Xz + phony (name <> "-dist-uncompressed") $ mk_bindist NoCompressor phony "binary-dist-cross" $ buildBinDistX "binary-dist-dir-cross" "bindist" Xz phony "binary-dist-stage3" $ buildBinDistX "binary-dist-dir-stage3" "bindist" Xz @@ -430,7 +431,7 @@ bindistRules = do fixup f | f `elem` ["INSTALL", "README"] = "distrib" -/- f | otherwise = f -data Compressor = Gzip | Bzip2 | Xz +data Compressor = Gzip | Bzip2 | Xz | NoCompressor deriving (Eq, Ord, Show) @@ -448,16 +449,18 @@ generateBuildMk BindistConfig{..} = do a =. b = a ++ " = " ++ b -- | Flag to pass to tar to use the given 'Compressor'. -compressorTarFlag :: Compressor -> String -compressorTarFlag Gzip = "--gzip" -compressorTarFlag Xz = "--xz" -compressorTarFlag Bzip2 = "--bzip" +compressorTarFlag :: Compressor -> [String] +compressorTarFlag Gzip = ["--gzip"] +compressorTarFlag Xz = ["--xz" ] +compressorTarFlag Bzip2 = ["--bzip"] +compressorTarFlag NoCompressor = [] -- | File extension to use for archives compressed with the given 'Compressor'. -compressorExtension :: Compressor -> String -compressorExtension Gzip = "gz" -compressorExtension Xz = "xz" -compressorExtension Bzip2 = "bz2" +compressorExtension :: Compressor -> String -> String +compressorExtension Gzip p = p <.> "gz" +compressorExtension Xz p = p <.> "xz" +compressorExtension Bzip2 p = p <.> "bz2" +compressorExtension NoCompressor p = p -- | A list of files that allow us to support a simple -- @./configure [...] && make install@ workflow. ===================================== m4/bindist_determine_linker.m4 ===================================== @@ -0,0 +1,134 @@ +# BINDIST_DETERMINE_LINKER +# ------------------------ +# +# This is used to determine the linker within the bindists configure +# +# Notes: +# - usually, linking works by invoking $CC +# - objects are merged using $LD directly +# - $LD is a configure variable and is meaningless to $CC +# - gcc only knows linker *flavours*, it cannot use paths +# which means that the linker path should not be an absolute path +# - clang konws --ld-path which means that it can be passed that +# flag and also merge objs can be an absolute path +# +# Algorithm: +# if $LD is set +# then if $CC accepts --ld-path=$(which $LD) +# then set --ld-path=$(which $LD), MergeObjsCommand=$(which $LD) +# else if $CC accepts --fuse-ld=$LD ($LD is a linker flavour, not an absolute path) +# then set -fuse-ld=$LD, MergeObjsCommand=$LD (not $(which ld)) +# else Reject with +# "$LD is not compatible with $CC you chose. This means that $LD is either +# an unsupported linker flavour or your $CC does not support absolute linker +# paths" +# else if --disable-ld-override is set or $target is macos +# then if $CC accepts --ld-path=$(which ld) +# then set --ld-path=$(which ld), set MergeObjsCommand=$(which ld) +# else set *no* flag (equivalent to --fuse-ld=ld, if you will), set MergeObjsCommand=ld +# else if $CC accepts --ld-path=$(which ld.lld) +# then set --ld-path=$(which ld.lld), MergeObjsCommand=$(which ld.lld) +# else if $CC accepts -fuse-ld=lld +# then set -fuse-ld=lld, MergeObjsCommand=ld.lld +# else set *no* flag (equivalent to --fuse-ld=ld), set MergeObjsCommand=ld +# +# $1 = the platform +# $2 = the variable to set with GHC options to configure gcc to use the chosen linker +# +AC_DEFUN([BINDIST_DETERMINE_LINKER],[ + AC_ARG_ENABLE(ld-override, + [AS_HELP_STRING([--disable-ld-override], + [Prevent GHC from overriding the default linker used by gcc. If ld-override is enabled GHC will try to tell gcc to use whichever linker is selected by the LD environment variable. [default=override enabled]])], + [], + [enable_ld_override=yes]) + + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_TARGET]) + + check_ld_path() { + AC_MSG_CHECKING([whether C compiler supports --ld-path=[$]1]) + ld_path="[$]1" + echo 'int main(void) { return 0; }' > conftest.c + if $CC -o conftest.o "--ld-path=$ld_path" $LDFLAGS conftest.c > /dev/null 2>&1 + then + AC_MSG_RESULT([yes]) + ld_path_ok=yes + else + AC_MSG_RESULT([no]) + ld_path_ok=no + fi + rm -f conftest.c conftest.o + } + + check_fuse_ld() { + AC_MSG_CHECKING([whether C compiler supports -fuse-ld=[$]1]) + ld="[$]1" + echo 'int main(void) {return 0;}' > conftest.c + if $CC -o conftest.o -fuse-ld=[$]1 $LDFLAGS conftest.c > /dev/null 2>&1 + then + AC_MSG_RESULT([yes]) + fuse_ld_ok=yes + else + AC_MSG_RESULT([no]) + fuse_ld_ok=no + fi + rm -f conftest.c conftest.o + } + + try_set_linker_to() { + AC_MSG_CHECKING([whether linker can be set to [$]1]) + tmp_ld=[$]1 + abs_path=`command -v "$tmp_ld" 2>/dev/null` # get absolute path of $tmp_ld if it isn't already one + ld_path_ok="no" + if test "z$abs_path" != "z" && check_ld_path "$abs_path" && test "x$ld_path_ok" = "xyes"; + then $2="--ld-path=$abs_path" + AC_CHECK_TARGET_TOOL([LD], [$abs_path]) + linker_set_successfully=yes + else # --ld-path does not work or $LD cannot be resolved to an absolute path + fuse_ld_ok=no + if check_fuse_ld "$tmp_ld" && test "x$fuse_ld_ok" = "xyes"; + then $2="-fuse-ld=$tmp_ld" + AC_CHECK_TARGET_TOOL([LD], [$tmp_ld]) + linker_set_successfully=yes + else AC_MSG_WARN(["$tmp_ld could not be set via either '--ld-path' or '-fuse-ld"]) + linker_set_successfully=no + fi + fi + } + + # we are lenient when $LD=ld and just act as if $LD wasn't set and + # enable-ld-override is off + if test "z$LD" != "z" && test "z$LD" != "zld"; + then linker_set_successfully=no + try_set_linker_to "$LD" + if test "z$linker_set_successfully" != "zyes"; + then AC_MSG_FAILURE([ $tmp_ld is an invalid linker. If your C compiler accepts the '--ld-path' flag, + \$LD can be either of an executable name that is in \$PATH *or* a path to an executable. + If your C compiler only supports the '--fuse-ld' flag, \$LD can only be one of the linker flavours supported + by it. Mind that if your C compiler supports '--ld-path', 'configure' will always prefer using an absolute path + to your linker as that is less error-prone.]) + fi + + else # $LD is not set -- we will do the ld-override non-sense + if test "x$enable_ld_override" = "xyes" && test "z$LD" != "zld" && case "$1" in + *-darwin) false ;; # don't do the ld override thing on macos + *) true ;; + esac; + then + AC_MSG_NOTICE(["enable ld override was set and no more specific linker was chosen by setting \$LD, trying to find best possible linker"]) + try_set_linker_to "lld" + if test "z$linker_set_successfully" != "zyes"; + then # ... bail out, just use ld in path + $2="" + AC_CHECK_TARGET_TOOL([LD], [ld]) + fi + else # ld override is not set and $LD not set either + $2="" + AC_CHECK_TARGET_TOOL([LD], [ld]) + fi + fi + + AC_MSG_NOTICE([linker discovery set $2 set to $$2]) + + CHECK_LD_COPY_BUG([$1]) +]) ===================================== m4/find_merge_objects.m4 ===================================== @@ -22,7 +22,6 @@ AC_DEFUN([CHECK_MERGE_OBJECTS],[ ]) AC_DEFUN([FIND_MERGE_OBJECTS],[ - AC_REQUIRE([FIND_LD]) if test -z ${MergeObjsCmd+x}; then AC_MSG_NOTICE([Setting cmd]) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b8774df10ffcb4c60992c2f7d172dd9... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b8774df10ffcb4c60992c2f7d172dd9... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help