summaryrefslogtreecommitdiff
path: root/Build
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-04-22 13:33:29 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-04-22 13:33:29 -0400
commit032c802d45c7872f704de1faf0733740b256444d (patch)
treee35c61900c3d4d3b5cb746d50aa69e42e099ae71 /Build
parent3f2a065f9079fe9c7e62e6d039475698a8dac675 (diff)
handle rpath in OSXMkLibs
Now oberon has some binaries and libraries that use rpath, so I had to put in this ugly hack to replace the @rapth/lib with the lib in the app. This was particularly tricky for libraries that use @rpath because I could not find a way to extract the rpath from the library. (Only from the executable, by running it.. ugh!) The hack I put in place may fail if multiple different libraries use rpath to refer to other libraries, and the "@rpath/lib" string is the same, but actually refers to different files.
Diffstat (limited to 'Build')
-rw-r--r--Build/OSXMkLibs.hs71
-rw-r--r--Build/Standalone.hs13
2 files changed, 59 insertions, 25 deletions
diff --git a/Build/OSXMkLibs.hs b/Build/OSXMkLibs.hs
index 5225f12bf..ed12a945f 100644
--- a/Build/OSXMkLibs.hs
+++ b/Build/OSXMkLibs.hs
@@ -22,6 +22,7 @@ import Utility.Process
import Utility.Monad
import Utility.SafeCommand
import Utility.Path
+import Utility.Exception
import qualified Data.Map as M
import qualified Data.Set as S
@@ -29,16 +30,16 @@ import qualified Data.Set as S
type LibMap = M.Map FilePath String
{- Recursively find and install libs, until nothing new to install is found. -}
-mklibs :: FilePath -> [FilePath] -> LibMap -> IO ()
-mklibs appbase libdirs libmap = do
- (new, libmap') <- installLibs appbase libmap
+mklibs :: FilePath -> [FilePath] -> [(FilePath, FilePath)] -> LibMap -> IO ()
+mklibs appbase libdirs replacement_libs libmap = do
+ (new, replacement_libs', libmap') <- installLibs appbase replacement_libs libmap
unless (null new) $
- mklibs appbase (libdirs++new) libmap'
+ mklibs appbase (libdirs++new) replacement_libs' libmap'
{- Returns directories into which new libs were installed. -}
-installLibs :: FilePath -> LibMap -> IO ([FilePath], LibMap)
-installLibs appbase libmap = do
- (needlibs, libmap') <- otool appbase libmap
+installLibs :: FilePath -> [(FilePath, FilePath)] -> LibMap -> IO ([FilePath], [(FilePath, FilePath)], LibMap)
+installLibs appbase replacement_libs libmap = do
+ (needlibs, replacement_libs', libmap') <- otool appbase replacement_libs libmap
libs <- forM needlibs $ \lib -> do
let shortlib = fromMaybe (error "internal") (M.lookup lib libmap')
let fulllib = dropWhile (== '/') lib
@@ -54,24 +55,54 @@ installLibs appbase libmap = do
_ <- boolSystem "ln" [Param "-s", File fulllib, File symdest]
return $ Just appbase
)
- return (catMaybes libs, libmap')
+ return (catMaybes libs, replacement_libs', libmap')
{- Returns libraries to install. -}
-otool :: FilePath -> LibMap -> IO ([FilePath], LibMap)
-otool appbase libmap = do
+otool :: FilePath -> [(FilePath, FilePath)] -> LibMap -> IO ([FilePath], [(FilePath, FilePath)], LibMap)
+otool appbase replacement_libs libmap = do
files <- filterM doesFileExist =<< dirContentsRecursive appbase
- process [] files libmap
+ process [] files replacement_libs libmap
where
want s = not ("@executable_path" `isInfixOf` s)
&& not (".framework" `isInfixOf` s)
&& not ("libSystem.B" `isInfixOf` s)
- process c [] m = return (nub $ concat c, m)
- process c (file:rest) m = do
+ process c [] rls m = return (nub $ concat c, rls, m)
+ process c (file:rest) rls m = do
_ <- boolSystem "chmod" [Param "755", File file]
libs <- filter want . parseOtool
<$> readProcess "otool" ["-L", file]
- m' <- install_name_tool file libs m
- process (libs:c) rest m'
+ expanded_libs <- expand_rpath libs replacement_libs file
+ let rls' = nub $ rls ++ (zip libs expanded_libs)
+ m' <- install_name_tool file libs expanded_libs m
+ process (expanded_libs:c) rest rls' m'
+
+{- Expands any @rpath in the list of libraries.
+ -
+ - This is done by the nasty method of running the command with a dummy
+ - option (so it doesn't do anything.. hopefully!) and asking the dynamic
+ - linker to print expanded rpaths.
+ -}
+expand_rpath :: [String] -> [(FilePath, FilePath)] -> FilePath -> IO [String]
+expand_rpath libs replacement_libs cmd
+ | any ("@rpath" `isInfixOf`) libs = do
+ installed <- M.fromList . Prelude.read
+ <$> readFile "tmp/standalone-installed"
+ let origcmd = case M.lookup cmd installed of
+ Nothing -> cmd
+ Just cmd' -> cmd'
+ s <- catchDefaultIO "" $ readProcess "sh" ["-c", probe origcmd]
+ let m = if (null s)
+ then M.fromList replacement_libs
+ else M.fromList $ mapMaybe parse $ lines s
+ return $ map (replace m) libs
+ | otherwise = return libs
+ where
+ probe c = "DYLD_PRINT_RPATHS=1 " ++ c ++ " --getting-rpath-dummy-option 2>&1 | grep RPATH"
+ parse s = case words s of
+ ("RPATH":"successful":"expansion":"of":old:"to:":new:[]) ->
+ Just (old, new)
+ _ -> Nothing
+ replace m l = fromMaybe l $ M.lookup l m
parseOtool :: String -> [FilePath]
parseOtool = catMaybes . map parse . lines
@@ -82,10 +113,10 @@ parseOtool = catMaybes . map parse . lines
{- Adjusts binaries to use libraries bundled with it, rather than the
- system libraries. -}
-install_name_tool :: FilePath -> [FilePath] -> LibMap -> IO LibMap
-install_name_tool _ [] libmap = return libmap
-install_name_tool binary libs libmap = do
- let (libnames, libmap') = getLibNames libs libmap
+install_name_tool :: FilePath -> [FilePath] -> [FilePath] -> LibMap -> IO LibMap
+install_name_tool _ [] _ libmap = return libmap
+install_name_tool binary libs expanded_libs libmap = do
+ let (libnames, libmap') = getLibNames expanded_libs libmap
let params = concatMap change $ zip libs libnames
ok <- boolSystem "install_name_tool" $ params ++ [File binary]
unless ok $
@@ -123,4 +154,4 @@ main :: IO ()
main = getArgs >>= go
where
go [] = error "specify OSXAPP_BASE"
- go (appbase:_) = mklibs appbase [] M.empty
+ go (appbase:_) = mklibs appbase [] [] M.empty
diff --git a/Build/Standalone.hs b/Build/Standalone.hs
index 163e3ea79..aa4521730 100644
--- a/Build/Standalone.hs
+++ b/Build/Standalone.hs
@@ -60,12 +60,15 @@ progDir topdir = topdir
progDir topdir = topdir </> "bin"
#endif
-installProg :: FilePath -> FilePath -> IO ()
+installProg :: FilePath -> FilePath -> IO (FilePath, FilePath)
installProg dir prog = searchPath prog >>= go
where
go Nothing = error $ "cannot find " ++ prog ++ " in PATH"
- go (Just f) = unlessM (boolSystem "install" [File f, File dir]) $
- error $ "install failed for " ++ prog
+ go (Just f) = do
+ let dest = dir </> takeFileName f
+ unlessM (boolSystem "install" [File f, File dest]) $
+ error $ "install failed for " ++ prog
+ return (dest, f)
main = getArgs >>= go
where
@@ -73,5 +76,5 @@ main = getArgs >>= go
go (topdir:_) = do
let dir = progDir topdir
createDirectoryIfMissing True dir
- forM_ thirdpartyProgs $ installProg dir
-
+ installed <- forM thirdpartyProgs $ installProg dir
+ writeFile "tmp/standalone-installed" (show installed)