Skip to content

Instantly share code, notes, and snippets.

@hasufell
Last active May 9, 2020 15:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hasufell/48bee103197344fee7c60891798ab819 to your computer and use it in GitHub Desktop.
Save hasufell/48bee103197344fee7c60891798ab819 to your computer and use it in GitHub Desktop.
Optional pkg-config detection with cabal
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