-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
Add functionality to allow preprocessors like hsc2hs and C2HS to inform Cabal of extra C sources that they create that need to be compiled and linked. Includes hsc2hs-based test case.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,8 +17,9 @@ | |
-- handlers. This module is not as good as it could be, it could really do with | ||
-- a rewrite to address some of the problems we have with pre-processors. | ||
|
||
module Distribution.Simple.PreProcess (preprocessComponent, knownSuffixHandlers, | ||
ppSuffixes, PPSuffixHandler, PreProcessor(..), | ||
module Distribution.Simple.PreProcess (preprocessComponent, preprocessExtras, | ||
knownSuffixHandlers, ppSuffixes, | ||
PPSuffixHandler, PreProcessor(..), | ||
mkSimplePreProcessor, runSimplePreProcessor, | ||
ppCpp, ppCpp', ppGreenCard, ppC2hs, ppHsc2hs, | ||
ppHappy, ppAlex, ppUnlit, platformDefines | ||
|
@@ -129,6 +130,14 @@ data PreProcessor = PreProcessor { | |
-> IO () -- Should exit if the preprocessor fails | ||
} | ||
|
||
-- Function to determine paths to possible extra C sources for a | ||
This comment has been minimized.
Sorry, something went wrong. |
||
-- preprocessor: same directory and filename arguments ass | ||
-- runPreProcessor. | ||
|
||
type PreProcessorExtras = | ||
(FilePath, FilePath) -> (FilePath, FilePath) -> IO [FilePath] | ||
|
||
|
||
mkSimplePreProcessor :: (FilePath -> FilePath -> Verbosity -> IO ()) | ||
-> (FilePath, FilePath) | ||
-> (FilePath, FilePath) -> Verbosity -> IO () | ||
|
@@ -455,6 +464,13 @@ ppHsc2hs bi lbi = | |
-> PackageIndex.insert rts { Installed.ldOptions = [] } index | ||
_ -> error "No (or multiple) ghc rts package is registered!!" | ||
|
||
ppHsc2hsExtras :: PreProcessorExtras | ||
ppHsc2hsExtras _ (outBaseDir, outRelativeFile) = do | ||
let possCFile = outBaseDir </> dropExtensions outRelativeFile ++ "_hsc.c" | ||
exists <- doesFileExist possCFile | ||
if exists | ||
then return [possCFile] | ||
else return [] | ||
|
||
ppC2hs :: BuildInfo -> LocalBuildInfo -> PreProcessor | ||
ppC2hs bi lbi = | ||
|
@@ -490,6 +506,14 @@ ppC2hs bi lbi = | |
where | ||
pkgs = PackageIndex.topologicalOrder (installedPkgs lbi) | ||
|
||
ppC2hsExtras :: PreProcessorExtras | ||
ppC2hsExtras _ (outBaseDir, outRelativeFile) = do | ||
let possCFile = outBaseDir </> replaceExtension outRelativeFile ".chs.c" | ||
exists <- doesFileExist possCFile | ||
if exists | ||
then return [possCFile] | ||
else return [] | ||
|
||
--TODO: perhaps use this with hsc2hs too | ||
--TODO: remove cc-options from cpphs for cabal-version: >= 1.10 | ||
getCppOptions :: BuildInfo -> LocalBuildInfo -> [String] | ||
|
@@ -620,3 +644,86 @@ knownSuffixHandlers = | |
, ("ly", ppHappy) | ||
, ("cpphs", ppCpp) | ||
] | ||
|
||
-- |Standard preprocessors with possible extra C sources: c2hs, hsc2hs. | ||
knownSuffixExtrasHandlers :: [ (String, PreProcessorExtras) ] | ||
knownSuffixExtrasHandlers = | ||
[ ("chs", ppC2hsExtras) | ||
, ("hsc", ppHsc2hsExtras) | ||
] | ||
|
||
preprocessExtras :: Component | ||
This comment has been minimized.
Sorry, something went wrong.
23Skidoo
|
||
-> LocalBuildInfo | ||
-> Verbosity | ||
-> IO [FilePath] | ||
preprocessExtras comp lbi verbosity = case comp of | ||
(CLib lib@Library{ libBuildInfo = bi }) -> do | ||
let dirs = hsSourceDirs bi ++ [autogenModulesDir lbi] | ||
This comment has been minimized.
Sorry, something went wrong.
23Skidoo
|
||
extrass <- forM (map ModuleName.toFilePath $ libModules lib) $ | ||
pre dirs (buildDir lbi) | ||
return $ concat extrass | ||
(CExe exe@Executable { buildInfo = bi, exeName = nm }) -> do | ||
let exeDir = buildDir lbi </> nm </> nm ++ "-tmp" | ||
dirs = hsSourceDirs bi ++ [autogenModulesDir lbi] | ||
extrass <- forM (map ModuleName.toFilePath $ otherModules bi) $ | ||
pre dirs exeDir | ||
extras2 <- pre (hsSourceDirs bi) exeDir $ dropExtensions (modulePath exe) | ||
return $ concat extrass ++ extras2 | ||
CTest test -> do | ||
case testInterface test of | ||
TestSuiteExeV10 _ f -> | ||
preProcessTest test f $ buildDir lbi </> testName test | ||
</> testName test ++ "-tmp" | ||
TestSuiteLibV09 _ _ -> do | ||
let testDir = buildDir lbi </> stubName test | ||
</> stubName test ++ "-tmp" | ||
preProcessTest test (stubFilePath test) testDir | ||
TestSuiteUnsupported tt -> die $ "No support for preprocessing test " | ||
++ "suite type " ++ display tt | ||
CBench bm -> do | ||
case benchmarkInterface bm of | ||
BenchmarkExeV10 _ f -> | ||
preProcessBench bm f $ buildDir lbi </> benchmarkName bm | ||
</> benchmarkName bm ++ "-tmp" | ||
BenchmarkUnsupported tt -> die $ "No support for preprocessing benchmark " | ||
++ "type " ++ display tt | ||
where | ||
pre dirs dir fp = preprocessFileExtras dirs dir fp verbosity | ||
preProcessTest test = preProcessExtras (testBuildInfo test) | ||
(testModules test) | ||
preProcessBench bm = preProcessExtras (benchmarkBuildInfo bm) | ||
(benchmarkModules bm) | ||
preProcessExtras bi modules exePath dir = do | ||
let sourceDirs = hsSourceDirs bi ++ [ autogenModulesDir lbi ] | ||
extrass <- sequence [ preprocessFileExtras sourceDirs dir | ||
(ModuleName.toFilePath modu) verbosity | ||
| modu <- modules ] | ||
extras2 <- preprocessFileExtras (dir : (hsSourceDirs bi)) dir | ||
(dropExtensions $ exePath) verbosity | ||
return $ concat extrass ++ extras2 | ||
|
||
preprocessFileExtras | ||
:: [FilePath] -- ^source directories | ||
-> FilePath -- ^build directory | ||
-> FilePath -- ^module file name | ||
-> Verbosity -- ^verbosity | ||
-> IO [FilePath] | ||
preprocessFileExtras searchLoc buildLoc baseFile verbosity = do | ||
-- look for files in the various source dirs with this module name | ||
-- and a file extension of a known preprocessor | ||
psrcFiles <- findFileWithExtension' (map fst knownSuffixExtrasHandlers) | ||
searchLoc baseFile | ||
case psrcFiles of | ||
Nothing -> return [] | ||
-- found a pre-processable file in one of the source dirs | ||
Just (psrcLoc, psrcRelFile) -> do | ||
let (srcStem, ext) = splitExtension psrcRelFile | ||
pp = fromMaybe (error "Internal error in preProcess module: Just expected") | ||
This comment has been minimized.
Sorry, something went wrong.
23Skidoo
|
||
(lookup (tailNotNull ext) knownSuffixExtrasHandlers) | ||
destDir = buildLoc </> takeDirectory srcStem | ||
createDirectoryIfMissingVerbose verbosity True destDir | ||
pp (psrcLoc, psrcRelFile) (buildLoc, srcStem <.> "hs") | ||
|
||
where | ||
tailNotNull [] = [] | ||
tailNotNull x = tail x |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
running tests/benchmarks (#1821). | ||
* Build shared libraries by default when linking executables dynamically. | ||
* Build profiled libraries by default when profiling executables. | ||
* Deal with extra C sources from preprocessors (#238). | ||
|
||
1.20.0.1 Johan Tibell <[email protected]> May 2014 | ||
* Fix streaming test output. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module PackageTests.PreProcessExtraSources.Check (suite) where | ||
|
||
import PackageTests.PackageTester | ||
(PackageSpec(..), assertBuildSucceeded, cabal_build) | ||
import System.FilePath | ||
import Test.Tasty.HUnit | ||
|
||
suite :: FilePath -> Assertion | ||
suite ghcPath = do | ||
let spec = PackageSpec | ||
{ directory = "PackageTests" </> "PreProcessExtraSources" | ||
, distPref = Nothing | ||
, configOpts = ["--enable-tests", "--enable-benchmarks"] | ||
} | ||
result <- cabal_build spec ghcPath | ||
assertBuildSucceeded result |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{-# LANGUAGE ForeignFunctionInterface #-} | ||
module Foo where | ||
|
||
import Foreign.C.Types | ||
|
||
#def int incr(int x) { return x + 1; } | ||
|
||
foreign import ccall unsafe "Foo_hsc.h incr" | ||
incr :: CInt -> CInt |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module Main where | ||
|
||
import Foo | ||
|
||
main :: IO () | ||
main = do | ||
let x = incr 4 | ||
return () |
Would be nice to have a Haddock comment here. In general, the rule is to have a Haddock comment for each new top-level function (I know that the existing code doesn't follow this policy).