diff options
author | Niklas Hambüchen <mail@nh2.me> | 2019-08-18 06:03:10 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2019-09-11 09:44:23 -0400 |
commit | 60c264030f5ab8d31d42c3b6697f1f6205ca519f (patch) | |
tree | 4252c83af7fc5472e365e581856bf774632015b3 | |
parent | 447864a94a1679b5b079e08bb7208a0005381cef (diff) | |
download | haskell-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.hs | 8 |
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 |