mirror of
https://github.com/nmattia/snack.git
synced 2024-09-11 11:55:36 +03:00
Add snack ghci
This commit is contained in:
parent
ac18afcf88
commit
54944a8cd8
@ -6,7 +6,15 @@ import (import nixpkgs) {
|
||||
(self: super: { snack-lib-with = extra: import ../snack extra;} )
|
||||
(self: super: { snack = self.writeScriptBin "snack"
|
||||
''
|
||||
${self.nix}/bin/nix-build snack.nix
|
||||
set -e
|
||||
case $1 in
|
||||
build)
|
||||
${self.nix}/bin/nix-build snack.nix
|
||||
;;
|
||||
ghci)
|
||||
res=$(${self.nix}/bin/nix-build -A ghci snack.nix)
|
||||
$res/bin/ghci
|
||||
esac
|
||||
''; })
|
||||
];
|
||||
}
|
||||
|
12
script/test
12
script/test
@ -7,18 +7,6 @@
|
||||
|
||||
set -eux
|
||||
|
||||
pushd tests/flat
|
||||
snack build
|
||||
popd
|
||||
|
||||
pushd tests/nested
|
||||
snack build
|
||||
popd
|
||||
|
||||
pushd tests/dependencies
|
||||
snack build
|
||||
popd
|
||||
|
||||
pushd tests/packages
|
||||
snack build
|
||||
popd
|
||||
|
@ -6,13 +6,8 @@
|
||||
# change: when a module is built with its dependencies, the flags for the
|
||||
# dependencies change as well, which causes them to be recompiled
|
||||
{ pkgs ? import (../nix) {} # nixpkgs
|
||||
, dependencies ? [] # The list of haskell dependencies, e.g. conduit, mtl, etc
|
||||
, ghcWith ? pkgs.haskellPackages.ghcWithPackages
|
||||
}:
|
||||
let
|
||||
# GHC with the package DB
|
||||
ghc = ghcWith (ps: map (p: ps.${p}) dependencies);
|
||||
|
||||
# Takes a (string) filepath and creates a derivation for that file (and for
|
||||
# that file only)
|
||||
singleOut = base: file:
|
||||
@ -77,13 +72,10 @@ let
|
||||
isMain
|
||||
) true;
|
||||
|
||||
buildFrom = base: modName: linkModuleObjects base
|
||||
(makeModuleSpecRec base modName);
|
||||
|
||||
buildModule = base: mod:
|
||||
buildModule = ghc: base: mod:
|
||||
let
|
||||
objectName = mod.moduleName;
|
||||
builtDeps = map (buildModule base) mod.moduleDependencies;
|
||||
builtDeps = map (buildModule ghc base) mod.moduleDependencies;
|
||||
depsDirs = map (x: x + "/") builtDeps;
|
||||
makeSymtree =
|
||||
if pkgs.lib.lists.length depsDirs >= 1
|
||||
@ -176,7 +168,7 @@ let
|
||||
|
||||
# Returns an attribute set where the keys are the module names and the values
|
||||
# are the '.o's
|
||||
flattenModuleObjects = base: mod':
|
||||
flattenModuleObjects = ghc: base: mod':
|
||||
let
|
||||
go = mod: attrs0:
|
||||
let
|
||||
@ -193,15 +185,16 @@ let
|
||||
then acc
|
||||
else acc //
|
||||
{ "${elem.moduleName}" =
|
||||
"${buildModule base elem}/${objectName elem}";
|
||||
"${buildModule ghc base elem}/${objectName elem}";
|
||||
};
|
||||
in
|
||||
pkgs.lib.lists.foldl f attrs1 mod.moduleDependencies;
|
||||
in go mod' {};
|
||||
|
||||
linkModuleObjects = base: mod:
|
||||
# TODO: it's sad that we pass ghcWithDeps + dependencies
|
||||
linkModuleObjects = ghc: dependencies: base: mod:
|
||||
let
|
||||
objAttrs = flattenModuleObjects base mod;
|
||||
objAttrs = flattenModuleObjects ghc base mod;
|
||||
objList = pkgs.lib.attrsets.mapAttrsToList (x: y: y) objAttrs;
|
||||
packageList = map (p: "-package ${p}") dependencies;
|
||||
in pkgs.stdenv.mkDerivation
|
||||
@ -211,22 +204,65 @@ let
|
||||
''
|
||||
source $stdenv/setup
|
||||
mkdir -p $out
|
||||
ghc \
|
||||
${ghc}/bin/ghc \
|
||||
${pkgs.lib.strings.escapeShellArgs packageList} \
|
||||
${pkgs.lib.strings.escapeShellArgs objList} \
|
||||
-o $out/out
|
||||
'';
|
||||
buildInputs =
|
||||
[ ghc
|
||||
];
|
||||
};
|
||||
|
||||
# Returns a list of all module names depended on in the module spec
|
||||
allModuleNames = modSpec:
|
||||
[ modSpec.moduleName ] ++ (pkgs.lib.lists.concatMap allModuleNames modSpec.moduleDependencies);
|
||||
|
||||
# Write a new ghci executable that loads all the modules defined in the
|
||||
# module spec
|
||||
ghciExecutable = ghc: base: modSpec:
|
||||
let
|
||||
ghciArgs = pkgs.lib.strings.escapeShellArgs absoluteModuleFiles;
|
||||
absoluteModuleFiles = map prependBase moduleFiles;
|
||||
moduleFiles = map moduleToFile modules;
|
||||
modules = allModuleNames modSpec;
|
||||
prependBase = f: builtins.toString base + "/${f}";
|
||||
in
|
||||
pkgs.symlinkJoin
|
||||
{ name = "ghci";
|
||||
paths = [ ghc ];
|
||||
postBuild =
|
||||
''
|
||||
source $stdenv/setup
|
||||
wrapProgram "$out/bin/ghci" \
|
||||
--add-flags "${ghciArgs}"
|
||||
'';
|
||||
buildInputs = [pkgs.makeWrapper];
|
||||
};
|
||||
|
||||
snack = executable:
|
||||
{
|
||||
build =
|
||||
let
|
||||
ghc = pkgs.haskellPackages.ghcWithPackages
|
||||
(ps: map (p: ps.${p}) deps);
|
||||
deps = executable.dependencies;
|
||||
base = executable.src;
|
||||
mainModName = executable.main;
|
||||
in linkModuleObjects ghc deps base (makeModuleSpecRec base mainModName);
|
||||
ghci =
|
||||
let
|
||||
ghc = pkgs.haskellPackages.ghcWithPackages
|
||||
(ps: map (p: ps.${p}) deps);
|
||||
deps = executable.dependencies;
|
||||
base = executable.src;
|
||||
mainModName = executable.main;
|
||||
in ghciExecutable ghc base (makeModuleSpecRec base mainModName);
|
||||
};
|
||||
|
||||
|
||||
|
||||
## TODO: use ghc -M for module dependencies
|
||||
in
|
||||
{
|
||||
inherit
|
||||
buildFrom
|
||||
linkModuleObjects
|
||||
makeModuleSpec
|
||||
snack
|
||||
;
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
# This "snack" passing is ugly, figure out a nice way of passing snack-lib
|
||||
with (import ../../nix {}).snack-lib;
|
||||
buildFrom ./src "Foo"
|
@ -1,3 +0,0 @@
|
||||
module BarFoo where
|
||||
|
||||
barFoo = "bar foo"
|
@ -1,2 +0,0 @@
|
||||
module Data.Foo where
|
||||
dataFoo = "Data, Foo."
|
@ -1,10 +0,0 @@
|
||||
import Data.Foo
|
||||
import Haskell
|
||||
import qualified FooBar
|
||||
import qualified BarFoo as F
|
||||
|
||||
main = do
|
||||
putStrLn dataFoo
|
||||
putStrLn haskell
|
||||
putStrLn FooBar.fooBar
|
||||
putStrLn F.barFoo
|
@ -1,2 +0,0 @@
|
||||
module FooBar where
|
||||
fooBar = "foo bar"
|
@ -1,2 +0,0 @@
|
||||
module Haskell where
|
||||
haskell = "haskell!"
|
@ -1,4 +0,0 @@
|
||||
import B
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn (var ++ ", world!")
|
@ -1,4 +0,0 @@
|
||||
module B where
|
||||
|
||||
var :: String
|
||||
var = "Hello"
|
@ -1,3 +0,0 @@
|
||||
# Flat
|
||||
|
||||
Makes sure that two modules, `A.hs` and `B.hs`, can be built into an executable
|
@ -1,6 +0,0 @@
|
||||
# This "snack" passing is ugly, figure out a nice way of passing snack-lib
|
||||
with (import ../../nix {}).snack-lib;
|
||||
let
|
||||
modB = makeModuleSpec "B" [] false;
|
||||
modA = makeModuleSpec "A" [modB] true;
|
||||
in linkModuleObjects ./. modA
|
@ -1,3 +0,0 @@
|
||||
import Foo.B.C
|
||||
|
||||
main = putStrLn var
|
@ -1,3 +0,0 @@
|
||||
module Foo.B.C where
|
||||
|
||||
var = "Hello, World!"
|
@ -1,4 +0,0 @@
|
||||
# Nested
|
||||
|
||||
Make sure that nested modules (e.g. `Foo.A` and `Foo.B.C`) can be built into an
|
||||
executable
|
@ -1,6 +0,0 @@
|
||||
# This "snack" passing is ugly, figure out a nice way of passing snack-lib
|
||||
with (import ../../nix {}).snack-lib;
|
||||
let
|
||||
modB = makeModuleSpec "Foo.B.C" [] false;
|
||||
modA = makeModuleSpec "Foo.A" [modB] true;
|
||||
in linkModuleObjects ./. modA
|
@ -1,5 +1,9 @@
|
||||
# This "snack" passing is ugly, figure out a nice way of passing snack-lib
|
||||
with (import ../../nix {}).snack-lib-with
|
||||
{ dependencies = ["conduit"] ;
|
||||
};
|
||||
buildFrom ./src "Foo"
|
||||
let
|
||||
pkgs = import ../../nix {};
|
||||
snack = pkgs.snack-lib.snack;
|
||||
in
|
||||
snack
|
||||
{ main = "Foo";
|
||||
src = ./src;
|
||||
dependencies = ["conduit"];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user