Allow musl cross interpreters to load C dependencies

Keep static Haskell libraries and fully static application outputs while planning ghc914-sh iserv projects with a dynamic musl C loader. Scope the policy to Linux-built musl Cabal v2 interpreters and check that scope in static Linux CI.

Normal and profiled target plans preserve all unit IDs, source records and Haskell ways; only the iserv executable-static flag changes. The shared V2 project skeleton changes auxiliary derivation hashes. A small i686 musl probe reproduces static dlopen failure and verifies the dynamic loader under QEMU; full interpreter TH validation remains for canonical CI.
This commit is contained in:
Moritz Angermann committed 2026-10-17 02:17:58 +09:00
1 parent 465b6dbfac
commit 89ffaea1be
5 files changed
+81 -1

No files matched your search

+9
View File
@@ -33,6 +33,15 @@ Musl projects declare OpenSSL in Cabal's `extra-libraries-static` field for
`direct-sqlcipher` and `simplexmq`. GHC's fully static link path reads that field,
so an ordinary `extra-libraries` entry alone does not supply `libcrypto`. These
source metadata patches run before planning and require Cabal specification 3.8.
Linux-built musl `ghc914-sh` iserv projects use a package-specific
`executable-static: False` policy before Cabal v2 planning. The build-time
interpreter needs musl's dynamic C loader for Template Haskell dependencies;
a fully static musl executable has a `dlopen` stub. Its Haskell library ways
and profiling selection stay unchanged, and the final CLI remains fully static.
The pure scope check runs in the Linux static CI group:
`nix eval --json --file scripts/nix/check-musl-iserv-scope.nix`.
Windows patches Basement's `INVALID_HANDLE_VALUE` expression to `INT_PTR`, so
hsc2hs receives the signed pointer-sized integer expected by the Haskell API.
+38
View File
@@ -0,0 +1,38 @@
# Pure policy regression: nix eval --json --file scripts/nix/check-musl-iserv-scope.nix
let
overlay = import ./musl-iserv-overlay.nix;
lib = {
optionalAttrs = condition: attrs: if condition then attrs else {};
mkIf = condition: attrs: if condition then attrs else {};
mkAfter = value: value;
};
apply = { musl ? true, linux ? true, compiler ? "ghc914-sh", name ? "iserv-proxy", builderVersion ? 2 }:
let
prev = {
inherit lib;
stdenv = { hostPlatform.isMusl = musl; buildPlatform.isLinux = linux; };
haskell-nix.cabalProject' = modules: modules;
};
result = overlay prev prev;
in if result ? haskell-nix then
(builtins.head (result.haskell-nix.cabalProject' [])) {
inherit lib;
pkgs = prev;
config = { inherit name builderVersion; compiler-nix-name = compiler; };
}
else {};
selected = apply {};
in
assert builtins.attrNames selected == [ "cabalProjectLocal" ];
assert builtins.match ".*executable-static: False.*" (builtins.replaceStrings [ "\n" ] [ " " ] selected.cabalProjectLocal) != null;
assert apply { name = "simplex-chat"; } == {};
assert apply { musl = false; } == {};
assert apply { linux = false; } == {};
assert apply { compiler = "ghc963"; } == {};
assert apply { builderVersion = 1; } == {};
{
muslInterpreterCLoadingEnabled = true;
applicationPolicyUnchanged = true;
nonMuslAndDarwinBuildersUnchanged = true;
otherCompilersAndLegacyBuilderUnchanged = true;
}
+27
View File
@@ -0,0 +1,27 @@
final: prev:
prev.lib.optionalAttrs (
prev.stdenv.hostPlatform.isMusl && prev.stdenv.buildPlatform.isLinux
) {
haskell-nix = prev.haskell-nix // {
cabalProject' = projectModule: prev.haskell-nix.cabalProject' (
[ ({ config, lib, pkgs, ... }:
lib.mkIf (
pkgs.stdenv.hostPlatform.isMusl
&& pkgs.stdenv.buildPlatform.isLinux
&& config.compiler-nix-name == "ghc914-sh"
&& config.name == "iserv-proxy"
&& config.builderVersion == 2
) {
# The build-time interpreter loads foreign libraries for TH.
# Fully static musl uses a dlopen stub; retain static Haskell
# libraries while allowing its C loader. Final CLI projects keep
# haskell.nix's default executable-static setting.
cabalProjectLocal = lib.mkAfter ''
package iserv-proxy
executable-static: False
'';
}) ]
++ (if builtins.isList projectModule then projectModule else [ projectModule ])
);
};
}