on iko/ghcjs-patch-master help sign in
fix ghcjs (#1311)
001df75Moritz Angermann
builder/Setup.ghcjs.hsnew file+272
@@ -0,0 +1,272 @@
1+{-# language LambdaCase #-}
2+import Distribution.Simple
3+import Distribution.Simple.Setup
4+import Distribution.Types.PackageDescription
5+import Distribution.Types.LocalBuildInfo
6+import Distribution.Simple.PackageIndex
7+import Distribution.Types.InstalledPackageInfo hiding (includeDirs)
8+import qualified Distribution.Types.InstalledPackageInfo as IPI
9+import Distribution.Types.PackageName
10+import System.FilePath
11+import Control.Monad (filterM, forM_, forM, unless)
12+import System.Directory (doesFileExist)
13+import Distribution.Types.Library (libBuildInfo, Library(..))
14+import Distribution.Types.BuildInfo (cSources, jsSources, includeDirs, emptyBuildInfo, options, extraBundledLibs)
15+import Distribution.Simple.BuildTarget (readBuildTargets, BuildTarget(..), readUserBuildTargets)
16+import Distribution.Verbosity (silent, verbose)
17+import Distribution.Types.ComponentName
18+import Distribution.Simple.Program.Types (programPath)
19+import Distribution.Simple.Program.Db (lookupKnownProgram, lookupProgram, knownPrograms)
20+import Distribution.Simple.Program (Program, gccProgram, arProgram, runDbProgram, simpleProgram, ghcProgram)
21+import Distribution.Simple.Utils (createDirectoryIfMissingVerbose)
22+import Distribution.Types.HookedBuildInfo
23+import Data.List (isPrefixOf, isSuffixOf, intercalate)
24+import System.Environment (getArgs, getProgName)
25+import Distribution.Simple.LocalBuildInfo (Component (..), withAllComponentsInBuildOrder, componentBuildDir)
26+import Distribution.Types.TestSuite (TestSuite(..))
27+import Distribution.Types.TestSuiteInterface (TestSuiteInterface(..) )
28+import Distribution.Simple.Test.LibV09 (stubName)
29+import Distribution.Types.Executable (exeName, Executable(..))
30+import Distribution.Types.Benchmark (Benchmark(..))
31+import Distribution.Types.TestSuite (TestSuite(..))
32+import Distribution.Types.UnqualComponentName (unUnqualComponentName, mkUnqualComponentName)
33+
34+
35+emarProgram :: Program
36+emarProgram = simpleProgram "emar"
37+
38+buildEMCCLib :: PackageDescription -> LocalBuildInfo -> IO ()
39+buildEMCCLib desc lbi = do
40+ let verbosity = verbose
41+ -- get build dir
42+ createDirectoryIfMissingVerbose verbosity True ((buildDir lbi) </> "emcc")
43+ --
44+ case library desc of
45+ Just lib -> do
46+ -- Let's see if we are going to export anything. If not there is likely no point in compiling anything
47+ -- from the C code.
48+ names <- forM (jsSources . libBuildInfo $ lib) $ \src -> do
49+ unwords . concatMap (drop 2 . words) . filter (isPrefixOf "// EMCC:EXPORTED_FUNCTIONS") . lines <$> readFile src
50+
51+ unless (null names) $ do
52+ let depIncludeDirs = concatMap IPI.includeDirs (topologicalOrder $ installedPkgs lbi)
53+ -- alright, let's compile all .c files into .o files with emcc, which is the `gcc` program.
54+ forM_ (cSources . libBuildInfo $ lib) $ \src -> do
55+ let dst = (buildDir lbi) </> "emcc" </> (src -<.> "o")
56+ createDirectoryIfMissingVerbose verbosity True (takeDirectory dst)
57+ runDbProgram verbosity gccProgram (withPrograms lbi) $
58+ ["-c", src, "-o", dst] ++ ["-I" <> incDir | incDir <- (includeDirs . libBuildInfo $ lib) ++ depIncludeDirs]
59+
60+ -- and now construct a canonical `.js_a` file, *if* we have any cSources we turned into objects.
61+ unless (null . cSources . libBuildInfo $ lib) $ do
62+ let dstLib = (buildDir lbi) </> "libEMCC" <> (unPackageName . pkgName . package $ desc) <> ".js_a"
63+ runDbProgram verbosity emarProgram (withPrograms lbi) $
64+ [ "-r", dstLib ] ++ [ (buildDir lbi) </> "emcc" </> (src -<.> "o") | src <- cSources . libBuildInfo $ lib ]
65+
66+ let expLib = (buildDir lbi) </> "libEMCC" <> (unPackageName . pkgName . package $ desc) <> ".exported.js_a"
67+ writeFile expLib (unwords names)
68+
69+ -- if there's no lib, this is a fairly pointless exercise
70+ Nothing -> return ()
71+
72+-- This is here so that we can link multiple libEMCC* libraries fromd ependencies together with emcc.
73+-- however we don't have figured out how to get the EXPORTED_FUNCTIONS from each dependency merged yet.
74+--
75+linkEMCCLib :: PackageDescription -> LocalBuildInfo -> IO ()
76+linkEMCCLib desc lbi = linkCLib ("emcc" </> "lib.js") desc lbi
77+
78+linkEMCCTHLib :: PackageDescription -> LocalBuildInfo -> IO ()
79+linkEMCCTHLib desc lbi = linkCLib ("th-support.js") desc lbi
80+
81+linkCLib :: String -> PackageDescription -> LocalBuildInfo -> IO ()
82+linkCLib libname desc lbi = do
83+ withAllComponentsInBuildOrder desc lbi $ \comp clbi -> do
84+ let extraLibs = [ "-l" <> l | l <- concatMap IPI.extraLibraries (topologicalOrder $ installedPkgs lbi)
85+ , l /= "m"
86+ , l /= "dl" ]
87+ libDirs = [ "-L" <> path | path <- concatMap IPI.libraryDirs (topologicalOrder $ installedPkgs lbi) ]
88+
89+ let verbosity = verbose
90+ libs <- filterM doesFileExist $
91+ concatMap (\x -> [ libDir </> "libEMCC" <> (unPackageName . pkgName . sourcePackageId $ x) <> ".js_a"
92+ | libDir <- libraryDirs x ])
93+ (topologicalOrder $ installedPkgs lbi)
94+ exff <- filterM doesFileExist $
95+ concatMap (\x -> [ libDir </> "libEMCC" <> (unPackageName . pkgName . sourcePackageId $ x) <> ".exported.js_a"
96+ | libDir <- libraryDirs x ])
97+ (topologicalOrder $ installedPkgs lbi)
98+ print exff
99+ exfns <- concat <$> forM exff (fmap words . readFile)
100+ unless (null libs && null exfns) $ do
101+ libs <- case libs of
102+ [] -> do writeFile (buildDir lbi </> "emcc_linking_dummy.c") ""
103+ runDbProgram verbosity gccProgram (withPrograms lbi) $
104+ ["-c", buildDir lbi </> "emcc_linking_dummy.c", "-o", buildDir lbi </> "emcc_linking_dummy.o"]
105+ return [(buildDir lbi </> "emcc_linking_dummy.o")]
106+ _ -> return libs
107+
108+ let dst = if libname == "emcc" </> "lib.js" then buildDir lbi
109+ -- who designed this shit in cabal?
110+ else case comp of
111+ (CTest test@(TestSuite { testInterface = TestSuiteLibV09 _ _ })) -> buildDir lbi </> stubName test </> stubName test ++ "-tmp"
112+ (CTest test@(TestSuite { testInterface = TestSuiteExeV10 _ _ })) -> buildDir lbi </> unUnqualComponentName (testName test) </> unUnqualComponentName (testName test) ++ "-tmp"
113+ (CExe exe) -> buildDir lbi </> unUnqualComponentName (exeName exe) </> unUnqualComponentName (exeName exe) ++ "-tmp"
114+ _ -> componentBuildDir lbi clbi
115+ dst' = dst </> libname
116+ createDirectoryIfMissingVerbose verbosity True (takeDirectory dst')
117+ runDbProgram verbosity gccProgram (withPrograms lbi) $
118+ [ "-o", dst'
119+ , "-s", "WASM=0"
120+ , "-s", "ALLOW_TABLE_GROWTH" -- we need this for addFunction/removeFunction
121+ -- addFunction, removeFunction are for dynamic functions.
122+ -- getTempRet0/setTempRet0 are for 64bit legalization.
123+ , "-s", "EXPORTED_RUNTIME_METHODS=['printErr','addFunction','removeFunction','getTempRet0','setTempRet0']"
124+ --
125+ , "-s", "EXPORTED_FUNCTIONS=['" <> intercalate "', '" exfns <> "']"
126+ ] ++ libs ++ libDirs ++ extraLibs
127+
128+postBuildHook :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
129+postBuildHook args flags desc lbi = do
130+ case (takeFileName . programPath <$> lookupProgram ghcProgram (withPrograms lbi)) of
131+ Just "js-unknown-ghcjs-ghc" ->
132+ readBuildTargets silent desc (buildArgs flags) >>= \case
133+ [BuildTargetComponent (CLibName _)] -> print "OK. Lib (Build)" >> buildEMCCLib desc lbi
134+ [BuildTargetComponent (CExeName _)] -> print "OK. Exe"
135+ [BuildTargetComponent (CTestName _)] -> print "OK. Test"
136+ [BuildTargetComponent (CBenchName _)] -> print "OK. Bench"
137+ _ -> print "EEk!"
138+ _ -> return ()
139+
140+postConfHook :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
141+postConfHook args flags desc lbi = do
142+ case (takeFileName . programPath <$> lookupProgram ghcProgram (withPrograms lbi)) of
143+ Just "js-unknown-ghcjs-ghc" -> do
144+ -- always link the TH lib
145+ -- this is technically only needed if the package uses TH somewhere.
146+ linkEMCCTHLib desc lbi
147+ -- only link the final lib if we want to produce an output.
148+ readBuildTargets silent desc (configArgs flags) >>= \case
149+ [BuildTargetComponent (CLibName _)] -> print "OK. Lib" >> postConf simpleUserHooks args flags desc lbi
150+ [BuildTargetComponent (CExeName _)] -> print "OK. Exe (Link)" >> linkEMCCLib desc lbi
151+ [BuildTargetComponent (CTestName _)] -> print "OK. Test (Link)" >> linkEMCCLib desc lbi
152+ [BuildTargetComponent (CBenchName _)] -> print "OK. Bench (Link)" >> linkEMCCLib desc lbi
153+ _ -> print "EEk!"
154+ -- defer to default postConf. XXX we should do this for the above cases in linkEMCCLib as well!
155+ _ -> postConf simpleUserHooks args flags desc lbi
156+
157+--
158+-- Injecting emcc/lib.js as needed.
159+--
160+-- We inject jsSources: dist/build/emcc/lib.js, the amalgamated emcc library,
161+-- into Executables, Tests and Benchmarks.
162+emccBuildHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
163+emccBuildHook desc lbi hooks flags = do
164+ let lbi' = lbi { localPkgDescr = updatePackageDescription (localPkgDescr lbi) }
165+ -- for some reason tests/benchmarks seem to rely on the description, whereas libraries and executables depend on the local build info...
166+ desc' = updatePackageDescription desc
167+ doesFileExist jsLib >>= \x -> print $ jsLib <> " " <> (if x then "exists" else "doesn't exist!")
168+ doesFileExist jsLib >>= \case
169+ True -> buildHook simpleUserHooks desc' lbi' hooks flags
170+ False -> buildHook simpleUserHooks desc lbi hooks flags
171+
172+ where
173+ jsLib = "dist/build" </> "emcc" </> "lib.js"
174+ extraOpts = PerCompilerFlavor [jsLib] []
175+ -- don't inject it for libraries, only for exe, test, bench.
176+ updateLibrary :: Library -> Library
177+ updateLibrary = id -- lib@Library{ libBuildInfo = bi } = lib { libBuildInfo = bi { options = options bi <> extraOpts } }
178+ updateExe :: Executable -> Executable
179+ updateExe exe@Executable{ buildInfo = bi } = exe { buildInfo = bi { options = options bi <> extraOpts } }
180+ updateTest :: TestSuite -> TestSuite
181+ updateTest test@TestSuite{ testBuildInfo = bi } = test { testBuildInfo = bi { options = options bi <> extraOpts } }
182+ updateBench :: Benchmark -> Benchmark
183+ updateBench bench@Benchmark{ benchmarkBuildInfo = bi } = bench { benchmarkBuildInfo = bi { options = options bi <> extraOpts } }
184+ updatePackageDescription :: PackageDescription -> PackageDescription
185+ updatePackageDescription desc = desc
186+ { library = updateLibrary <$> library desc
187+ , executables = updateExe <$> executables desc
188+ , testSuites = updateTest <$> testSuites desc
189+ , benchmarks = updateBench <$> benchmarks desc
190+ }
191+
192+--
193+-- Injecting EMCC<name> extra libraries as needed
194+-- this one we only need alongside library components; as it's shipped and installed
195+-- into the package databse. This is not necesary for executables/test/benchmarks, that
196+-- are not installed into the package database
197+--
198+emccCopyHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags -> IO ()
199+emccCopyHook desc lbi hooks flags = do
200+ emccLibs <- filterM (\l -> doesFileExist (buildDir lbi </> "lib" <> l <> ".js_a"))
201+ [ "EMCC" <> (unPackageName . pkgName . package $ desc)
202+ , "EMCC" <> (unPackageName . pkgName . package $ desc) <> ".exported" ]
203+ print $ "EMCC extra lib files: " ++ intercalate ", " emccLibs
204+ let lbi' = lbi { localPkgDescr = updatePackageDescription emccLibs (localPkgDescr lbi) }
205+ desc' = updatePackageDescription emccLibs desc
206+ copyHook simpleUserHooks desc' lbi' hooks flags
207+ where
208+ emccLib = (buildDir lbi) </> "libEMCC" <> (unPackageName . pkgName . package $ desc) <> ".js_a"
209+ -- don't inject it for libraries, only for exe, test, bench.
210+ updateLibrary :: [String] -> Library -> Library
211+ updateLibrary extraLibs lib@Library{ libBuildInfo = bi } = lib { libBuildInfo = bi { extraBundledLibs = extraBundledLibs bi <> extraLibs } }
212+ updatePackageDescription :: [String] -> PackageDescription -> PackageDescription
213+ updatePackageDescription extraLibs desc = desc { library = updateLibrary extraLibs <$> library desc }
214+
215+emccRegHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
216+emccRegHook desc lbi hooks flags = do
217+ emccLibs <- filterM (\l -> doesFileExist (buildDir lbi </> "lib" <> l <> ".js_a"))
218+ [ "EMCC" <> (unPackageName . pkgName . package $ desc)
219+ , "EMCC" <> (unPackageName . pkgName . package $ desc) <> ".exported" ]
220+ print $ "EMCC extra lib files: " ++ intercalate ", " emccLibs
221+ let lbi' = lbi { localPkgDescr = updatePackageDescription emccLibs (localPkgDescr lbi) }
222+ desc' = updatePackageDescription emccLibs desc
223+ regHook simpleUserHooks desc' lbi' hooks flags
224+ where
225+ emccLib = (buildDir lbi) </> "libEMCC" <> (unPackageName . pkgName . package $ desc) <> ".js_a"
226+ -- don't inject it for libraries, only for exe, test, bench.
227+ updateLibrary :: [String] -> Library -> Library
228+ updateLibrary extraLibs lib@Library{ libBuildInfo = bi } = lib { libBuildInfo = bi { extraBundledLibs = extraBundledLibs bi <> extraLibs } }
229+ updatePackageDescription :: [String] -> PackageDescription -> PackageDescription
230+ updatePackageDescription extraLibs desc = desc { library = updateLibrary extraLibs <$> library desc }
231+
232+emccUnregHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO ()
233+emccUnregHook desc lbi hooks flags = do
234+ emccLibs <- filterM (\l -> doesFileExist (buildDir lbi </> "lib" <> l <> ".js_a"))
235+ [ "EMCC" <> (unPackageName . pkgName . package $ desc)
236+ , "EMCC" <> (unPackageName . pkgName . package $ desc) <> ".exported" ]
237+ print $ "EMCC extra lib files: " ++ intercalate ", " emccLibs
238+ let lbi' = lbi { localPkgDescr = updatePackageDescription emccLibs (localPkgDescr lbi) }
239+ desc' = updatePackageDescription emccLibs desc
240+ unregHook simpleUserHooks desc' lbi' hooks flags
241+ where
242+ emccLib = (buildDir lbi) </> "libEMCC" <> (unPackageName . pkgName . package $ desc) <> ".js_a"
243+ -- don't inject it for libraries, only for exe, test, bench.
244+ updateLibrary :: [String] -> Library -> Library
245+ updateLibrary extraLibs lib@Library{ libBuildInfo = bi } = lib { libBuildInfo = bi { extraBundledLibs = extraBundledLibs bi <> extraLibs } }
246+ updatePackageDescription :: [String] -> PackageDescription -> PackageDescription
247+ updatePackageDescription extraLibs desc = desc { library = updateLibrary extraLibs <$> library desc }
248+--
249+-- Main
250+--
251+main :: IO ()
252+main = do
253+ args <- getArgs
254+ defaultMainWithHooksArgs emccHooks (injectEmar args)
255+ where
256+ injectEmar :: [String] -> [String]
257+ injectEmar [] = []
258+ injectEmar (x:xs) | "--with-gcc=" `isPrefixOf` x
259+ , "emcc" `isSuffixOf` x
260+ = x:("--with-emar="<> (takeDirectory $ drop 11 $ x) </> "emar"):injectEmar xs
261+ injectEmar (x:xs) = x:injectEmar xs
262+
263+ emccHooks :: UserHooks
264+ emccHooks = simpleUserHooks
265+ { postConf = postConfHook
266+ , buildHook = emccBuildHook
267+ , postBuild = postBuildHook
268+ , copyHook = emccCopyHook
269+ , regHook = emccRegHook
270+ , unregHook = emccUnregHook
271+ , hookedPrograms = [emarProgram]
272+ }
builder/Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
builder/comp-builder.nix+8−2
@@ -380,12 +380,18 @@ let
380 runHook postConfigure
380 runHook postConfigure
381 '';
381 '';
382
382
383− buildPhase = ''
383+ buildPhase = if stdenv.hostPlatform.isGhcjs then ''
384+ runHook preBuild
385+ # https://gitlab.haskell.org/ghc/ghc/issues/9221
386+ $SETUP_HS build ${haskellLib.componentTarget componentId} ${lib.concatStringsSep " " setupBuildFlags}
387+ runHook postBuild
388+ '' else ''
384 runHook preBuild
389 runHook preBuild
385 # https://gitlab.haskell.org/ghc/ghc/issues/9221
390 # https://gitlab.haskell.org/ghc/ghc/issues/9221
386 $SETUP_HS build ${haskellLib.componentTarget componentId} -j$(($NIX_BUILD_CORES > 4 ? 4 : $NIX_BUILD_CORES)) ${lib.concatStringsSep " " setupBuildFlags}
391 $SETUP_HS build ${haskellLib.componentTarget componentId} -j$(($NIX_BUILD_CORES > 4 ? 4 : $NIX_BUILD_CORES)) ${lib.concatStringsSep " " setupBuildFlags}
387 runHook postBuild
392 runHook postBuild
388− '';
393+ ''
394+ ;
389
395
390 # Note: Cabal does *not* copy test executables during the `install` phase.
396 # Note: Cabal does *not* copy test executables during the `install` phase.
391 #
397 #
builder/default.nix+2−2
@@ -17,8 +17,8 @@ let
17 # in the native case, it would be the same in the cross case however
17 # in the native case, it would be the same in the cross case however
18 # we *really* want to build the Setup.hs on the build machine and not
18 # we *really* want to build the Setup.hs on the build machine and not
19 # have the stdenv confuse it with the target/host env.
19 # have the stdenv confuse it with the target/host env.
20− inherit (buildPackages) stdenv;
20+ inherit (buildPackages) stdenv pkgconfig;
21− inherit buildPackages pkgconfig;
21+ inherit buildPackages;
22 inherit haskellLib nonReinstallablePkgs makeSetupConfigFiles;
22 inherit haskellLib nonReinstallablePkgs makeSetupConfigFiles;
23 };
23 };
24
24
builder/hspkg-builder.nix+18−6
@@ -30,10 +30,7 @@ let
30 sha256 = revisionSha256;
30 sha256 = revisionSha256;
31 };
31 };
32
32
33− defaultSetupSrc = builtins.toFile "Setup.hs" ''
33+ defaultSetupSrc = if stdenv.hostPlatform.isGhcjs then ./Setup.ghcjs.hs else ./Setup.hs;
34− import Distribution.Simple
35− main = defaultMain
36− '';
37
34
38 # Get the Cabal lib used to build `cabal-install`.
35 # Get the Cabal lib used to build `cabal-install`.
39 # To avoid infinite recursion we have to leave this out for packages
36 # To avoid infinite recursion we have to leave this out for packages
@@ -51,7 +48,22 @@ let
51 )
48 )
52 buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library;
49 buildPackages.haskell-nix.cabal-install-unchecked.${compiler-nix-name}.project.hsPkgs.Cabal.components.library;
53
50
51+ # This logic is needed so that we don't get duplicate packages if we
52+ # add a custom Cabal package to the dependencies. That way custom
53+ # setups won't complain about e.g. binary from the Cabal dependencies
54+ # and binary from the global package-db.
55+ nonReinstallablePkgs = if (
56+ stdenv.hostPlatform.isGhcjs || (
57+ builtins.elem compiler-nix-name["ghc865" "ghc884"]
58+ &&
59+ !builtins.elem package.identifier.name
60+ ["nix-tools" "alex" "happy" "hscolour" "Cabal" "bytestring" "aeson" "time"
61+ "filepath" "base-compat-batteries" "base-compat" "unix" "directory" "transformers"
62+ "containers" "binary" "mtl" "text" "process" "parsec"]
63+ )
64+ ) then [] else null;
65+
54− defaultSetup = setup-builder {
66+ defaultSetup = setup-builder ({
55 name = "${ghc.targetPrefix}default-Setup";
67 name = "${ghc.targetPrefix}default-Setup";
56 component = {
68 component = {
57 depends = config.setup-depends ++ cabalLibDepends;
69 depends = config.setup-depends ++ cabalLibDepends;
@@ -87,7 +99,7 @@ let
87 cat ${defaultSetupSrc} > $out/Setup.hs
99 cat ${defaultSetupSrc} > $out/Setup.hs
88 '';
100 '';
89 inherit defaultSetupSrc;
101 inherit defaultSetupSrc;
90− };
102+ } // (if nonReinstallablePkgs == null then {} else { inherit nonReinstallablePkgs; }));
91
103
92 # buildPackages.runCommand "default-Setup" { nativeBuildInputs = [(ghc.passthru.buildGHC or ghc)]; } ''
104 # buildPackages.runCommand "default-Setup" { nativeBuildInputs = [(ghc.passthru.buildGHC or ghc)]; } ''
93 # cat ${defaultSetupSrc} > Setup.hs
105 # cat ${defaultSetupSrc} > Setup.hs
builder/make-config-files.nix+1−1
@@ -1,6 +1,6 @@
1{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }@defaults:
1{ stdenv, lib, haskellLib, ghc, nonReinstallablePkgs, runCommand, writeText, writeScript }@defaults:
2
2
3−{ identifier, component, fullName, flags ? {}, needsProfiling ? false, enableDWARF ? false, chooseDrv ? drv: drv }:
3+{ identifier, component, fullName, flags ? {}, needsProfiling ? false, enableDWARF ? false, chooseDrv ? drv: drv, nonReinstallablePkgs ? defaults.nonReinstallablePkgs }:
4
4
5let
5let
6 ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
6 ghc = if enableDWARF then defaults.ghc.dwarf else defaults.ghc;
builder/setup-builder.nix+3−2
@@ -1,4 +1,4 @@
1−{ pkgs, stdenv, lib, buildPackages, haskellLib, ghc, nonReinstallablePkgs, hsPkgs, makeSetupConfigFiles, pkgconfig }:
1+{ pkgs, stdenv, lib, buildPackages, haskellLib, ghc, nonReinstallablePkgs, hsPkgs, makeSetupConfigFiles, pkgconfig }@defaults:
2
2
3let self =
3let self =
4{ component, package, name, src, enableDWARF ? false, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
4{ component, package, name, src, enableDWARF ? false, flags ? {}, revision ? null, patches ? [], defaultSetupSrc
@@ -7,6 +7,7 @@ let self =
7, preBuild ? component.preBuild , postBuild ? component.postBuild
7, preBuild ? component.preBuild , postBuild ? component.postBuild
8, preInstall ? component.preInstall , postInstall ? component.postInstall
8, preInstall ? component.preInstall , postInstall ? component.postInstall
9, cleanSrc ? haskellLib.cleanCabalComponent package component "setup" src
9, cleanSrc ? haskellLib.cleanCabalComponent package component "setup" src
10+, nonReinstallablePkgs ? defaults.nonReinstallablePkgs
10}@drvArgs:
11}@drvArgs:
11
12
12let
13let
@@ -18,7 +19,7 @@ let
18
19
19 configFiles = makeSetupConfigFiles {
20 configFiles = makeSetupConfigFiles {
20 inherit (package) identifier;
21 inherit (package) identifier;
21− inherit fullName flags component enableDWARF;
22+ inherit fullName flags component enableDWARF nonReinstallablePkgs;
22 };
23 };
23 hooks = haskellLib.optionalHooks {
24 hooks = haskellLib.optionalHooks {
24 inherit
25 inherit
compiler/ghcjs/ghcjs.nix+1
@@ -59,6 +59,7 @@ let
59 # Used to detect non haskell-nix compilers (accidental use of nixpkgs compilers can lead to unexpected errors)
59 # Used to detect non haskell-nix compilers (accidental use of nixpkgs compilers can lead to unexpected errors)
60 isHaskellNixCompiler = true;
60 isHaskellNixCompiler = true;
61 } // ghcjs.components.exes;
61 } // ghcjs.components.exes;
62+ dontUpdateAutotoolsGnuConfigScripts = true;
62 dontConfigure = true;
63 dontConfigure = true;
63 dontInstall = true;
64 dontInstall = true;
64 buildPhase = ''
65 buildPhase = ''
compiler/ghcjs/ghcjs810-src.json+3−3
@@ -1,6 +1,6 @@
1{
1{
2− "url": "https://github.com/angerman/ghcjs",
2+ "url": "https://github.com/ghcjs/ghcjs",
3− "rev": "fd1f61c593c81d5ce1491e000f8e899561026351",
3+ "rev": "bb403ec3a1506831aae2d608b7b21c1937e4fb20",
4− "sha256": "sha256-HdcZW7om8x1O2bDTOdGnx7nohRdigKla+SvcpS+wdHA=",
4+ "sha256": "0bs3hijwn0p4wvphwg78mwbz8qyi10wqgfh8yfaszaj1766892ba",
5 "fetchSubmodules": true
5 "fetchSubmodules": true
6}
6}
modules/configuration-nix.nix+4
@@ -52,4 +52,8 @@ in {
52 ];
52 ];
53 # Remove dependency on hsc2hs (hsc2hs should be in ghc derivation)
53 # Remove dependency on hsc2hs (hsc2hs should be in ghc derivation)
54 packages.mintty.components.library.build-tools = pkgs.lib.mkForce [];
54 packages.mintty.components.library.build-tools = pkgs.lib.mkForce [];
55+
56+ packages.ghc-lib-parser.patches = [
57+ (fromUntil "8.10.0.0" "9.1" ../overlays/patches/ghc-lib-parser-8.10-global-unique-counters-in-rts.patch)
58+ ];
55}
59}
overlays/bootstrap.nix+1
@@ -190,6 +190,7 @@ in {
190 ++ fromUntil "8.10" "9.2.2" ./patches/ghc/MR6654-nonmoving-maxmem.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6654
190 ++ fromUntil "8.10" "9.2.2" ./patches/ghc/MR6654-nonmoving-maxmem.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6654
191 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/MR6617-nonmoving-mvar.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6617
191 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/MR6617-nonmoving-mvar.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6617
192 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/MR6595-nonmoving-mutvar.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6595
192 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/MR6595-nonmoving-mutvar.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6595
193+ ++ fromUntil "8.10" "8.11" ./patches/ghc/ghc-8.10-global-unique-counters-in-rts.patch # backport of https://gitlab.haskell.org/ghc/ghc/-/commit/9a28680d2e23e7b25dd7254a439aea31dfae32d5
193 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/issue-18708.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6554
194 ++ fromUntil "8.10" "8.10.8" ./patches/ghc/issue-18708.patch # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6554
194 ;
195 ;
195 in ({
196 in ({
overlays/emscripten.nix+2−52
@@ -1,56 +1,6 @@
1−final: prev: let
1+final: prev: {
2− # GHCJS currently requires an old version of emscripten. Overriding to build the older version doesn't
3− # work straightforwardly on 20.09 anymore, so we use an ugly hack and pull emscripten from 20.03.
4− # In future, we'll just fix GHCJS to work with the newer emscripten.
5−
6− # Not sure what to do here - akrmn
7− pkgs-2003 = import final.haskell-nix.sources.nixpkgs-2003 {
8− system = final.stdenv.system;
9− overlays = [(final: prev: with final; {
10− binaryen = callPackage ./emscripten/binaryen.nix {};
11−
12− emscriptenVersion = "1.39.1";
13−
14− emscripten = callPackage ./emscripten { };
15−
16− emscriptenfastcompPackages = dontRecurseIntoAttrs (callPackage ./emscripten/fastcomp { });
17−
18− emscriptenfastcomp = emscriptenfastcompPackages.emscriptenfastcomp;
19−
20− emscriptenupstreamPackages = dontRecurseIntoAttrs (callPackage ./emscripten/upstream { });
21−
22− emscriptenupstream = emscriptenupstreamPackages.emscriptenupstream;
23−
24− # emscriptenPackages = recurseIntoAttrs (callPackage ./emscripten-packages.nix { });
25−
26− emscriptenStdenv = stdenv // { mkDerivation = buildEmscriptenPackage; };
27− })];
28− };
29−
30−in {
31− # nixpkgs does not have an emsdk, this derivation uses symlinks to make something
32− # that matches enought for `ghcjs-boot` to work
33− emscriptenupstream = pkgs-2003.emscriptenupstream;
34− emscripten = (pkgs-2003.emscripten.override {
35− emscriptenBackend = pkgs-2003.emscriptenupstream;
36− }).overrideAttrs (attrs: {
37− buildInputs = attrs.buildInputs or [] ++ [ final.makeWrapper ];
38− buildCommand = attrs.buildCommand or "" + ''
39− for f in $(find $out/bin/ -type l -executable ! -name "*.py"); do
40− if [[ -e "$f.py" ]]; then
41− rm "$f"
42− echo '#!'${final.runtimeShell} > "$f"
43− echo 'if [[ ! -d $HOME ]]; then' >> "$f"
44− echo ' export HOME=$(mktemp -d)' >> "$f"
45− echo 'fi' >> "$f"
46− echo 'exec "'$f.py'" "$@"' >> "$f"
47− chmod +x "$f"
48− fi
49− done
50− '';
51− });
52 emsdk = final.linkFarm "emsdk" [
2 emsdk = final.linkFarm "emsdk" [
53− { name = "upstream/bin"; path = final.emscriptenupstream + "/bin"; }
3+ { name = "upstream/bin"; path = final.clang + "/bin"; }
54 { name = "upstream/emscripten"; path = final.emscripten + "/bin"; }
4 { name = "upstream/emscripten"; path = final.emscripten + "/bin"; }
55 { name = "share"; path = final.emscripten + "/share"; }
5 { name = "share"; path = final.emscripten + "/share"; }
56 ];
6 ];
overlays/emscripten/binaryen.nixdeleted−46
@@ -1,46 +0,0 @@
1−{ stdenv, lib, cmake, python3, fetchFromGitHub, emscriptenRev ? null, substituteAll }:
2−
3−let
4− defaultVersion = "93";
5−
6− # Map from git revs to SHA256 hashes
7− sha256s = {
8− version_93 = "15y3703ha6mxcq168br0wlydas5rq66msrcsd650zrjz0ndxwsfx";
9− "1.39.1" = "0ygm9m5322h4vfpf3j63q32qxk2l26yk62hh7dkb49j51zwl1y3y";
10− };
11−in
12−
13−stdenv.mkDerivation rec {
14− version = if emscriptenRev == null
15− then defaultVersion
16− else "emscripten-${emscriptenRev}";
17− rev = if emscriptenRev == null
18− then "version_${version}"
19− else emscriptenRev;
20− pname = "binaryen";
21−
22− src = fetchFromGitHub {
23− owner = "WebAssembly";
24− repo = "binaryen";
25− sha256 =
26− if builtins.hasAttr rev sha256s
27− then builtins.getAttr rev sha256s
28− else null;
29− inherit rev;
30− };
31−
32− patches = lib.optional (emscriptenRev != null) (substituteAll {
33− src = ./0001-Get-rid-of-git-dependency.patch;
34− emscriptenv = "1.39.1";
35− });
36−
37− nativeBuildInputs = [ cmake python3 ];
38−
39− meta = with lib; {
40− homepage = "https://github.com/WebAssembly/binaryen";
41− description = "Compiler infrastructure and toolchain library for WebAssembly, in C++";
42− platforms = platforms.all;
43− maintainers = with maintainers; [ asppsa ];
44− license = licenses.asl20;
45− };
46−}
overlays/emscripten/default.nixdeleted−71
@@ -1,71 +0,0 @@
1−{ emscriptenVersion, stdenv, lib, fetchFromGitHub, emscriptenfastcomp, python, nodejs, closurecompiler
2−, jre, binaryen, enableWasm ? true , cmake, emscriptenBackend ? emscriptenfastcomp
3−}:
4−
5−let
6− rev = emscriptenVersion;
7− appdir = "share/emscripten";
8− binaryenVersioned = binaryen;
9−in
10−
11−stdenv.mkDerivation {
12− name = "emscripten-${rev}";
13−
14− src = fetchFromGitHub {
15− owner = "emscripten-core";
16− repo = "emscripten";
17− sha256 = "10f2mlwh4s6v3rqghb7zdmv4ry0a4si915x4v17vp4nv7swkkwhn";
18− rev = "fc6a4bb97b421b6dcf5806d0dc42ab8ddd4da026";
19− };
20−
21− buildInputs = [ nodejs cmake python ];
22−
23− buildCommand = ''
24− mkdir -p $out/${appdir}
25− cp -r $src/* $out/${appdir}
26− chmod -R +w $out/${appdir}
27− grep -rl '^#!/usr.*python' $out/${appdir} | xargs sed -i -s 's@^#!/usr.*python.*@#!${python}/bin/python@'
28− sed -i -e "s,EM_CONFIG = '~/.emscripten',EM_CONFIG = '$out/${appdir}/config'," $out/${appdir}/tools/shared.py
29− sed -i -e 's,^.*did not see a source tree above the LLVM.*$, return True,' $out/${appdir}/tools/shared.py
30− sed -i -e 's,def check_sanity(force=False):,def check_sanity(force=False):\n return,' $out/${appdir}/tools/shared.py
31− # fixes cmake support
32− sed -i -e "s/print \('emcc (Emscript.*\)/sys.stderr.write(\1); sys.stderr.flush()/g" $out/${appdir}/emcc.py
33− mkdir $out/bin
34− ln -s $out/${appdir}/{em++,em-config,emar,emar.py,embuilder.py,emcc,emcc.py,emcmake,emconfigure,emconfigure.py,emlink.py,emmake,emmake.py,emranlib,emranlib.py,emrun,emscons} $out/bin
35−
36− echo "EMSCRIPTEN_ROOT = '$out/${appdir}'" > $out/${appdir}/config
37− echo "LLVM_ROOT = '${emscriptenBackend}/bin'" >> $out/${appdir}/config
38− echo "PYTHON = '${python}/bin/python'" >> $out/${appdir}/config
39− echo "NODE_JS = '${nodejs}/bin/node'" >> $out/${appdir}/config
40− echo "JS_ENGINES = [NODE_JS]" >> $out/${appdir}/config
41− echo "COMPILER_ENGINE = NODE_JS" >> $out/${appdir}/config
42− echo "CLOSURE_COMPILER = '${closurecompiler}/share/java/closure-compiler-v${closurecompiler.version}.jar'" >> $out/${appdir}/config
43− echo "JAVA = '${jre}/bin/java'" >> $out/${appdir}/config
44− # to make the test(s) below work
45− echo "SPIDERMONKEY_ENGINE = []" >> $out/${appdir}/config
46− echo "EMCC_FAST_COMPILER = 0" >> $out/${appdir}/config
47− ''
48− + lib.optionalString enableWasm ''
49− echo "BINARYEN_ROOT = '${binaryenVersioned}'" >> $out/share/emscripten/config
50− ''
51− +
52− ''
53− echo "--------------- running test -----------------"
54− # quick hack to get the test working
55− HOME=$TMPDIR
56− cp $out/${appdir}/config $HOME/.emscripten
57− export PATH=$PATH:$out/bin
58−
59− #export EMCC_DEBUG=2
60− ${python}/bin/python $src/tests/runner.py test_hello_world
61− echo "--------------- /running test -----------------"
62− '';
63−
64− meta = with lib; {
65− homepage = "https://github.com/emscripten-core/emscripten";
66− description = "An LLVM-to-JavaScript Compiler";
67− platforms = platforms.all;
68− maintainers = with maintainers; [ qknight matthewbauer ];
69− license = licenses.ncsa;
70− };
71−}
overlays/emscripten/fastcomp/emscripten-fastcomp.nixdeleted−55
@@ -1,55 +0,0 @@
1−{ emscriptenVersion, stdenv, lib, fetchFromGitHub, cmake, python, gtest, ... }:
2−
3−let
4− rev = emscriptenVersion;
5− gcc = if stdenv.cc.isGNU then stdenv.cc.cc else stdenv.cc.cc.gcc;
6−in
7−stdenv.mkDerivation rec {
8− name = "emscripten-fastcomp-${rev}";
9−
10− src = fetchFromGitHub {
11− owner = "emscripten-core";
12− repo = "emscripten-fastcomp";
13− sha256 = "0bd0l5k2fa4k0nax2cpxi003pqffqivx4z4m2j5xdha1a12sid8i";
14− inherit rev;
15− };
16−
17− srcFL = fetchFromGitHub {
18− owner = "emscripten-core";
19− repo = "emscripten-fastcomp-clang";
20− sha256 = "1iw2qplhp489qzw0rma73sab7asnm27g4m95sr36c6kq9cq6agri";
21− inherit rev;
22− };
23−
24− nativeBuildInputs = [ cmake python gtest ];
25− preConfigure = ''
26− cp -Lr ${srcFL} tools/clang
27− chmod +w -R tools/clang
28− '';
29− cmakeFlags = [
30− "-DCMAKE_BUILD_TYPE=Release"
31− "-DLLVM_TARGETS_TO_BUILD='X86;JSBackend'"
32− "-DLLVM_INCLUDE_EXAMPLES=OFF"
33− "-DLLVM_INCLUDE_TESTS=ON"
34− #"-DLLVM_CONFIG=${llvm}/bin/llvm-config"
35− "-DLLVM_BUILD_TESTS=ON"
36− "-DCLANG_INCLUDE_TESTS=ON"
37− ] ++ (lib.optional stdenv.isLinux
38− # necessary for clang to find crtend.o
39− "-DGCC_INSTALL_PREFIX=${gcc}"
40− );
41− enableParallelBuilding = true;
42−
43− passthru = {
44− isClang = true;
45− inherit gcc;
46− };
47−
48− meta = with lib; {
49− homepage = "https://github.com/emscripten-core/emscripten-fastcomp";
50− description = "Emscripten LLVM";
51− platforms = platforms.all;
52− maintainers = with maintainers; [ qknight matthewbauer ];
53− license = lib.licenses.ncsa;
54− };
55−}
overlays/emscripten/upstream/emscripten-upstream.nixdeleted−60
@@ -1,60 +0,0 @@
1−{ emscriptenVersion, stdenv, lib, fetchFromGitHub, cmake, python, gtest, ... }:
2−
3−let
4− gcc = if stdenv.cc.isGNU then stdenv.cc.cc else stdenv.cc.cc.gcc;
5−in
6−stdenv.mkDerivation rec {
7− name = "emscripten-upstream";
8−
9− src = (fetchFromGitHub {
10− owner = "llvm";
11− repo = "llvm-project";
12− rev = "5f7ea85e789d5b5f3f463e538a28c040e373620b";
13− sha256 = "1kik1zdl1igkdri9zkdri7jwjjfjwhzniaw2a57lr80ajhs60kr7";
14− });
15−
16− nativeBuildInputs = [ cmake python gtest ];
17− setSourceRoot = ''
18− sourceRoot=$(echo */llvm)
19− '';
20− cmakeFlags = [
21− "-DCMAKE_CXX_FLAGS=-Wno-nonportable-include-path"
22− "-DLLVM_ENABLE_LIBXML2=OFF"
23− "-DLLVM_INCLUDE_EXAMPLES=OFF"
24− "-DCOMPILER_RT_BUILD_XRAY=OFF"
25− "-DCOMPILER_RT_INCLUDE_TESTS=OFF"
26− "-DCOMPILER_RT_ENABLE_IOS=OFF"
27− "-DLLVM_BUILD_LLVM_DYLIB=ON"
28− "-DLLVM_LINK_LLVM_DYLIB=ON"
29− "-DLLVM_TOOL_LTO_BUILD=OFF"
30− # "-DLLVM_INSTALL_TOOLCHAIN_ONLY=ON"
31− "-DLLVM_ENABLE_ASSERTIONS=ON"
32− "-DLLVM_TARGETS_TO_BUILD=X86;WebAssembly"
33− "-DLLVM_ENABLE_PROJECTS=lld;clang"
34− "-DLLVM_ENABLE_TERMINFO=0"
35−
36− "-DCMAKE_BUILD_TYPE=Release"
37− "-DLLVM_INCLUDE_EXAMPLES=OFF"
38− "-DLLVM_INCLUDE_TESTS=ON"
39− #"-DLLVM_CONFIG=${llvm}/bin/llvm-config"
40− "-DLLVM_BUILD_TESTS=ON"
41− "-DCLANG_INCLUDE_TESTS=OFF"
42− ] ++ (lib.optional stdenv.isLinux
43− # necessary for clang to find crtend.o
44− "-DGCC_INSTALL_PREFIX=${gcc}"
45− );
46− enableParallelBuilding = true;
47−
48− passthru = {
49− isClang = true;
50− inherit gcc;
51− };
52−
53− meta = with lib; {
54− homepage = "http://github.com/llvm/llvm-project";
55− description = "LLVM";
56− platforms = platforms.all;
57− maintainers = with maintainers; [ ];
58− license = lib.licenses.ncsa;
59− };
60−}
overlays/patches/ghc-lib-parser-8.10-global-unique-counters-in-rts.patchnew file+20
@@ -0,0 +1,20 @@
1+diff --git a/compiler/cbits/genSym.c b/compiler/cbits/genSym.c
2+index ecb318d5a8..8e70db33fc 100644
3+--- a/compiler/cbits/genSym.c
4++++ b/compiler/cbits/genSym.c
5+@@ -1,9 +1,15 @@
6+ #include <Rts.h>
7+ #include <assert.h>
8+ #include "Unique.h"
9++#include "ghcversion.h"
10+
11++// These global variables have been moved into the RTS. It allows them to be
12++// shared with plugins even if two different instances of the GHC library are
13++// loaded at the same time (#19940)
14++#if !MIN_VERSION_GLASGOW_HASKELL(8,10,0,0)
15+ static HsInt GenSymCounter = 0;
16+ static HsInt GenSymInc = 1;
17++#endif
18+
19+ #define UNIQUE_BITS (sizeof (HsInt) * 8 - UNIQUE_TAG_BITS)
20+ #define UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)
overlays/patches/ghc/ghc-8.10-global-unique-counters-in-rts.patchnew file+55
@@ -0,0 +1,55 @@
1+diff --git a/compiler/cbits/genSym.c b/compiler/cbits/genSym.c
2+index ecb318d5a8..8e70db33fc 100644
3+--- a/compiler/cbits/genSym.c
4++++ b/compiler/cbits/genSym.c
5+@@ -1,9 +1,15 @@
6+ #include <Rts.h>
7+ #include <assert.h>
8+ #include "Unique.h"
9++#include "ghcversion.h"
10+
11++// These global variables have been moved into the RTS. It allows them to be
12++// shared with plugins even if two different instances of the GHC library are
13++// loaded at the same time (#19940)
14++#if !MIN_VERSION_GLASGOW_HASKELL(8,10,0,0) || GHC_STAGE < 2
15+ static HsInt GenSymCounter = 0;
16+ static HsInt GenSymInc = 1;
17++#endif
18+
19+ #define UNIQUE_BITS (sizeof (HsInt) * 8 - UNIQUE_TAG_BITS)
20+ #define UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)
21+diff --git a/includes/rts/Globals.h b/includes/rts/Globals.h
22+index ff36572c56..12db025423 100644
23+--- a/includes/rts/Globals.h
24++++ b/includes/rts/Globals.h
25+@@ -34,3 +34,7 @@ mkStoreAccessorPrototype(LibHSghcInitLinkerDone)
26+ mkStoreAccessorPrototype(LibHSghcGlobalDynFlags)
27+ mkStoreAccessorPrototype(LibHSghcStaticOptions)
28+ mkStoreAccessorPrototype(LibHSghcStaticOptionsReady)
29++#if GHC_STAGE >= 2
30++extern HsInt GenSymCounter;
31++extern HsInt GenSymInc;
32++#endif
33+diff --git a/rts/Globals.c b/rts/Globals.c
34+index c9980d9a3a..56522937ef 100644
35+--- a/rts/Globals.c
36++++ b/rts/Globals.c
37+@@ -111,3 +111,5 @@ mkStoreAccessor(LibHSghcInitLinkerDone)
38+ mkStoreAccessor(LibHSghcGlobalDynFlags)
39+ mkStoreAccessor(LibHSghcStaticOptions)
40+ mkStoreAccessor(LibHSghcStaticOptionsReady)
41++HsInt GenSymCounter = 0;
42++HsInt GenSymInc = 1;
43+diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
44+index d5b8cc5fec..7ed561ff3f 100644
45+--- a/rts/RtsSymbols.c
46++++ b/rts/RtsSymbols.c
47+@@ -646,6 +646,8 @@
48+ SymI_HasProto(getOrSetLibHSghcPersistentLinkerState) \
49+ SymI_HasProto(getOrSetLibHSghcInitLinkerDone) \
50+ SymI_HasProto(getOrSetLibHSghcGlobalDynFlags) \
51++ SymI_HasProto(GenSymCounter) \
52++ SymI_HasProto(GenSymInc) \
53+ SymI_HasProto(genericRaise) \
54+ SymI_HasProto(getProgArgv) \
55+ SymI_HasProto(getFullProgArgv) \
test/c-ffi/c-ffi.cabalnew file+24
@@ -0,0 +1,24 @@
1+cabal-version: >=1.10
2+name: c-ffi
3+version: 0.1.0.0
4+license: PublicDomain
5+author: Hamish Mackenzie
6+maintainer: Hamish.K.Mackenzie@gmail.com
7+build-type: Simple
8+
9+library
10+ exposed-modules:
11+ Lib
12+ c-sources: cbits/test.c
13+ if os(ghcjs)
14+ js-sources: jsbits/bindings.js
15+ build-depends: base
16+ hs-source-dirs: src
17+ default-language: Haskell2010
18+
19+executable c-ffi
20+ main-is: Main.hs
21+ build-depends: base
22+ , c-ffi
23+ hs-source-dirs: exe
24+ default-language: Haskell2010
test/c-ffi/cbits/test.cnew file+7
@@ -0,0 +1,7 @@
1+#include <stdio.h>
2+
3+double add1(double x) {
4+ return x + 1;
5+};
6+
7+
test/c-ffi/default.nixnew file+65
@@ -0,0 +1,65 @@
1+# Test a package set
2+{ stdenv, lib, util, mkCabalProjectPkgSet, project', haskellLib, recurseIntoAttrs, testSrc, compiler-nix-name }:
3+
4+with lib;
5+
6+let
7+ modules = [
8+ {
9+ # Package has no exposed modules which causes
10+ # haddock: No input file(s)
11+ packages.c-ffi.doHaddock = false;
12+ }
13+ ];
14+
15+ project = project' {
16+ inherit compiler-nix-name;
17+ src = testSrc "c-ffi";
18+ inherit modules;
19+ };
20+
21+ packages = project.hsPkgs;
22+
23+in recurseIntoAttrs {
24+ ifdInputs = {
25+ inherit (project) plan-nix;
26+ };
27+
28+ run = stdenv.mkDerivation {
29+ name = "c-ffi-test";
30+
31+ buildCommand = ''
32+ exe="${packages.c-ffi.components.exes.c-ffi.exePath}"
33+
34+ size=$(command stat --format '%s' "$exe")
35+ printf "size of executable $exe is $size. \n" >& 2
36+
37+ # fixme: run on target platform when cross-compiled
38+ printf "checking whether executable runs... " >& 2
39+ cat ${haskellLib.check packages.c-ffi.components.exes.c-ffi}/test-stdout
40+ '' + (if stdenv.hostPlatform.isMusl
41+ then ''
42+ printf "checking that executable is statically linked... " >& 2
43+ (ldd $exe 2>&1 || true) | grep -i "not a"
44+ ''
45+ else
46+ # Skip this on aarch as we do not have an `ldd` tool
47+ optionalString (!stdenv.hostPlatform.isAarch32 && !stdenv.hostPlatform.isAarch64) (''
48+ printf "checking that executable is dynamically linked to system libraries... " >& 2
49+ '' + optionalString stdenv.isLinux ''
50+ ldd $exe | grep libpthread
51+ '' + optionalString stdenv.isDarwin ''
52+ otool -L $exe |grep .dylib
53+ '')) + ''
54+
55+ touch $out
56+ '';
57+
58+ meta.platforms = platforms.all;
59+
60+ passthru = {
61+ # Used for debugging with nix repl
62+ inherit project packages;
63+ };
64+ };
65+}
test/c-ffi/exe/Main.hsnew file+15
@@ -0,0 +1,15 @@
1+module Main where
2+
3+import Control.Monad (when)
4+import System.Exit (exitFailure)
5+
6+import Lib (c_add1)
7+
8+main :: IO ()
9+main =
10+ if c_add1 1 /= 2
11+ then do
12+ putStrLn "Unexpected Result calling `c_add1 1`"
13+ exitFailure
14+ else putStrLn "OK"
15+
test/c-ffi/jsbits/bindings.jsnew file+6
@@ -0,0 +1,6 @@
1+// EMCC:EXPORTED_FUNCTIONS _malloc _free
2+// EMCC:EXPORTED_FUNCTIONS _add1
3+function h$add1(x) {
4+ return _add1(x);
5+}
6+
test/c-ffi/src/Lib.hsnew file+6
@@ -0,0 +1,6 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+module Lib where
3+
4+foreign import ccall "add1" c_add1 :: Double -> Double
5+
6+
test/default.nix+1
@@ -200,6 +200,7 @@ let
200 snapshots = callTest ./snapshots { inherit compiler-nix-name; };
200 snapshots = callTest ./snapshots { inherit compiler-nix-name; };
201 sublib-docs = callTest ./sublib-docs { inherit util compiler-nix-name; };
201 sublib-docs = callTest ./sublib-docs { inherit util compiler-nix-name; };
202 githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
202 githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
203+ c-ffi = callTest ./c-ffi { inherit util compiler-nix-name; };
203
204
204 unit = unitTests;
205 unit = unitTests;
205 };
206 };