Commit 60c26403 authored by Niklas Hambüchen's avatar Niklas Hambüchen Committed by Marge Bot

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"
parent 447864a9
Pipeline #10062 failed with stages
in 178 minutes and 18 seconds
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment