on iko/ghcjs-patch-master help sign in
Allow packages to specify external static plugins
commitbfeea3e8944d331bf970799be764cfe194ee61c1 authorShea Levy <shea@shealevy.com> dateMon 25 Apr 2022, 10:04 (4 years ago) parentbe667b0
14 files changed+163−15
builder/comp-builder.nix+1 builder/ghc-for-component-wrapper.nix+60−15 builder/haddock-builder.nix+1 builder/shell-for.nix+1 modules/package.nix+17 test/default.nix+1 test/external-static-plugin/cabal.project+1 test/external-static-plugin/default.nix+27 test/external-static-plugin/plugin/CHANGELOG.md+5 test/external-static-plugin/plugin/plugin.cabal+12 test/external-static-plugin/plugin/src/Plugin.hs+16 test/external-static-plugin/prog/CHANGELOG.md+5 test/external-static-plugin/prog/app/Main.hs+4 test/external-static-plugin/prog/prog.cabal+12
builder/comp-builder.nix+1
@@ -236,6 +236,7 @@ let
236236 shellWrappers = ghcForComponent {
237237 componentName = fullName;
238238 inherit configFiles enableDWARF;
239+ inherit (component) plugins;
239240 };
240241
241242 # In order to let shell hooks make package-specific things like Hoogle databases
builder/ghc-for-component-wrapper.nix+60−15
@@ -13,6 +13,7 @@
1313, configFiles # The component's "config" derivation
1414, postInstall ? ""
1515, enableDWARF
16+, plugins
1617}:
1718
1819let
@@ -37,31 +38,70 @@ in runCommand "${componentName}-${ghc.name}-env" {
3738 ''
3839 . ${makeWrapper}/nix-support/setup-hook
3940
40− # Start with a ghc...
41+ ''
42+ # Start with a ghc and remove all of the package directories
43+ + ''
4144 mkdir -p $out/bin
4245 ${lndir}/bin/lndir -silent ${ghc} $out
43− # ... remove all of the package directories
4446 rm -rf ${libDir}/*/
45− # ... but retain the lib/ghc/bin directory. This contains `unlit' and friends.
47+ ''
48+ # ... but retain the lib/ghc/bin directory. This contains `unlit' and friends.
49+ + ''
4650 ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/bin ${libDir}
47− # ... and the ghcjs shim's if they are available ...
51+ ''
52+ # ... and the ghcjs shim's if they are available ...
53+ + ''
4854 if [ -d ${ghc}/lib/${ghcCommand}-${ghc.version}/shims ]; then
4955 ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/shims ${libDir}
5056 fi
51− # ... and node modules ...
57+ ''
58+ # ... and node modules ...
59+ + ''
5260 if [ -d ${ghc}/lib/${ghcCommand}-${ghc.version}/ghcjs-node ]; then
5361 ln -s ${ghc}/lib/${ghcCommand}-${ghc.version}/ghcjs-node ${libDir}
5462 fi
55− # Replace the package database with the one from target package config.
63+ ''
64+ # Replace the package database with the one from target package config.
65+ + ''
5666 ln -s ${configFiles}/${packageCfgDir} $out/${packageCfgDir}
5767
58− # now the tricky bit. For GHCJS (to make plugins work), we need a special
59− # file called ghc_libdir. That points to the build ghc's lib.
60− echo "${ghc.buildGHC or ghc}/lib/${(ghc.buildGHC or ghc).name}" > "${libDir}/ghc_libdir"
68+ ''
69+ # Set the GHC_PLUGINS environment variable according to the plugins for the component.
70+ # GHC will automatically load the relevant symbols from the given libraries and
71+ # initialize them with the given arguments.
72+ #
73+ # GHC_PLUGINS is a `read`able [(FilePath,String,String,[String])], where the
74+ # first component is a path to the shared library, the second is the package ID,
75+ # the third is the module name, and the fourth is the plugin arguments.
76+ + ''
77+ GHC_PLUGINS="["
78+ LIST_PREFIX=""
79+ ${builtins.concatStringsSep "\n" (map (plugin: ''
80+ id=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} id --simple-output)
81+ lib_dir=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} dynamic-library-dirs --simple-output)
82+ lib_base=$(${ghc}/bin/ghc-pkg --package-db ${plugin.library}/package.conf.d field ${plugin.library.package.identifier.name} hs-libraries --simple-output)
83+ lib="$(echo ''${lib_dir}/lib''${lib_base}*)"
84+ GHC_PLUGINS="''${GHC_PLUGINS}''${LIST_PREFIX}(\"''${lib}\",\"''${id}\",\"${plugin.moduleName}\",["
85+ LIST_PREFIX=""
86+ ${builtins.concatStringsSep "\n" (map (arg: ''
87+ GHC_PLUGINS="''${GHC_PLUGINS}''${LIST_PREFIX}\"${arg}\""
88+ LIST_PREFIX=","
89+ '') plugin.args)}
90+ GHC_PLUGINS="''${GHC_PLUGINS}])"
91+ LIST_PREFIX=","
92+ '') plugins)}
93+ GHC_PLUGINS="''${GHC_PLUGINS}]"
6194
62− # Wrap compiler executables with correct env variables.
63− # The NIX_ variables are used by the patched Paths_ghc module.
95+ ''
96+ # now the tricky bit. For GHCJS (to make plugins work), we need a special
97+ # file called ghc_libdir. That points to the build ghc's lib.
98+ + ''
99+ echo "${ghc.buildGHC or ghc}/lib/${(ghc.buildGHC or ghc).name}" > "${libDir}/ghc_libdir"
64100
101+ ''
102+ # Wrap compiler executables with correct env variables.
103+ # The NIX_ variables are used by the patched Paths_ghc module.
104+ + ''
65105 for prg in ${ghcCommand} ${ghcCommand}i ${ghcCommand}-${ghc.version} ${ghcCommand}i-${ghc.version}; do
66106 if [[ -x "${ghc}/bin/$prg" ]]; then
67107 rm -f $out/bin/$prg
@@ -70,6 +110,7 @@ in runCommand "${componentName}-${ghc.name}-env" {
70110 --set "NIX_${ghcCommandCaps}" "$out/bin/${ghcCommand}" \
71111 --set "NIX_${ghcCommandCaps}PKG" "$out/bin/${ghcCommand}-pkg" \
72112 --set "NIX_${ghcCommandCaps}_DOCDIR" "${docDir}" \
113+ --set "GHC_PLUGINS" "$GHC_PLUGINS" \
73114 --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}"
74115 fi
75116 done
@@ -82,11 +123,14 @@ in runCommand "${componentName}-${ghc.name}-env" {
82123 --set "NIX_${ghcCommandCaps}" "$out/bin/${ghcCommand}" \
83124 --set "NIX_${ghcCommandCaps}PKG" "$out/bin/${ghcCommand}-pkg" \
84125 --set "NIX_${ghcCommandCaps}_DOCDIR" "${docDir}" \
126+ --set "GHC_PLUGINS" "$GHC_PLUGINS" \
85127 --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}"
86128 fi
87129 done
88130
89− # Wrap haddock, if the base GHC provides it.
131+ ''
132+ # Wrap haddock, if the base GHC provides it.
133+ + ''
90134 if [[ -x "${haddock}/bin/haddock" ]]; then
91135 rm -f $out/bin/haddock
92136 makeWrapper ${haddock}/bin/haddock $out/bin/haddock \
@@ -94,9 +138,10 @@ in runCommand "${componentName}-${ghc.name}-env" {
94138 --set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}"
95139 fi
96140
97− # Point ghc-pkg to the package database of the component using the
98− # --global-package-db flag.
99−
141+ ''
142+ # Point ghc-pkg to the package database of the component using the
143+ # --global-package-db flag.
144+ + ''
100145 for prg in ${ghcCommand}-pkg ${ghcCommand}-pkg-${ghc.version}; do
101146 if [[ -x "${ghc}/bin/$prg" ]]; then
102147 rm -f $out/bin/$prg
builder/haddock-builder.nix+1
@@ -56,6 +56,7 @@ let
5656 componentName = fullName;
5757 configFiles = docsConfigFiles;
5858 inherit (componentDrv) enableDWARF;
59+ inherit (component) plugins;
5960 };
6061
6162 drv = stdenv.mkDerivation (commonAttrs // {
builder/shell-for.nix+1
@@ -113,6 +113,7 @@ let
113113 ln -s ${hoogleIndex}/bin/hoogle $out/bin
114114 '';
115115 inherit enableDWARF;
116+ plugins = [];
116117 };
117118
118119 hoogleIndex = let
modules/package.nix+17
@@ -31,6 +31,23 @@ let
3131 type = bool;
3232 default = true;
3333 };
34+ plugins = mkOption {
35+ type = listOf (submodule {
36+ options = {
37+ library = mkOption {
38+ type = unspecified;
39+ };
40+ moduleName = mkOption {
41+ type = str;
42+ };
43+ args = mkOption {
44+ type = listOf str;
45+ default = [];
46+ };
47+ };
48+ });
49+ default = [];
50+ };
3451 depends = mkOption {
3552 type = listOfFilteringNulls unspecified;
3653 default = [];
test/default.nix+1
@@ -203,6 +203,7 @@ let
203203 githash = haskell-nix.callPackage ./githash { inherit compiler-nix-name; testSrc = testSrcWithGitDir; };
204204 c-ffi = callTest ./c-ffi { inherit util compiler-nix-name; };
205205 th-dlls = callTest ./th-dlls { inherit util compiler-nix-name; };
206+ external-static-plugin = callTest ./external-static-plugin { inherit compiler-nix-name; };
206207
207208 unit = unitTests;
208209 };
test/external-static-plugin/cabal.projectnew file+1
@@ -0,0 +1 @@
1+packages: ./**/*.cabal
test/external-static-plugin/default.nixnew file+27
@@ -0,0 +1,27 @@
1+{ cabalProject', testSrc, compiler-nix-name, recurseIntoAttrs, haskellLib }: let
2+ project = cabalProject' {
3+ src = testSrc "external-static-plugin";
4+ inherit compiler-nix-name;
5+ modules = [ {
6+ packages.prog.components.exes.prog.plugins = [ {
7+ inherit (project.hsPkgs.plugin.components) library;
8+ moduleName = "Plugin";
9+ args = [ "f1" "f2" ];
10+ } ];
11+ packages.prog.postInstall = ''
12+ test -f f1
13+ test -f f2
14+ '';
15+ } ];
16+ };
17+in recurseIntoAttrs {
18+ ifdInputs = {
19+ inherit (project) plan-nix;
20+ };
21+
22+ meta.disabled = !(builtins.elem compiler-nix-name [
23+ "ghc810420210212"
24+ ]) || haskellLib.isCrossHost;
25+
26+ build = project.hsPkgs.prog.components.exes.prog;
27+}
test/external-static-plugin/plugin/CHANGELOG.mdnew file+5
@@ -0,0 +1,5 @@
1+# Revision history for plugin
2+
3+## 0.1.0.0 -- YYYY-mm-dd
4+
5+* First version. Released on an unsuspecting world.
test/external-static-plugin/plugin/plugin.cabalnew file+12
@@ -0,0 +1,12 @@
1+cabal-version: 2.4
2+name: plugin
3+version: 0.1.0.0
4+author: Shea Levy
5+maintainer: shea@shealevy.com
6+extra-source-files: CHANGELOG.md
7+
8+library
9+ exposed-modules: Plugin
10+ build-depends: base, ghc
11+ hs-source-dirs: src
12+ default-language: Haskell2010
test/external-static-plugin/plugin/src/Plugin.hsnew file+16
@@ -0,0 +1,16 @@
1+module Plugin (plugin) where
2+
3+import GhcPlugins
4+import MonadUtils
5+import System.IO
6+import Control.Monad
7+
8+plugin :: Plugin
9+plugin = defaultPlugin
10+ { installCoreToDos = install
11+ }
12+
13+install :: CorePlugin
14+install files passes = do
15+ liftIO . forM files $ flip writeFile ""
16+ pure passes
test/external-static-plugin/prog/CHANGELOG.mdnew file+5
@@ -0,0 +1,5 @@
1+# Revision history for prog
2+
3+## 0.1.0.0 -- YYYY-mm-dd
4+
5+* First version. Released on an unsuspecting world.
test/external-static-plugin/prog/app/Main.hsnew file+4
@@ -0,0 +1,4 @@
1+module Main where
2+
3+main :: IO ()
4+main = putStrLn "Hello, Haskell!"
test/external-static-plugin/prog/prog.cabalnew file+12
@@ -0,0 +1,12 @@
1+cabal-version: 2.4
2+name: prog
3+version: 0.1.0.0
4+author: Shea Levy
5+maintainer: shea@shealevy.com
6+extra-source-files: CHANGELOG.md
7+
8+executable prog
9+ main-is: Main.hs
10+ build-depends: base
11+ hs-source-dirs: app
12+ default-language: Haskell2010