Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
636 changes: 29 additions & 607 deletions .github/workflows/nix-ci.yml

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,12 @@ $(STAGE1_STAMP): $(CONFIGURE_SCRIPTS) $(CONFIGURED_FILES) cabal.project.stage1 c
ifeq ($(DYNAMIC),1)
$(SED) -i -e 's/"RTS ways","/"RTS ways","dyn debug_dyn thr_dyn thr_debug_dyn /' $(STORE_DIR)/host/$(HOST_PLATFORM)/lib/settings
endif
@# Inject the four per-target dials into the native settings file
@# too — same keys as the stage3 cross targets (see the lengthy
@# comment above $(TARGET_DIR)/lib/settings injection). The native
@# target's dynamic state tracks our DYNAMIC=0/1 build flag; prof
@# is always NO because stage2 isn't built -prof.
$(SED) -i -e 's/\]$$/,("target is dynamic","$(if $(filter 1,$(DYNAMIC)),YES,NO)"),("target ships dynamic libraries","$(if $(filter 1,$(DYNAMIC)),YES,NO)"),("target is profiled","NO"),("target ships profiling libraries","NO")]/' $(STORE_DIR)/host/$(HOST_PLATFORM)/lib/settings

$(call LOG,Creating packagedb in $(STORE_DIR)/host/$(HOST_PLATFORM)/lib/package.conf.d)
@rm -rf $(STORE_DIR)/host/$(HOST_PLATFORM)/lib/package.conf.d
Expand Down Expand Up @@ -919,6 +925,17 @@ STAGE3_javascript-unknown-ghcjs_NM = emnm
STAGE3_javascript-unknown-ghcjs_RANLIB = emranlib
STAGE3_javascript-unknown-ghcjs_STRIP = emstrip
STAGE3_javascript-unknown-ghcjs_GHC_TOOLCHAIN_ARGS = $(GHC_TOOLCHAIN_ARGS) --disable-tables-next-to-code
# JS target overrides: NO across the board.
# * dyn: iserv runs vanilla (no dlopen in the JS runtime), lib tree
# ships no .dyn_hi (Path C doesn't apply to JS — see PR #187).
# * prof: stage2 isn't built -prof, no .p_hi shipped.
# All four dials NO → `ghc --info` for the JS target reports
# `GHC Dynamic: NO`, `GHC Profiled: NO`, `Support dynamic-too: NO`.
# End-user cabal-install correctly skips library-{dynamic,profiling}.
STAGE3_javascript-unknown-ghcjs_TARGET_IS_DYNAMIC = NO
STAGE3_javascript-unknown-ghcjs_TARGET_SHIPS_DYN_LIBS = NO
STAGE3_javascript-unknown-ghcjs_TARGET_IS_PROFILED = NO
STAGE3_javascript-unknown-ghcjs_TARGET_SHIPS_PROF_LIBS = NO

STAGE3_wasm32-unknown-wasi_CC = wasm32-unknown-wasi-clang
STAGE3_wasm32-unknown-wasi_CC_OPTS = -fno-strict-aliasing -Wno-error=int-conversion -Oz -msimd128 -mnontrapping-fptoint -msign-ext -mbulk-memory -mmutable-globals -mmultivalue -mreference-types
Expand Down Expand Up @@ -1007,6 +1024,42 @@ ifeq ($(DYNAMIC),1)
$(SED) -i -e 's/"RTS ways","/"RTS ways","dyn /' $$(TARGET_DIR)/lib/settings
endif

@# Inject the per-target dials that drive `ghc --info`'s
@# `GHC Dynamic` and `GHC Profiled` values (cabal-install reads
@# these to decide whether to enable library-dynamic /
@# library-profiling by default):
@#
@# target is dynamic — GHC capable of -dynamic /
@# -dynamic-too output
@# target ships dynamic libraries — lib tree has .dyn_hi / .so
@# target is profiled — GHC capable of -prof output
@# target ships profiling libraries — lib tree has .p_hi / .p_a
@#
@# Reported pairs:
@# GHC Dynamic = (target is dynamic) && (target ships dynamic libraries)
@# GHC Profiled = (target is profiled) && (target ships profiling libraries)
@#
@# Per-target settings file completely controls these — the
@# shared stage2 GHC binary's RTS-baked-in dynamic/prof-ness is
@# no longer consulted. Two dials per way (is / ships) so a
@# target can be capable but not currently ship artifacts (or
@# vice versa) — keeps the axes orthogonal for slimming
@# experiments and matches what cabal really wants to know.
@#
@# Defaults for our bindists: dynamic dials YES (most targets
@# ship dyn libs), prof dials NO (stage2 isn't built -prof so
@# no target currently ships prof libs).
@# Override via STAGE3_<triple>_TARGET_{IS_DYNAMIC,SHIPS_DYN_LIBS,
@# IS_PROFILED,SHIPS_PROF_LIBS}.
@#
@# Note: `$$$$` (four dollars) collapses through two layers of
@# Make expansion (define-template + recipe-time) to a literal `$`
@# at shell time, which is what sed needs as the end-of-line anchor.
@# `$$` would collapse to `$` after template expansion, then Make
@# would interpret the lone `$/` in the recipe as a variable lookup
@# and drop the anchor entirely (verified: PR #187 first attempt).
$(SED) -i -e 's/\]$$$$/,("target is dynamic","$(if $(STAGE3_$(1)_TARGET_IS_DYNAMIC),$(STAGE3_$(1)_TARGET_IS_DYNAMIC),YES)"),("target ships dynamic libraries","$(if $(STAGE3_$(1)_TARGET_SHIPS_DYN_LIBS),$(STAGE3_$(1)_TARGET_SHIPS_DYN_LIBS),YES)"),("target is profiled","$(if $(STAGE3_$(1)_TARGET_IS_PROFILED),$(STAGE3_$(1)_TARGET_IS_PROFILED),NO)"),("target ships profiling libraries","$(if $(STAGE3_$(1)_TARGET_SHIPS_PROF_LIBS),$(STAGE3_$(1)_TARGET_SHIPS_PROF_LIBS),NO)")]/' $$(TARGET_DIR)/lib/settings

$$(DIST_DIR)/bin/$(1)-ghc --info

@rm -rf $$(TARGET_DIR)/lib/package.conf.d
Expand Down
41 changes: 35 additions & 6 deletions cabal.project.stage3.settings.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- cabal.project.stage3.settings - generated by configure from .in template
-- Do not edit this file directly; edit cabal.project.stage3.settings.in instead.
--
-- Multi-target stage3: applies dynamic library settings ONLY to wasm32
-- via cabal's `if arch(wasm32)` conditional, which cabal evaluates against
-- Multi-target stage3: applies dynamic library settings per-target
-- via cabal's `if arch(...)` conditional, which cabal evaluates against
-- the --with-compiler's target arch per-invocation.
--
-- * stage3-wasm32-unknown-wasi (--with-compiler=wasm32-...-ghc):
Expand All @@ -11,10 +11,21 @@
-- (miso, jsaddle, aeson, …)
--
-- * stage3-javascript-unknown-ghcjs (--with-compiler=javascript-...-ghc):
-- arch=javascript → conditional FALSE → settings do NOT apply
-- → no shared:True flowing into emcc/wasm-ld (which can't produce
-- .so for the JS backend; the alternative breaks with
-- `wasm-ld: error: unknown argument: -h`)
-- arch=javascript → conditional TRUE (ghc-options branch)
-- → ghc-options: -dynamic-too applied per-package
-- → produces .dyn_hi files without invoking cabal's library-dynamic
-- .so link step (which fails for JS with
-- `wasm-ld: error: unknown argument: -h`).
-- Path C symmetric: the shared stage2 GHC binary reports
-- GHC Dynamic=YES (it is) which makes cabal-install enable
-- library-dynamic by default for the JS target too. Without
-- .dyn_hi files cabal then fails reading e.g. Prelude.dyn_hi
-- when compiling miso. We don't want shared:True here (which
-- would also invoke wasm-ld for an .so we don't need), so
-- ghc-options is the surgical alternative: ask GHC to emit
-- .dyn_o + .dyn_hi alongside .o + .hi during compile, and let
-- cabal skip the library-dynamic link step. .so byproducts
-- are inert for JS (no dlopen).
--
-- * Native build-side packages (compiled with --with-build-compiler=ghc,
-- i.e. happy-lib, alex, deriveConstants, Setup.hs scripts):
Expand All @@ -33,5 +44,23 @@ if arch(wasm32)
shared: True
executable-dynamic: True

-- NOTE: an earlier draft of #66 (PR #187) attempted Path C for the
-- JS target via:
-- if arch(javascript)
-- package *
-- ghc-options: -dynamic-too
-- but cabal-install applies `ghc-options` differently from `shared`
-- in the dual-compiler split: `shared` is properly per-target-arch
-- (only host packages see it; native build-side packages like alex,
-- happy-lib do NOT), but `ghc-options` leaks to build-side compiles
-- regardless of the arch conditional. The native stage2 is built
-- DYNAMIC=0 (no .dyn_hi for the host arch), so alex's first .hs
-- module failed with
-- Prelude.dyn_hi: does not exist (No such file or directory)
-- when compiled by the build compiler with -dynamic-too.
-- Path C for JS therefore needs deeper cabal work (or a Makefile-
-- side .dyn_hi copy after the fact); the GHC Dynamic settings dial
-- in the sibling commit (#67) is the proper long-term answer.

constraints:
rts +dynamic
41 changes: 35 additions & 6 deletions compiler/GHC/Driver/Session.hs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ module GHC.Driver.Session (
sGhcWithInterpreter,
sLibFFI,
sTargetRTSLinkerOnlySupportsSharedLibs,
sTargetIsDynamic,
sTargetShipsDynLibs,
sTargetIsProfiled,
sTargetShipsProfLibs,
GhcNameVersion(..),
FileSettings(..),
PlatformMisc(..),
Expand Down Expand Up @@ -3548,8 +3552,16 @@ compilerInfo dflags
("Have native code generator", showBool $ platformNcgSupported platform),
("target has RTS linker", showBool $ platformHasRTSLinker platform),
("Target default backend", show $ platformDefaultBackend platform),
-- Whether or not we support @-dynamic-too@
("Support dynamic-too", showBool $ not isWindows),
-- Whether or not we support @-dynamic-too@ for this target.
-- Historically `not isWindows` (Windows tooling couldn't do
-- it). Now also gated on the per-target `sTargetIsDynamic`
-- dial — if the target isn't dynamic-capable, -dynamic-too
-- is meaningless. Keep the Windows guard as defence in depth
-- for pre-this-patch bindists on Windows that lack the key
-- and so default sTargetIsDynamic=True (the AND would
-- otherwise regress them).
("Support dynamic-too", showBool $ not isWindows
&& sTargetIsDynamic (settings dflags)),
-- Whether or not we support the @-j@ flag with @--make@.
("Support parallel --make", "YES"),
-- Whether or not we support "Foo from foo-0.1-XXX:Foo" syntax in
Expand All @@ -3569,10 +3581,27 @@ compilerInfo dflags
("Uses package keys", "YES"),
-- Whether or not we support the @-this-unit-id@ flag
("Uses unit IDs", "YES"),
-- Whether or not GHC was compiled using -dynamic
("GHC Dynamic", showBool hostIsDynamic),
-- Whether or not GHC was compiled using -prof
("GHC Profiled", showBool hostIsProfiled),
-- Reported as YES iff *both* per-target settings dials say so:
-- `target is dynamic` — the GHC for this target
-- can produce dynamic output
-- `target ships dynamic libraries` — the lib tree actually has
-- .dyn_hi / .so artifacts
-- cabal-install reads this to decide whether to enable
-- @library-dynamic@ by default. The target's per-target settings
-- file completely controls this value — no host-RTS dependency,
-- so on a multi-target bindist with one shared stage2 GHC binary
-- different targets can correctly disagree. Both keys default to
-- True if absent (matches pre-this-change behaviour).
("GHC Dynamic", showBool (sTargetIsDynamic (settings dflags)
&& sTargetShipsDynLibs (settings dflags))),
-- Profiling-way analogue of `GHC Dynamic`. Per-target dials
-- via `target is profiled` + `target ships profiling libraries`
-- settings keys. Drops the historical `hostIsProfiled` RTS-
-- baked-in for the same reason the dyn pair did: on a multi-
-- target bindist the shared stage2 GHC binary's prof-ness is
-- fixed but the lib trees can disagree per target.
("GHC Profiled", showBool (sTargetIsProfiled (settings dflags)
&& sTargetShipsProfLibs (settings dflags))),
("Debug on", showBool debugIsOn),
("LibDir", topDir dflags),
-- This is always an absolute path, unlike "Relative Global Package DB" which is
Expand Down
27 changes: 27 additions & 0 deletions compiler/GHC/Platform.hs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,33 @@ data PlatformMisc = PlatformMisc
, platformMisc_libFFI :: Bool
, platformMisc_llvmTarget :: String
, platformMisc_targetRTSLinkerOnlySupportsSharedLibs :: Bool
-- | Is the GHC for this target capable of producing dynamic
-- output (i.e. can it honour @-dynamic@ / @-dynamic-too@)?
-- Per-target settings key @"target is dynamic"@ in
-- @lib/targets/\<triple\>/lib/settings@. On a multi-target bindist
-- the shared stage2 GHC binary's RTS-baked-in dynamic-ness is
-- not a per-target proxy — different targets in one binary may
-- need to disagree (e.g. a JS target whose iserv runs vanilla
-- and whose lib tree has no dyn artifacts). Combined with
-- 'platformMisc_targetShipsDynLibs' to drive @ghc --info@'s
-- @GHC Dynamic@ value, which cabal-install reads.
, platformMisc_targetIsDynamic :: Bool
-- | Does the target's installed library tree ship @.dyn_hi@ /
-- @.so@ files? Per-target settings key
-- @"target ships dynamic libraries"@. Set independently of
-- 'platformMisc_targetIsDynamic' so a target can be dynamic-
-- capable but not currently ship dyn artifacts (or vice versa).
, platformMisc_targetShipsDynLibs :: Bool
-- | Profiling-way analogue of 'platformMisc_targetIsDynamic'.
-- Per-target settings key @"target is profiled"@. Drives
-- @ghc --info@'s @GHC Profiled@ — cabal-install reads that to
-- decide whether to enable @library-profiling@.
, platformMisc_targetIsProfiled :: Bool
-- | Profiling-way analogue of 'platformMisc_targetShipsDynLibs'.
-- Per-target settings key @"target ships profiling libraries"@.
-- Combined with 'platformMisc_targetIsProfiled' for the
-- @GHC Profiled@ report.
, platformMisc_targetShipsProfLibs :: Bool
}

platformSOName :: Platform -> FilePath -> FilePath
Expand Down
27 changes: 27 additions & 0 deletions compiler/GHC/Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ module GHC.Settings
, sGhcWithInterpreter
, sLibFFI
, sTargetRTSLinkerOnlySupportsSharedLibs
, sTargetIsDynamic
, sTargetShipsDynLibs
, sTargetIsProfiled
, sTargetShipsProfLibs
) where

import GHC.Prelude
Expand Down Expand Up @@ -314,3 +318,26 @@ sLibFFI = platformMisc_libFFI . sPlatformMisc

sTargetRTSLinkerOnlySupportsSharedLibs :: Settings -> Bool
sTargetRTSLinkerOnlySupportsSharedLibs = platformMisc_targetRTSLinkerOnlySupportsSharedLibs . sPlatformMisc

-- | Is the GHC for this target capable of producing dynamic output?
-- Read from the per-target settings file key @"target is dynamic"@.
-- Combined with 'sTargetShipsDynLibs' to drive @ghc --info@'s
-- @GHC Dynamic@ value — the target's settings file completely
-- controls that, no host-RTS dependency.
sTargetIsDynamic :: Settings -> Bool
sTargetIsDynamic = platformMisc_targetIsDynamic . sPlatformMisc

-- | Does this target's installed library tree ship .dyn_hi / .so files?
-- Per-target settings key @"target ships dynamic libraries"@.
sTargetShipsDynLibs :: Settings -> Bool
sTargetShipsDynLibs = platformMisc_targetShipsDynLibs . sPlatformMisc

-- | Profiling-way analogue of 'sTargetIsDynamic'. Per-target settings
-- key @"target is profiled"@.
sTargetIsProfiled :: Settings -> Bool
sTargetIsProfiled = platformMisc_targetIsProfiled . sPlatformMisc

-- | Profiling-way analogue of 'sTargetShipsDynLibs'. Per-target settings
-- key @"target ships profiling libraries"@.
sTargetShipsProfLibs :: Settings -> Bool
sTargetShipsProfLibs = platformMisc_targetShipsProfLibs . sPlatformMisc
32 changes: 32 additions & 0 deletions compiler/GHC/Settings/IO.hs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,34 @@ initSettings top_dir = do
ghcWithInterpreter <- getBooleanSetting "Use interpreter"
useLibFFI <- getBooleanSetting "Use LibFFI"

-- Per-target dial #1: is the GHC for THIS target capable of
-- producing dynamic output (i.e. honouring -dynamic /
-- -dynamic-too)? On a multi-target bindist with one shared stage2
-- GHC binary, this can't be derived from the binary's compile-
-- time `hostIsDynamic`. Default True for backward compatibility
-- with older bindist settings files that predate the key.
targetIsDynamic <- either (const $ pure True) pure $
getRawBooleanSetting settingsFile mySettings "target is dynamic"

-- Per-target dial #2: does this target's installed lib tree
-- actually ship .dyn_hi / .so files? Independent of
-- `target is dynamic` so a dynamic-capable target can still
-- truthfully say it doesn't ship artifacts (e.g. a slimmed
-- bindist). cabal-install combines both via GHC Dynamic to
-- decide whether to enable library-dynamic by default.
targetShipsDynLibs <- either (const $ pure True) pure $
getRawBooleanSetting settingsFile mySettings "target ships dynamic libraries"

-- Profiling-way analogues of the two dyn dials above. Drive
-- `GHC Profiled` the same way (sTargetIsProfiled && sTargetShipsProfLibs).
-- Defaults to True for backward compatibility with bindists that
-- predate the keys — matches the historical hostIsProfiled
-- behaviour when GHC was prof-built.
targetIsProfiled <- either (const $ pure True) pure $
getRawBooleanSetting settingsFile mySettings "target is profiled"
targetShipsProfLibs <- either (const $ pure True) pure $
getRawBooleanSetting settingsFile mySettings "target ships profiling libraries"

baseUnitId <- getSetting_raw "base unit-id"

return $ Settings
Expand Down Expand Up @@ -267,6 +295,10 @@ initSettings top_dir = do
, platformMisc_libFFI = useLibFFI
, platformMisc_llvmTarget = llvmTarget
, platformMisc_targetRTSLinkerOnlySupportsSharedLibs = targetRTSLinkerOnlySupportsSharedLibs
, platformMisc_targetIsDynamic = targetIsDynamic
, platformMisc_targetShipsDynLibs = targetShipsDynLibs
, platformMisc_targetIsProfiled = targetIsProfiled
, platformMisc_targetShipsProfLibs = targetShipsProfLibs
}

, sRawSettings = settingsList
Expand Down
Loading