2014-08-26 18:35:29 +01:00
# generic builder for Cabal packages
{ stdenv , fetchurl , lib , pkgconfig , ghcjs , ghc , Cabal , jailbreakCabal , glibcLocales
, gnugrep , coreutils , hscolour # hscolour is unused
, enableLibraryProfiling ? false
, enableSharedLibraries ? false
, enableSharedExecutables ? false
, enableStaticLibraries ? true
2015-01-02 17:30:19 +00:00
, enableCheckPhase ? true
2014-08-26 18:35:29 +01:00
, enableHyperlinkSource ? false
, extension ? ( self : super : { } )
} :
let
enableFeature = stdenv . lib . enableFeature ;
optional = stdenv . lib . optional ;
optionals = stdenv . lib . optionals ;
optionalString = stdenv . lib . optionalString ;
filter = stdenv . lib . filter ;
2014-09-20 23:54:09 +01:00
defaultSetupHs = builtins . toFile " S e t u p . h s " ''
import Distribution . Simple
main = defaultMain
'' ;
2014-08-26 18:35:29 +01:00
in
{
mkDerivation =
args : # arguments for the individual package, can modify the defaults
let # These attributes are removed in the end. This is in order not to spoil the build
# environment overly, but also to keep hash-backwards-compatible with the old cabal.nix.
internalAttrs = [
" i n t e r n a l A t t r s " " b u i l d D e p e n d s " " b u i l d T o o l s " " e x t r a L i b r a r i e s " " p k g c o n f i g D e p e n d s "
" i s L i b r a r y " " i s E x e c u t a b l e " " t e s t D e p e n d s "
] ;
# Stuff happening after the user preferences have been processed. We remove
# internal attributes and strip null elements from the dependency lists, all
# in the interest of keeping hashes stable.
postprocess =
x : ( removeAttrs x internalAttrs ) // {
buildInputs = filter ( y : ! ( y == null ) ) x . buildInputs ;
propagatedBuildInputs = filter ( y : ! ( y == null ) ) x . propagatedBuildInputs ;
propagatedUserEnvPkgs = filter ( y : ! ( y == null ) ) x . propagatedUserEnvPkgs ;
doCheck = enableCheckPhase && x . doCheck ;
hyperlinkSource = enableHyperlinkSource && x . hyperlinkSource ;
} ;
defaults =
self : { # self is the final version of the attribute set
# pname should be defined by the client to be the package basename
# version should be defined by the client to be the package version
# fname is the internal full name of the package
fname = " ${ self . pname } - ${ self . version } " ;
# name is the external full name of the package; usually we prefix
# all packages with haskell- to avoid name clashes for libraries;
# if that is not desired (for applications), name can be set to
# fname.
name = if self . isLibrary then
if enableLibraryProfiling && self . enableSharedLibraries then
" h a s k e l l - ${ self . pname } - g h c j s ${ ghc . ghc . version } - ${ self . version } - p r o f i l i n g - s h a r e d "
else if enableLibraryProfiling && ! self . enableSharedLibraries then
" h a s k e l l - ${ self . pname } - g h c j s ${ ghc . ghc . version } - ${ self . version } - p r o f i l i n g "
else if ! enableLibraryProfiling && self . enableSharedLibraries then
" h a s k e l l - ${ self . pname } - g h c j s ${ ghc . ghc . version } - ${ self . version } - s h a r e d "
else
" h a s k e l l - ${ self . pname } - g h c j s ${ ghc . ghc . version } - ${ self . version } "
else
" ${ self . pname } - ${ self . version } " ;
# the default download location for Cabal packages is Hackage,
# you still have to specify the checksum
src = fetchurl {
url = " m i r r o r : / / h a c k a g e / ${ self . pname } / ${ self . fname } . t a r . g z " ;
inherit ( self ) sha256 ;
} ;
# default buildInputs are just ghc, if more buildInputs are required
# buildInputs can be extended by the client by using extraBuildInputs,
# but often propagatedBuildInputs is preferable anyway
2015-01-09 13:29:56 +00:00
buildInputs = [ ghc ghc . ghc . parent . Cabal_1_22_0_0 ] ++ self . extraBuildInputs ;
2014-08-26 18:35:29 +01:00
extraBuildInputs = self . buildTools ++
( optionals self . doCheck self . testDepends ) ++
( if self . pkgconfigDepends == [ ] then [ ] else [ pkgconfig ] ) ++
( if self . isLibrary then [ ] else self . buildDepends ++ self . extraLibraries ++ self . pkgconfigDepends ) ;
# we make sure that propagatedBuildInputs is defined, so that we don't
# have to check for its existence
propagatedBuildInputs = if self . isLibrary then self . buildDepends ++ self . extraLibraries ++ self . pkgconfigDepends else [ ] ;
# By default, also propagate all dependencies to the user environment. This is required, otherwise packages would be broken, because
# GHC also needs all dependencies to be available.
propagatedUserEnvPkgs = if self . isLibrary then self . buildDepends else [ ] ;
# library directories that have to be added to the Cabal files
extraLibDirs = [ ] ;
# build-depends Cabal field
buildDepends = [ ] ;
# target(s) passed to the cabal build phase as an argument
buildTarget = " " ;
# build-depends Cabal fields stated in test-suite stanzas
testDepends = [ ] ;
# target(s) passed to the cabal test phase as an argument
testTarget = " " ;
# build-tools Cabal field
buildTools = [ ] ;
# extra-libraries Cabal field
extraLibraries = [ ] ;
# pkgconfig-depends Cabal field
pkgconfigDepends = [ ] ;
isLibrary = ! self . isExecutable ;
isExecutable = false ;
# ignore version restrictions on the build inputs that the cabal file might specify
jailbreak = false ;
# pass the '--enable-split-objs' flag to cabal in the configure stage
enableSplitObjs = false ; # !stdenv.isDarwin; # http://hackage.haskell.org/trac/ghc/ticket/4013
# pass the '--enable-tests' flag to cabal in the configure stage
# and run any regression test suites the package might have
doCheck = false ; #enableCheckPhase;
# pass the '--hyperlink-source' flag to ./Setup haddock
hyperlinkSource = enableHyperlinkSource ;
# abort the build if the configure phase detects that the package
# depends on multiple versions of the same build input
strictConfigurePhase = true ;
# pass the '--enable-library-vanilla' flag to cabal in the
# configure stage to enable building shared libraries
inherit enableStaticLibraries ;
# pass the '--enable-shared' flag to cabal in the configure
# stage to enable building shared libraries
inherit enableSharedLibraries ;
# pass the '--enable-executable-dynamic' flag to cabal in
# the configure stage to enable linking shared libraries
inherit enableSharedExecutables ;
extraConfigureFlags = [
( enableFeature self . enableSplitObjs " s p l i t - o b j s " )
( enableFeature enableLibraryProfiling " l i b r a r y - p r o f i l i n g " )
( enableFeature true " s h a r e d " )
2015-01-02 17:30:19 +00:00
( enableFeature self . enableStaticLibraries " l i b r a r y - v a n i l l a " )
( enableFeature self . enableSharedExecutables " e x e c u t a b l e - d y n a m i c " )
( enableFeature self . doCheck " t e s t s " )
2014-08-26 18:35:29 +01:00
] ;
# GHC needs the locale configured during the Haddock phase.
LANG = " e n _ U S . U T F - 8 " ;
LOCALE_ARCHIVE = optionalString stdenv . isLinux " ${ glibcLocales } / l i b / l o c a l e / l o c a l e - a r c h i v e " ;
# compiles Setup and configures
configurePhase = ''
eval " $ p r e C o n f i g u r e "
$ { optionalString self . jailbreak " ${ ghc . ghc . parent . jailbreakCabal } / b i n / j a i l b r e a k - c a b a l ${ self . pname } . c a b a l " }
PATH = $ PATH:$ { ghc . ghc . ghc } /bin
2014-09-20 23:54:09 +01:00
for i in Setup . hs Setup . lhs $ { defaultSetupHs } ; do
test - f $ i && break
2014-08-26 18:35:29 +01:00
done
2014-09-20 23:54:09 +01:00
ghc - - make - o Setup - odir $ TMPDIR - hidir $ TMPDIR $ i
2014-08-26 18:35:29 +01:00
for p in $ extraBuildInputs $ propagatedBuildInputs $ propagatedNativeBuildInputs ; do
PkgDir = " $ p / l i b / g h c j s - ${ ghc . ghc . version } _ g h c - ${ ghc . ghc . ghc . version } / p a c k a g e . c o n f . d "
if [ - f " $ P k g D i r / p a c k a g e . c a c h e " ] ; then
extraConfigureFlags + = " - - p a c k a g e - d b = $ P k g D i r "
continue ;
fi
if [ - d " $ p / i n c l u d e " ] ; then
extraConfigureFlags + = " - - e x t r a - i n c l u d e - d i r s = $ p / i n c l u d e "
fi
for d in lib { , 64 } ; do
if [ - d " $ p / $ d " ] ; then
extraConfigureFlags + = " - - e x t r a - l i b - d i r s = $ p / $ d "
fi
done
done
2014-12-12 01:53:25 +00:00
configureFlags + = " - - p a c k a g e - d b = ${ ghc . ghc } / ${ ghc . ghc . libDir } / p a c k a g e . c o n f . d "
2014-08-26 18:35:29 +01:00
$ { optionalString ( self . enableSharedExecutables && self . stdenv . isLinux ) ''
configureFlags + = " - - g h c - o p t i o n = - o p t l = - W l , - r p a t h = $ o u t / l i b / ${ ghc . ghc . name } / ${ self . pname } - ${ self . version } " ;
'' }
$ { optionalString ( self . enableSharedExecutables && self . stdenv . isDarwin ) ''
configureFlags + = " - - g h c - o p t i o n = - o p t l = - W l , - h e a d e r p a d _ m a x _ i n s t a l l _ n a m e s " ;
'' }
echo " c o n f i g u r e f l a g s : $ e x t r a C o n f i g u r e F l a g s $ c o n f i g u r e F l a g s "
./Setup configure - - ghcjs - - verbose - - prefix = " $ o u t " - - libdir = ' $ prefix/lib / $ compiler' \
- - libsubdir = ' $ pkgid' $ extraConfigureFlags $ configureFlags 2 > & 1 \
$ { optionalString self . strictConfigurePhase ''
| $ { coreutils } /bin/tee " $ N I X _ B U I L D _ T O P / c a b a l - c o n f i g u r e . l o g "
if $ { gnugrep } /bin/egrep - q ' ^ Warning:.*depends on multiple versions' " $ N I X _ B U I L D _ T O P / c a b a l - c o n f i g u r e . l o g " ; then
echo > & 2 " * * * a b o r t b e c a u s e o f s e r i o u s c o n f i g u r e - t i m e w a r n i n g f r o m C a b a l "
exit 1
fi
'' }
eval " $ p o s t C o n f i g u r e "
'' ;
# builds via Cabal
buildPhase = ''
eval " $ p r e B u i l d "
./Setup build $ { self . buildTarget }
export GHC_PACKAGE_PATH = $ ( $ { ghc . GHCPackages } )
#test -n "$noHaddock" || ./Setup haddock --html --hoogle \
# ${optionalString self.hyperlinkSource "--hyperlink-source"}
eval " $ p o s t B u i l d "
'' ;
checkPhase = optional self . doCheck ''
eval " $ p r e C h e c k "
./Setup test $ { self . testTarget }
eval " $ p o s t C h e c k "
'' ;
# installs via Cabal; creates a registration file for nix-support
# so that the package can be used in other Haskell-builds; also
# adds all propagated build inputs to the user environment packages
installPhase = ''
eval " $ p r e I n s t a l l "
./Setup copy
2014-11-29 13:24:31 +00:00
mkdir - p $ out/bin # necessary to get it added to PATH
2014-08-26 18:35:29 +01:00
local confDir = $ out/lib/ghcjs- $ { ghc . ghc . version } _ghc- $ { ghc . ghc . ghc . version } /package.conf.d
local installedPkgConf = $ confDir / $ { self . fname } . installedconf
local pkgConf = $ confDir / $ { self . fname } . conf
2014-11-29 13:24:31 +00:00
mkdir - p $ confDir
2014-08-26 18:35:29 +01:00
./Setup register - - gen-pkg-config = $ pkgConf
if test - f $ pkgConf ; then
echo ' [ ] ' > $ installedPkgConf
GHC_PACKAGE_PATH = $ installedPkgConf ghcjs-pkg - - global register $ pkgConf - - force - - package-db = $ confDir || true
ghcjs-pkg recache - - package-db = $ confDir
fi
if test - f $ out/nix-support/propagated-native-build-inputs ; then
ln - s $ out/nix-support/propagated-native-build-inputs $ out/nix-support/propagated-user-env-packages
fi
$ { optionalString ( self . enableSharedExecutables && self . isExecutable && self . stdenv . isDarwin ) ''
for exe in $ out/bin /* ; d o
2014-08-27 18:15:33 +01:00
install_name_tool - add_rpath $ out/lib / $ { ghc . ghc . name } / $ { self . pname } - $ { self . version } $ exe || true # Ignore failures, which seem to be due to hitting bash scripts rather than binaries
2014-08-26 18:35:29 +01:00
done
'' }
eval " $ p o s t I n s t a l l "
'' ;
# We inherit stdenv and ghc so that they can be used
# in Cabal derivations.
inherit stdenv ghc ;
} ;
in
stdenv . mkDerivation ( postprocess ( let super = defaults self // args self ;
self = super // extension self super ;
in self ) ) ;
}