2012-11-26 18:09:40 +00:00
|
|
|
{- 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 libdir = parentDir lib
|
2012-11-26 21:11:09 +00:00
|
|
|
let dest = appbase ++ lib
|
2012-11-26 18:09:40 +00:00
|
|
|
ifM (doesFileExist dest)
|
|
|
|
( return Nothing
|
|
|
|
, do
|
2012-11-26 21:11:09 +00:00
|
|
|
createDirectoryIfMissing True (appbase ++ libdir)
|
2012-11-26 18:09:40 +00:00
|
|
|
_ <- boolSystem "cp" [File lib, File dest]
|
2012-11-26 20:31:41 +00:00
|
|
|
putStrLn $ "installing " ++ lib
|
2012-11-26 18:09:40 +00:00
|
|
|
return $ Just libdir
|
|
|
|
)
|
|
|
|
|
2012-12-08 15:07:59 +00:00
|
|
|
{- Returns libraries to install. -}
|
2012-11-26 18:09:40 +00:00
|
|
|
otool :: FilePath -> IO [FilePath]
|
|
|
|
otool appbase = do
|
|
|
|
files <- filterM doesFileExist =<< dirContentsRecursive appbase
|
2012-12-08 15:07:59 +00:00
|
|
|
l <- forM files $ \file -> do
|
|
|
|
libs <- parseOtool <$> readProcess "otool" ["-L", file]
|
|
|
|
forM_ libs $ \lib -> install_name_tool file lib
|
|
|
|
return libs
|
|
|
|
return $ nub $ concat l
|
2012-11-26 18:09:40 +00:00
|
|
|
|
|
|
|
parseOtool :: String -> [FilePath]
|
|
|
|
parseOtool = catMaybes . map parse . lines
|
|
|
|
where
|
|
|
|
parse l
|
|
|
|
| "\t" `isPrefixOf` l = headMaybe $ words l
|
|
|
|
| otherwise = Nothing
|
|
|
|
|
2012-12-08 15:07:59 +00:00
|
|
|
{- 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" ++ lib
|
|
|
|
, File binary
|
|
|
|
]
|
|
|
|
unless ok $
|
|
|
|
hPutStrLn stderr $ "install_name_tool failed for " ++ binary
|
|
|
|
|
2012-11-26 18:09:40 +00:00
|
|
|
main :: IO ()
|
|
|
|
main = getArgs >>= go
|
|
|
|
where
|
|
|
|
go [] = error "specify OSXAPP_BASE"
|
|
|
|
go (appbase:_) = do
|
|
|
|
libdirs <- mklibs appbase []
|
|
|
|
writeFile (appbase </> "libdirs") $
|
|
|
|
unlines $ nub libdirs
|