diff --git a/flake.nix b/flake.nix index 405663a..b6bcc06 100644 --- a/flake.nix +++ b/flake.nix @@ -91,18 +91,19 @@ # PostgreSQL extensions # services.postgres.extensions = extensions: [ extensions.postgis ]; - # GHC 9.10.3 crash fix: Generated.Types imports 119 modules, exceeding - # the ~287 MB interface-file binary-deserialization limit. + # GHC 9.10.3 crash fix: Generated.ActualTypes uses `module M` re-export + # syntax for 61 sub-modules; the resulting ActualTypes.hi exceeds GHC's + # ~274 MB binary-deserialization limit (crash at position 287686318). # # pkgs is built from `import nixpkgs { overlays = devenv.shells.default.overlays; }`. # IHP adds ihp.overlays.default to this list, which sets # pkgs.ghc = haskellPackages.override { overrides = ihpOverrides }. # We extend pkgs.ghc with a mkDerivation override (lib.mkAfter ensures # we run after IHP's overlay, so prev.ghc is already IHP's package set). - # 2-way split (60 entities) still crashes — TypesPart1.hi itself hits 287 MB. - # 4-way split (~30 entities, ~150 MB .hi each) stays safely under the limit. - # When pname == "inter-hub-models", postUnpack replaces the monolithic - # Types.hs → empty stub (not compiled); inter-hub-lib imports TypesPart1-8 directly. + # For inter-hub-models: stub Generated.ActualTypes + Generated.Types to + # empty modules; patch every importer with direct sub-module imports. + # For inter-hub-lib: same for both hubs (originals still intact in its + # sourceRoot — each package is unpacked independently). overlays = lib.mkAfter [ (final: prev: { ghc = prev.ghc.extend (hfinal: hprev: { @@ -110,166 +111,48 @@ let drv = hprev.mkDerivation args; in if (args.pname or "") == "inter-hub-models" then drv.overrideAttrs (old: { - # GHC 9.10.3 crash: Data.Binary.Get.runGet at position 287686318. - # Invariant regardless of flags. Workaround: split the 476-module - # inter-hub-models into two Cabal library components so GHC runs - # two separate --make invocations instead of one giant one. - # - # models-inner (~63 modules): Generated.ActualTypes.* + Enums. - # Pure type definitions; no inter-hub-models deps. - # main library (~413 modules): entity ops + Include instances. - # Depends on models-inner. - # - # Long-term intent: explicit module boundaries reduce build cost, - # isolate changes, and make diagnostics cheaper across the board. + # GHC 9.10.3 crash: `module M` re-export syntax in Generated.ActualTypes + # embeds 61 full sub-interfaces into ActualTypes.hi (~287 MB), exceeding + # GHC's 274 MB binary read limit. Fix: stub both hub files to empty + # modules (tiny .hi), patch every importer to use direct sub-module + # imports (same semantics, no embedded sub-interfaces in .hi). configureFlags = (old.configureFlags or []) ++ [ "--ghc-option=-O0" "--ghc-option=-fomit-interface-pragmas" ]; postUnpack = (old.postUnpack or "") + '' - _cabal=$(ls "$sourceRoot"/*.cabal | head -1) - _pname=$(grep '^name:' "$_cabal" | awk '{print $2}') + _actual="$sourceRoot/build/Generated/ActualTypes.hs" - # Classify exposed-modules into inner vs outer. - # Inner: Generated.ActualTypes.X (capital X) and Generated.Enums - # — these have zero inter-hub-models dependencies. - # Outer: everything else except Generated.Types (empty stub). - _inner=$(awk ' - /^ exposed-modules:/{e=1;next} - e && /^ /{m=$1; - if (m~/^Generated\.ActualTypes\.[A-Z]/||m=="Generated.Enums") - print m; - next} - e{e=0} - ' "$_cabal") - _outer=$(awk ' - /^ exposed-modules:/{e=1;next} - e && /^ /{m=$1; - if (!(m~/^Generated\.ActualTypes\.[A-Z]/) && - m!="Generated.Enums" && m!="Generated.Types") - print m; - next} - e{e=0} - ' "$_cabal") + # Collect direct sub-module imports before stubbing the hub + _act_imp=$(mktemp) + awk '/^import Generated\./{print}' "$_actual" > "$_act_imp" - # Rewrite the cabal file with two library stanzas. - # Hard-coded deps/extensions match IHP default.nix template - # (pinned flake — these won't drift without a flake update). - cat > "$_cabal" < "$_actual" printf '%s\n' 'module Generated.Types () where' \ > "$sourceRoot/build/Generated/Types.hs" + + # Patch every entity file that imports the hub → direct imports + find "$sourceRoot/build" -name "*.hs" | while IFS= read -r _f; do + if grep -qE "^import Generated\.ActualTypes$" "$_f"; then + awk -v imp="$_act_imp" ' + /^import Generated\.ActualTypes$/{ + while ((getline ln < imp) > 0) print ln + close(imp) + next + } + { print }' "$_f" > "$_f.new" && mv "$_f.new" "$_f" + fi + done + rm -f "$_act_imp" ''; }) else if (args.pname or "") == "inter-hub-lib" then drv.overrideAttrs (old: { - # Generated.Types is an empty stub in models — no re-export hub. - # Replace every bare `import Generated.Types` with direct imports - # of all 119 individual entity modules (read from the original - # Generated/Types.hs before it was replaced in models postUnpack — - # each package gets its own unpacked sourceRoot, so Types.hs is - # still intact here). Individual entity .hi files are ~9 MB each. + # Both Generated.Types and Generated.ActualTypes are empty stubs in + # models. Replace every bare import with direct sub-module imports, + # reading the originals from this package's own sourceRoot (each + # package is unpacked independently, so originals are intact here). postUnpack = (old.postUnpack or "") + '' _types="$sourceRoot/build/Generated/Types.hs" _imp=$(mktemp) @@ -286,6 +169,22 @@ CABAL_EOF fi done rm -f "$_imp" + + _actual="$sourceRoot/build/Generated/ActualTypes.hs" + _act_imp=$(mktemp) + awk '/^import Generated\./{print}' "$_actual" > "$_act_imp" + find "$sourceRoot" -name "*.hs" | while IFS= read -r _f; do + if grep -qE "^import Generated\.ActualTypes$" "$_f"; then + awk -v imp="$_act_imp" ' + /^import Generated\.ActualTypes$/{ + while ((getline ln < imp) > 0) print ln + close(imp) + next + } + { print }' "$_f" > "$_f.new" && mv "$_f.new" "$_f" + fi + done + rm -f "$_act_imp" ''; }) else drv;