blob: 45a86000b646a58741808ce12b881dd6a27b6484 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
{- OSX library copier
-
- Copyright 2012 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Build.OSXMkLibs where
import Control.Applicative
import System.Environment
import Data.Maybe
import System.FilePath
import System.Directory
import System.IO
import Control.Monad
import Data.List
import Utility.PartialPrelude
import Utility.Directory
import Utility.Process
import Utility.Monad
import Utility.SafeCommand
import Utility.Path
{- Recursively find and install libs, until nothing new to install is found. -}
mklibs :: FilePath -> [FilePath] -> IO [FilePath]
mklibs appbase libdirs = do
new <- catMaybes <$> installLibs appbase
if null new
then return (libdirs++new)
else mklibs appbase (libdirs++new)
{- Returns directories into which new libs were installed. -}
installLibs :: FilePath -> IO [Maybe FilePath]
installLibs appbase = do
needlibs <- otool appbase
forM needlibs $ \lib -> do
let dest = appbase </> takeFileName lib
ifM (doesFileExist dest)
( return Nothing
, do
createDirectoryIfMissing True appbase
putStrLn $ "installing " ++ lib
_ <- boolSystem "cp" [File lib, File dest]
return $ Just appbase
)
{- Returns libraries to install. -}
otool :: FilePath -> IO [FilePath]
otool appbase = do
files <- filterM doesFileExist =<< dirContentsRecursive appbase
l <- forM files $ \file -> do
libs <- filter unprocessed . parseOtool
<$> readProcess "otool" ["-L", file]
forM_ libs $ \lib -> install_name_tool file lib
return libs
return $ nub $ concat l
where
unprocessed s = not ("@executable_path" `isInfixOf` s)
parseOtool :: String -> [FilePath]
parseOtool = catMaybes . map parse . lines
where
parse l
| "\t" `isPrefixOf` l = headMaybe $ words l
| otherwise = Nothing
{- Adjusts binaries to use libraries in paths relative to the executable.
-
- Assumes all executables are installed into the same directory, and
- the libraries will be installed in subdirectories that match their
- absolute paths. -}
install_name_tool :: FilePath -> FilePath -> IO ()
install_name_tool binary lib = do
ok <- boolSystem "install_name_tool"
[ Param "-change"
, File lib
, Param $ "@executable_path" ++ (dropFileName lib)
, File binary
]
unless ok $
hPutStrLn stderr $ "install_name_tool failed for " ++ binary
main :: IO ()
main = getArgs >>= go
where
go [] = error "specify OSXAPP_BASE"
go (appbase:_) = do
libdirs <- mklibs appbase []
writeFile (appbase </> "libdirs") $
unlines $ nub libdirs
|