Hadrian: support extra libraries + OSX rpath
authorAlec Theriault <alec.theriault@gmail.com>
Mon, 7 Jan 2019 19:38:11 +0000 (11:38 -0800)
committerBen Gamari <ben@smart-cactus.org>
Wed, 16 Jan 2019 19:16:51 +0000 (14:16 -0500)
Summary:
This fixes some of the issues that surfaced when trying to build
dynamic GHC on OSX. Unfortunately, due some other `libffi`
issues, this doesn't completely fix dynamic builds on OSX.

  - Use 'extra-libraries' from .cabal files instead of hardcoding
    which packages need which extra libs. Also add support for
    'extra-lib-dirs'.

  - Make sure Hadrian looks in the right places to support both
    plain '<pkg>.buildinfo' and '<pkg>.buildinfo.in' files.

  - Make the '-rpath' support more robust across OS's (it previously
    didn't work on OSX and possibly windows either).

Reviewers: angerman, alpmestan, adamse, DavidEichmann, bgamari, Phyx

Subscribers: rwbarton, carter

GHC Trac Issues: #15990

Differential Revision: https://phabricator.haskell.org/D5409

hadrian/src/Context.hs
hadrian/src/Hadrian/Haskell/Cabal/Parse.hs
hadrian/src/Oracles/Setting.hs
hadrian/src/Rules/BinaryDist.hs
hadrian/src/Settings/Builders/Ghc.hs

index 8036eb0..7943e6d 100644 (file)
@@ -51,12 +51,15 @@ libPath :: Context -> Action FilePath
 libPath context = buildRoot <&> (-/- libDir context)
 
 -- | Get the directory name for binary distribution files
--- <arch>-<os>-ghc-<version>.
+-- @<arch>-<os>-ghc-<version>@.
+--
+-- We preform some renaming to accomodate Cabal's slightly different naming
+-- conventions (see 'cabalOsString' and 'cabalArchString').
 distDir :: Action FilePath
 distDir = do
     version        <- setting ProjectVersion
-    hostOs         <- setting BuildOs
-    hostArch       <- setting BuildArch
+    hostOs         <- cabalOsString <$> setting BuildOs
+    hostArch       <- cabalArchString <$> setting BuildArch
     return $ hostArch ++ "-" ++ hostOs ++ "-ghc-" ++ version
 
 pkgFile :: Context -> String -> String -> Action FilePath
index bb2f0be..9952701 100644 (file)
@@ -208,7 +208,7 @@ resolveContextData context@Context {..} = do
     -- Create the @cabal_macros.h@, ...
     -- Note: the @cPath@ is ignored. The path that's used is the 'buildDir' path
     -- from the local build info @lbi@.
-    pdi <- liftIO $ getHookedBuildInfo (pkgPath package)
+    pdi <- liftIO $ getHookedBuildInfo [pkgPath package, cPath -/- "build"]
     let pd'  = C.updatePackageDescription pdi pd
         lbi' = lbi { C.localPkgDescr = pd' }
     liftIO $ C.initialBuildSteps cPath pd' lbi' C.silent
@@ -282,12 +282,12 @@ resolveContextData context@Context {..} = do
           , depLdOpts       = forDeps Installed.ldOptions
           , buildGhciLib    = C.withGHCiLib lbi' }
 
-getHookedBuildInfo :: FilePath -> IO C.HookedBuildInfo
-getHookedBuildInfo baseDir = do
-    -- TODO: We should probably better generate this in the build directory,
-    -- rather than in the base directory? However, @configure@ is run in the
-    -- base directory.
+-- | Look for a @.buildinfo@ in all of the specified directories, stopping on
+-- the first one we find.
+getHookedBuildInfo :: [FilePath] -> IO C.HookedBuildInfo
+getHookedBuildInfo [] = return C.emptyHookedBuildInfo
+getHookedBuildInfo (baseDir:baseDirs) = do
     maybeInfoFile <- C.findHookedPackageDesc baseDir
     case maybeInfoFile of
-        Nothing       -> return C.emptyHookedBuildInfo
+        Nothing       -> getHookedBuildInfo baseDirs
         Just infoFile -> C.readHookedBuildInfo C.silent infoFile
index 5197b8e..02ac42e 100644 (file)
@@ -3,7 +3,7 @@ module Oracles.Setting (
     getSettingList,  anyTargetPlatform, anyTargetOs, anyTargetArch, anyHostOs,
     ghcWithInterpreter, ghcEnableTablesNextToCode, useLibFFIForAdjustors,
     ghcCanonVersion, cmdLineLengthLimit, iosHost, osxHost, windowsHost,
-    topDirectory, libsuf
+    hostSupportsRPaths, topDirectory, libsuf
     ) where
 
 import Hadrian.Expression
@@ -166,6 +166,14 @@ iosHost = anyHostOs ["ios"]
 osxHost :: Action Bool
 osxHost = anyHostOs ["darwin"]
 
+-- | Check whether the host OS supports the @-rpath@ linker option when
+-- using dynamic linking.
+--
+-- TODO: Windows supports lazy binding (but GHC doesn't currently support
+--       dynamic way on Windows anyways).
+hostSupportsRPaths :: Action Bool
+hostSupportsRPaths = anyHostOs ["linux", "darwin", "freebsd"]
+
 -- | Check whether the host OS setting is set to @"mingw32"@ or @"cygwin32"@.
 windowsHost :: Action Bool
 windowsHost = anyHostOs ["mingw32", "cygwin32"]
index a589c7a..f847af9 100644 (file)
@@ -98,14 +98,12 @@ bindistRules = do
 
         version        <- setting ProjectVersion
         targetPlatform <- setting TargetPlatformFull
-        cabalHostOs    <- cabalOsString <$> setting BuildOs
-        cabalHostArch  <- cabalArchString <$> setting BuildArch
+        distDir        <- Context.distDir
         rtsDir         <- pkgIdentifier rts
 
         let ghcBuildDir      = root -/- stageString Stage1
             bindistFilesDir  = root -/- "bindist" -/- ghcVersionPretty
             ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform
-            distDir          = cabalHostArch ++ "-" ++ cabalHostOs ++ "-ghc-" ++ version
             rtsIncludeDir    = ghcBuildDir -/- "lib" -/- distDir -/- rtsDir
                                -/- "include"
 
index a605873..4957de7 100644 (file)
@@ -43,10 +43,10 @@ compileC = builder (Ghc CompileCWithGhc) ? do
 ghcLinkArgs :: Args
 ghcLinkArgs = builder (Ghc LinkHs) ? do
     pkg     <- getPackage
-    libs    <- pkg == hp2ps ? pure ["m"]
-    intLib  <- getIntegerPackage
-    gmpLibs <- notStage0 ? intLib == integerGmp ? pure ["gmp"]
+    libs    <- getContextData extraLibs
+    libDirs <- getContextData extraLibDirs
     dynamic <- requiresDynamic
+    darwin  <- expr osxHost
 
     -- Relative path from the output (rpath $ORIGIN).
     originPath <- dropFileName <$> getOutput
@@ -56,20 +56,21 @@ ghcLinkArgs = builder (Ghc LinkHs) ? do
     let
         distPath = libPath' -/- distDir
         originToLibsDir = makeRelativeNoSysLink originPath distPath
+        rpath | darwin = "@loader_path" -/- originToLibsDir
+              | otherwise = "$ORIGIN" -/- originToLibsDir
 
     mconcat [ dynamic ? mconcat
                 [ arg "-dynamic"
-                -- TODO what about windows / OSX?
-                , notStage0 ? pure
-                    [ "-optl-Wl,-rpath"
-                    , "-optl-Wl," ++ ("$ORIGIN" -/- originToLibsDir) ]
+                -- TODO what about windows?
+                , isLibrary pkg ? pure [ "-shared", "-dynload", "deploy" ]
+                , notStage0 ?
+                  hostSupportsRPaths ? arg ("-optl-Wl,-rpath," ++ rpath)
                 ]
-            , (dynamic && isLibrary pkg) ?
-                pure [ "-shared", "-dynload", "deploy" ]
             , arg "-no-auto-link-packages"
             ,      nonHsMainPackage pkg  ? arg "-no-hs-main"
             , not (nonHsMainPackage pkg) ? arg "-rtsopts"
-            , pure [ "-optl-l" ++           lib | lib <- libs ++ gmpLibs ]
+            , pure [ "-l" ++ lib    | lib <-    libs    ]
+            , pure [ "-L" ++ libDir | libDir <- libDirs ]
             ]
 
 findHsDependencies :: Args