Last active
May 9, 2020 15:10
-
-
Save hasufell/48bee103197344fee7c60891798ab819 to your computer and use it in GitHub Desktop.
Optional pkg-config detection with cabal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Exception ( SomeException | |
, handle | |
, try | |
) | |
import Control.Applicative | |
import Control.Monad | |
import Data.Char | |
import Data.List | |
import Data.Maybe | |
import Data.Monoid | |
import Distribution.PackageDescription | |
hiding ( buildInfo | |
, includeDirs | |
) | |
import Distribution.Simple | |
import Distribution.Simple.LocalBuildInfo | |
import Distribution.Simple.PreProcess | |
import Distribution.Simple.Program | |
import Distribution.Simple.Setup | |
hiding ( Flag ) | |
import Distribution.System | |
import Distribution.Verbosity | |
import System.Environment | |
import System.Process | |
-- Set this | |
-- | Name of the pkg-config package. E.g., if the file is | |
-- named "liblzma.pc", then set this to "liblzma". | |
pcFile :: String | |
pcFile = undefined | |
-- | Name of the library. If it is named "liblzma.so", then | |
-- set this to "lzma". | |
libName' :: String | |
libName' = undefined | |
-- | |
main :: IO () | |
main = do | |
let origUserHooks = simpleUserHooks | |
cFlags <- getCflags | |
ldFlags <- getLDFlags | |
libs <- getLibs | |
includeDirs <- getIncludeDirs | |
libDirs <- getLibdirs | |
defaultMainWithHooks origUserHooks | |
{ confHook = \(genericPackageDescription, hookedBuildInfo) confFlags -> do | |
let genericPackageDescription' = genericPackageDescription | |
{ condLibrary = do | |
libraryCondTree <- condLibrary genericPackageDescription | |
return libraryCondTree | |
{ condTreeData = condTreeData libraryCondTree <> mempty | |
{ libBuildInfo = mempty { ccOptions = cFlags | |
, ldOptions = ldFlags | |
, extraLibs = libs | |
} | |
} | |
} | |
} | |
configFlags' = confFlags | |
{ configExtraLibDirs = libDirs ++ configExtraLibDirs confFlags | |
, configExtraIncludeDirs = includeDirs | |
++ configExtraIncludeDirs confFlags | |
} | |
addToLdLibraryPath libDirs | |
confHook simpleUserHooks | |
(genericPackageDescription', hookedBuildInfo) | |
configFlags' | |
, hookedPreProcessors = | |
let origHookedPreprocessors = hookedPreProcessors origUserHooks | |
newHsc buildInfo localBuildInfo componentLocalBuildInfo = | |
PreProcessor | |
{ platformIndependent = platformIndependent (origHsc buildInfo) | |
, runPreProcessor = \inFiles outFiles verbosity -> do | |
let buildInfo' = | |
buildInfo { ccOptions = cFlags, ldOptions = ldFlags } | |
runPreProcessor (origHsc buildInfo') inFiles outFiles verbosity | |
} | |
where | |
origHsc buildInfo' = fromMaybe | |
ppHsc2hs | |
(lookup "hsc" origHookedPreprocessors) | |
buildInfo' | |
localBuildInfo | |
componentLocalBuildInfo | |
in [("hsc", newHsc)] ++ origHookedPreprocessors | |
, buildHook = \packageDesc localBuildInfo userHooks buildFlags -> do | |
addToLdLibraryPath libDirs | |
buildHook origUserHooks | |
packageDesc | |
localBuildInfo | |
userHooks | |
buildFlags | |
, testHook = \args packageDesc localBuildInfo userHooks testFlags -> do | |
addToLdLibraryPath libDirs | |
testHook origUserHooks | |
args | |
packageDesc | |
localBuildInfo | |
userHooks | |
testFlags | |
} | |
addToLdLibraryPath :: [String] -> IO () | |
addToLdLibraryPath [] = pure () | |
addToLdLibraryPath paths = do | |
let (ldLibraryPathVar, ldLibraryPathSep) = case buildOS of | |
OSX -> ("DYLD_LIBRARY_PATH", ":") | |
_ -> ("LD_LIBRARY_PATH", ":") | |
v <- try $ getEnv ldLibraryPathVar :: IO (Either SomeException String) | |
setEnv | |
ldLibraryPathVar | |
( (intercalate ldLibraryPathSep paths) | |
++ either (const "") (ldLibraryPathSep ++) v | |
) | |
getCflags :: IO [String] | |
getCflags = | |
(fmap words $ _pkgConfig ["--cflags-only-other", pcFile]) <|> pure [] | |
getLDFlags :: IO [String] | |
getLDFlags = | |
(fmap words $ _pkgConfig ["--libs-only-other", pcFile]) <|> pure [] | |
getLibs :: IO [String] | |
getLibs = | |
((fmap . fmap) (fromJust . stripPrefix "-l") $ fmap words $ _pkgConfig | |
["--libs-only-l", pcFile] | |
) | |
<|> pure [libName'] | |
getIncludeDirs :: IO [String] | |
getIncludeDirs = | |
((fmap . fmap) (fromJust . stripPrefix "-I") $ fmap words $ _pkgConfig | |
["--cflags-only-I", pcFile] | |
) | |
<|> pure [] | |
getLibdirs :: IO [String] | |
getLibdirs = | |
((fmap . fmap) (fromJust . stripPrefix "-L") $ fmap words $ _pkgConfig | |
["--libs-only-L", pcFile] | |
) | |
<|> pure [] | |
_pkgConfig :: [String] -> IO String | |
_pkgConfig args = do | |
readProcess "pkg-config" args "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment