diff options
-rw-r--r-- | aclocal.m4 | 33 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 26 | ||||
-rw-r--r-- | compiler/main/SysTools.lhs | 117 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | distrib/configure.ac.in | 2 |
5 files changed, 137 insertions, 43 deletions
diff --git a/aclocal.m4 b/aclocal.m4 index 2ab4ad5ddb..0283206d67 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -535,18 +535,6 @@ AC_DEFUN([FPTOOLS_SET_C_LD_FLAGS], $2="$$2 -fno-stack-protector" fi - # Reduce memory usage when linking. See trac #5240. - if test -n "$LdHashSize31" - then - $3="$$3 -Wl,$LdHashSize31" - $4="$$4 $LdHashSize31" - fi - if test -n "$LdReduceMemoryOverheads" - then - $3="$$3 -Wl,$LdReduceMemoryOverheads" - $4="$$4 $LdReduceMemoryOverheads" - fi - rm -f conftest.c conftest.o AC_MSG_RESULT([done]) ]) @@ -921,27 +909,6 @@ $2=$fp_cv_$2 ])# FP_PROG_LD_FLAG -# FP_PROG_LD_HashSize31 -# ------------ -# Sets the output variable LdHashSize31 to --hash-size=31 if ld supports -# this flag. Otherwise the variable's value is empty. -AC_DEFUN([FP_PROG_LD_HashSize31], -[ -FP_PROG_LD_FLAG([--hash-size=31],[LdHashSize31]) -])# FP_PROG_LD_HashSize31 - - -# FP_PROG_LD_ReduceMemoryOverheads -# ------------ -# Sets the output variable LdReduceMemoryOverheads to -# --reduce-memory-overheads if ld supports this flag. -# Otherwise the variable's value is empty. -AC_DEFUN([FP_PROG_LD_ReduceMemoryOverheads], -[ -FP_PROG_LD_FLAG([--reduce-memory-overheads],[LdReduceMemoryOverheads]) -])# FP_PROG_LD_ReduceMemoryOverheads - - # FP_PROG_LD_BUILD_ID # ------------ diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index 0e96a2069c..64ae9b5699 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -129,6 +129,9 @@ module DynFlags ( -- * SSE isSse2Enabled, isSse4_2Enabled, + + -- * Linker information + LinkerInfo(..), ) where #include "HsVersions.h" @@ -742,7 +745,10 @@ data DynFlags = DynFlags { nextWrapperNum :: IORef Int, -- | Machine dependant flags (-m<blah> stuff) - sseVersion :: Maybe (Int, Int) -- (major, minor) + sseVersion :: Maybe (Int, Int), -- (major, minor) + + -- | Run-time linker information (what options we need, etc.) + rtldFlags :: IORef (Maybe LinkerInfo) } class HasDynFlags m where @@ -1201,6 +1207,7 @@ initDynFlags dflags = do refFilesToNotIntermediateClean <- newIORef [] refGeneratedDumps <- newIORef Set.empty refLlvmVersion <- newIORef 28 + refRtldFlags <- newIORef Nothing wrapperNum <- newIORef 0 canUseUnicodeQuotes <- do let enc = localeEncoding str = "‛’" @@ -1216,7 +1223,8 @@ initDynFlags dflags = do generatedDumps = refGeneratedDumps, llvmVersion = refLlvmVersion, nextWrapperNum = wrapperNum, - useUnicodeQuotes = canUseUnicodeQuotes + useUnicodeQuotes = canUseUnicodeQuotes, + rtldFlags = refRtldFlags } -- | The normal 'DynFlags'. Note that they is not suitable for use in this form @@ -1349,7 +1357,8 @@ defaultDynFlags mySettings = llvmVersion = panic "defaultDynFlags: No llvmVersion", interactivePrint = Nothing, nextWrapperNum = panic "defaultDynFlags: No nextWrapperNum", - sseVersion = Nothing + sseVersion = Nothing, + rtldFlags = panic "defaultDynFlags: no rtldFlags" } defaultWays :: Settings -> [Way] @@ -3519,3 +3528,14 @@ isSse2Enabled dflags = case platformArch (targetPlatform dflags) of isSse4_2Enabled :: DynFlags -> Bool isSse4_2Enabled dflags = sseVersion dflags >= Just (4,2) + +-- ----------------------------------------------------------------------------- +-- Linker information + +-- LinkerInfo contains any extra options needed by the system linker. +data LinkerInfo + = GnuLD [Option] + | GnuGold [Option] + | DarwinLD [Option] + | UnknownLD + deriving Eq diff --git a/compiler/main/SysTools.lhs b/compiler/main/SysTools.lhs index 5926114984..d43826a046 100644 --- a/compiler/main/SysTools.lhs +++ b/compiler/main/SysTools.lhs @@ -24,6 +24,8 @@ module SysTools ( figureLlvmVersion, readElfSection, + getLinkerInfo, + linkDynLib, askCc, @@ -596,13 +598,122 @@ figureLlvmVersion dflags = do text "Make sure you have installed LLVM"] return Nothing) return ver - + + +{- Note [Run-time linker info] + +See also: Trac #5240, Trac #6063 + +Before 'runLink', we need to be sure to get the relevant information +about the linker we're using at runtime to see if we need any extra +options. For example, GNU ld requires '--reduce-memory-overheads' and +'--hash-size=31' in order to use reasonable amounts of memory (see +trac #5240.) But this isn't supported in GNU gold. + +Generally, the linker changing from what was detected at ./configure +time has always been possible using -pgml, but on Linux it can happen +'transparently' by installing packages like binutils-gold, which +change what /usr/bin/ld actually points to. + +Clang vs GCC notes: + +For gcc, 'gcc -Wl,--version' gives a bunch of output about how to +invoke the linker before the version information string. For 'clang', +the version information for 'ld' is all that's output. For this +reason, we typically need to slurp up all of the standard error output +and look through it. + +Other notes: + +We cache the LinkerInfo inside DynFlags, since clients may link +multiple times. The definition of LinkerInfo is there to avoid a +circular dependency. + +-} + + +neededLinkArgs :: LinkerInfo -> [Option] +neededLinkArgs (GnuLD o) = o +neededLinkArgs (GnuGold o) = o +neededLinkArgs (DarwinLD o) = o +neededLinkArgs UnknownLD = [] + +-- Grab linker info and cache it in DynFlags. +getLinkerInfo :: DynFlags -> IO LinkerInfo +getLinkerInfo dflags = do + info <- readIORef (rtldFlags dflags) + case info of + Just v -> return v + Nothing -> do + v <- getLinkerInfo' dflags + writeIORef (rtldFlags dflags) (Just v) + return v + +-- See Note [Run-time linker info]. +getLinkerInfo' :: DynFlags -> IO LinkerInfo +getLinkerInfo' dflags = do + let platform = targetPlatform dflags + os = platformOS platform + (pgm,_) = pgm_l dflags + + -- Try to grab the info from the process output. + parseLinkerInfo stdo _stde _exitc + | any ("GNU ld" `isPrefixOf`) stdo = + -- GNU ld specifically needs to use less memory. This especially + -- hurts on small object files. Trac #5240. + return (GnuLD $ map Option ["-Wl,--hash-size=31", + "-Wl,--reduce-memory-overheads"]) + + | any ("GNU gold" `isPrefixOf`) stdo = + -- GNU gold does not require any special arguments. + return (GnuGold []) + + -- Unknown linker. + | otherwise = fail "invalid --version output, or linker is unsupported" + + -- Process the executable call + info <- catchIO (do + case os of + OSDarwin -> + -- Darwin has neither GNU Gold or GNU LD, but a strange linker + -- that doesn't support --version. We can just assume that's + -- what we're using. + return $ DarwinLD [] + OSMinGW32 -> + -- GHC doesn't support anything but GNU ld on Windows anyway. + -- Process creation is also fairly expensive on win32, so + -- we short-circuit here. + return $ GnuLD $ map Option ["-Wl,--hash-size=31", + "-Wl,--reduce-memory-overheads"] + _ -> do + -- In practice, we use the compiler as the linker here. Pass + -- -Wl,--version to get linker version info. + (exitc, stdo, stde) <- readProcessWithExitCode pgm + ["-Wl,--version"] "" + -- Split the output by lines to make certain kinds + -- of processing easier. In particular, 'clang' and 'gcc' + -- have slightly different outputs for '-Wl,--version', but + -- it's still easy to figure out. + parseLinkerInfo (lines stdo) (lines stde) exitc + ) + (\err -> do + debugTraceMsg dflags 2 + (text "Error (figuring out linker information):" <+> + text (show err)) + errorMsg dflags $ hang (text "Warning:") 9 $ + text "Couldn't figure out linker information!" $$ + text "Make sure you're using GNU ld, GNU gold" <+> + text "or the built in OS X linker, etc." + return UnknownLD) + return info runLink :: DynFlags -> [Option] -> IO () runLink dflags args = do + -- See Note [Run-time linker info] + linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags let (p,args0) = pgm_l dflags - args1 = map Option (getOpts dflags opt_l) - args2 = args0 ++ args1 ++ args + args1 = map Option (getOpts dflags opt_l) + args2 = args0 ++ args1 ++ args ++ linkargs mb_env <- getGccEnv args2 runSomethingFiltered dflags id "Linker" p args2 mb_env diff --git a/configure.ac b/configure.ac index 5fccdbed65..7bbeca6605 100644 --- a/configure.ac +++ b/configure.ac @@ -553,8 +553,6 @@ dnl ** look to see if we have a C compiler using an llvm back end. dnl FP_CC_LLVM_BACKEND -FP_PROG_LD_HashSize31 -FP_PROG_LD_ReduceMemoryOverheads FP_PROG_LD_IS_GNU FP_PROG_LD_BUILD_ID FP_PROG_LD_NO_COMPACT_UNWIND diff --git a/distrib/configure.ac.in b/distrib/configure.ac.in index 6b20f849d4..4a6944fe17 100644 --- a/distrib/configure.ac.in +++ b/distrib/configure.ac.in @@ -72,8 +72,6 @@ AC_SUBST([LdCmd]) FP_GCC_VERSION AC_PROG_CPP -FP_PROG_LD_HashSize31 -FP_PROG_LD_ReduceMemoryOverheads FP_PROG_LD_IS_GNU FP_PROG_LD_BUILD_ID FP_PROG_LD_NO_COMPACT_UNWIND |