build.nix (5488B)
1 { pkgs, source, haskellPackages ? pkgs.haskellPackages, archiveHaskell ? false, trimArchive ? archiveHaskell }: 2 assert !trimArchive || archiveHaskell; 3 let 4 libraryName = "tricu-haskell"; 5 entryModule = "Embedding"; 6 dependencies = p: [ 7 p.aeson p.base16-bytestring p.cryptonite p.memory p.vector 8 p.network p.stm p.temporary p.mtl 9 ]; 10 ghc = haskellPackages.ghcWithPackages dependencies; 11 in pkgs.stdenv.mkDerivation { 12 pname = "${libraryName}${pkgs.lib.optionalString archiveHaskell "-archive"}-embedding"; 13 version = "2026.10.24"; 14 src = source; 15 outputs = [ "out" "linkEvidence" ]; 16 passthru = { 17 compiler = haskellPackages.ghc; 18 haskellLibraries = pkgs.lib.filter (p: p ? isHaskellLibrary && p ? src) 19 (pkgs.lib.closePropagation (dependencies haskellPackages)); 20 }; 21 nativeBuildInputs = [ ghc pkgs.python3 ] 22 ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.patchelf ]; 23 buildPhase = '' 24 runHook preBuild 25 mkdir -p objects 26 # GHC 9.14's executable linker roots the RTS-to-Haskell startup interface; 27 # shared archive linkage needs the same root to resolve the archive cycle. 28 ghc -O2 ${if archiveHaskell then "-static" else "-dynamic"} -shared -fPIC -flink-rts -threaded \ 29 ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux "-optl-Wl,-Map,embedding-link.map"} \ 30 ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux "-optl-Wl,-z,nodelete"} \ 31 ${pkgs.lib.optionalString archiveHaskell "-optl-Wl,-z,text -optl-Wl,-z,defs"} \ 32 ${pkgs.lib.optionalString trimArchive "-optl-Wl,--version-script=ext/haskell/src/core.exports -optl-Wl,--gc-sections"} \ 33 ${pkgs.lib.optionalString (archiveHaskell && pkgs.lib.versionAtLeast haskellPackages.ghc.version "9.14") "-optl-Wl,-u,init_ghc_hs_iface"} \ 34 -XOverloadedStrings -XScopedTypeVariables -XMultiWayIf -XLambdaCase \ 35 -Wall -isrc -iext/haskell/src -outputdir objects \ 36 -optc-Iext/haskell/include \ 37 ext/haskell/src/${entryModule}.hs ext/haskell/src/init.c \ 38 -o lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} 39 runHook postBuild 40 ''; 41 meta = pkgs.lib.optionalAttrs archiveHaskell { platforms = [ "x86_64-linux" ]; }; 42 doCheck = true; 43 checkPhase = '' 44 runHook preCheck 45 ghc -O2 ${if archiveHaskell then "-static" else "-dynamic"} -fPIC -threaded \ 46 -XOverloadedStrings -XScopedTypeVariables -XMultiWayIf -XLambdaCase \ 47 -isrc -iext/haskell/src -outputdir boundary-objects \ 48 ext/haskell/BoundaryTests.hs -o boundary-tests 49 timeout 30s ./boundary-tests 50 $CC -Wall -Wextra -Werror ext/haskell/tests.c -Iext/haskell/include \ 51 -L. -l${libraryName} -Wl,-rpath,$PWD -o c-embedding-tests 52 GHCRTS=--tricu-test-invalid timeout 30s ./c-embedding-tests 53 ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux '' 54 $CC -Wall -Wextra -Werror ext/haskell/reload.c -Iext/haskell/include -ldl -o reload-tests 55 timeout 30s ./reload-tests "$PWD/lib${libraryName}.so" 56 ''} 57 python3 ext/haskell/test_exports.py ./lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} ${pkgs.lib.optionalString trimArchive "public-only"} 58 PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=ext/haskell/python timeout 60s python3 ext/haskell/test_embedding.py \ 59 ./lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} test/fixtures > embedding-report.json 60 cat embedding-report.json 61 PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=ext/haskell/python timeout 30s python3 \ 62 ext/haskell/test_scopes.py ./lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} test/fixtures 63 runHook postCheck 64 ''; 65 installPhase = '' 66 runHook preInstall 67 mkdir -p $out/lib $out/include $out/share/tricu $linkEvidence 68 ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux "cp embedding-link.map $linkEvidence/"} 69 ghc-pkg dump > $linkEvidence/ghc-packages.txt 70 cp lib${libraryName}* $out/lib/ 71 printf '{"ghc_version":"%s","haskell_linkage":"${if archiveHaskell then "archive" else "dynamic"}","public_symbols_only":${if trimArchive then "true" else "false"}}\n' \ 72 "$(ghc --numeric-version)" > $out/share/tricu/build.json 73 cp ext/haskell/include/tricu.h $out/include/ 74 cp ext/haskell/python/tricu.py $out/share/tricu/ 75 cp embedding-report.json $out/share/tricu/ 76 ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux '' 77 python3 ext/haskell/package_runtime.py $out/lib/lib${libraryName}.so 78 ''} 79 runHook postInstall 80 ''; 81 # Verify the installed runtime paths in a fresh foreign process, too. 82 doInstallCheck = true; 83 installCheckPhase = '' 84 ${pkgs.lib.optionalString archiveHaskell '' 85 if ldd $out/lib/lib${libraryName}.so | grep -q libHS; then 86 echo "archive-linked library retained Haskell shared dependencies" >&2 87 exit 1 88 fi 89 ''} 90 $CC -Wall -Wextra -Werror ext/haskell/tests.c -I$out/include \ 91 -L$out/lib -l${libraryName} -Wl,-rpath,$out/lib -o installed-embedding-tests 92 GHCRTS=--tricu-test-invalid timeout 30s ./installed-embedding-tests 93 python3 ext/haskell/test_exports.py $out/lib/lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} ${pkgs.lib.optionalString trimArchive "public-only"} 94 PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=$out/share/tricu timeout 60s python3 \ 95 ext/haskell/test_embedding.py \ 96 $out/lib/lib${libraryName}${pkgs.stdenv.hostPlatform.extensions.sharedLibrary} test/fixtures 97 ''; 98 }