summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Hambüchen <mail@nh2.me>2019-08-18 06:03:10 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-09-11 09:44:23 -0400
commit60c264030f5ab8d31d42c3b6697f1f6205ca519f (patch)
tree4252c83af7fc5472e365e581856bf774632015b3
parent447864a94a1679b5b079e08bb7208a0005381cef (diff)
downloadhaskell-60c264030f5ab8d31d42c3b6697f1f6205ca519f.tar.gz
linker: Move -optl flags to end of linker invocation.
Until now, giving `-optl` linker flags to `ghc` on the command line placed them in the wrong place in the `ld` command line: They were given before all the Haskell libararies, when they should appear after. Background: Most linkers like `ld.bfd` and `ld.gold`, but not the newer LLVM `lld`, work in a way where the order of `-l` flags given matters; earlier `-lmylib1` flags are supposed to create "holes" for linker symbols that are to be filled with later `lmylib2` flags that "fill the holes" for these symbols. As discovered in https://github.com/haskell/cabal/pull/5451#issuecomment-518001240, the `-optl` flags appeared before e.g. the -lHStext-1.2.3.1 -lHSbinary-0.8.6.0 -lHScontainers-0.6.0.1 flags that GHC added at the very end. Haskell libraries typically depend on C libraries, so `-lHS*` flags will create holes for the C libraries to fill in, but that only works when those libraries' `-l` flags are given **after** the `-lHS*` flags; until now they were given before, which was wrong. This meant that Cabal's `--ld-options` flag and `ld-options` `.cabal` file field were pretty ineffective, unless you used the `--ld-option=--start-group` hack as (https://github.com/haskell/cabal/pull/5451#issuecomment-406761676) that convinces the classical linkers to not be dependent on the order of linker flags given. This commit fixes the problem by simply flipping the order, putting `-optl` flags at the end, after Haskell libraries. The code change is effectively only `args1 ++ args` -> `args ++ args1` but the commit also renames the variables for improved clarity. Simple way to test it: ghc --make Main.hs -fforce-recomp -v -optl-s on a `Main.hs` like: import qualified Data.Set as Set main = print $ Set.fromList "hello"
-rw-r--r--compiler/main/SysTools/Tasks.hs8
1 files changed, 6 insertions, 2 deletions
diff --git a/compiler/main/SysTools/Tasks.hs b/compiler/main/SysTools/Tasks.hs
index 9ee3ba467c..838ab64717 100644
--- a/compiler/main/SysTools/Tasks.hs
+++ b/compiler/main/SysTools/Tasks.hs
@@ -240,10 +240,14 @@ figureLlvmVersion dflags = traceToolCommand dflags "llc" $ do
runLink :: DynFlags -> [Option] -> IO ()
runLink dflags args = traceToolCommand dflags "linker" $ do
-- See Note [Run-time linker info]
+ --
+ -- `-optl` args come at the end, so that later `-l` options
+ -- given there manually can fill in symbols needed by
+ -- Haskell libaries coming in via `args`.
linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags
let (p,args0) = pgm_l dflags
- args1 = map Option (getOpts dflags opt_l)
- args2 = args0 ++ linkargs ++ args1 ++ args
+ optl_args = map Option (getOpts dflags opt_l)
+ args2 = args0 ++ linkargs ++ args ++ optl_args
mb_env <- getGccEnv args2
runSomethingResponseFile dflags ld_filter "Linker" p args2 mb_env
where