Skip to content

Deprecate -dynamic-too: remove duplicate object file generation#122

Open
angerman wants to merge 8 commits intostable-ghc-9.14from
feature/remove-dyn-too
Open

Deprecate -dynamic-too: remove duplicate object file generation#122
angerman wants to merge 8 commits intostable-ghc-9.14from
feature/remove-dyn-too

Conversation

@angerman
Copy link

@angerman angerman commented Dec 3, 2025

Summary

This PR deprecates the -dynamic-too flag and removes the infrastructure that generated separate .dyn_o and .dyn_hi files alongside regular .o and .hi files.

  • The -dynamic-too flag now emits a deprecation warning and is a no-op
  • GHC no longer produces .dyn_o or .dyn_hi files
  • Only standard .o and .hi files are generated
  • ModLocation API preserved for compatibility (dyn paths return same as non-dyn paths)

Changes

File Changes
GHC/Driver/Session.hs Flag now deprecated with warning
GHC/Driver/Downsweep.hs Removed dynamic_too_enable auto-enablement
GHC/Driver/Pipeline.hs Removed backend double-run
GHC/Driver/DynFlags.hs Removed DynamicTooState, dynamicNow, setDynamicNow
GHC/Driver/Main.hs Simplified interface writing (single .hi)
GHC/Driver/Pipeline/Execute.hs Removed dynamicNow path checks
GHC/Iface/Load.hs Removed load_dynamic_too* functions
GHC/Iface/Recomp.hs Removed check_dyn_hi logic
GHC/Tc/Utils/Monad.hs Removed withoutDynamicNow
GHC/Unit/Finder.hs mkDynObjPath = mkObjPath, mkDynHiPath = mkHiPath
GHC/Linker/Loader.hs dyn_obj_file = obj_file
GHC/Linker/Deps.hs Updated comments

Breaking Changes

  • Build systems that rely on .dyn_o files will need to be updated to use regular .o files
  • The -dynamic-too flag no longer has any effect (deprecation warning emitted)

Test plan

  • Verify deprecation warning is emitted when using -dynamic-too
  • Verify only .o and .hi files are produced (no .dyn_o or .dyn_hi)
  • Run testsuite to check for regressions
  • Test TemplateHaskell compilation still works without auto-enablement

@hasufell
Copy link
Member

I had to add this patch:

--- a/compiler/GHC/Driver/DynFlags.hs
+++ b/compiler/GHC/Driver/DynFlags.hs
@@ -997,6 +997,7 @@ dopt_unset dfs f = dfs{ dumpFlags = EnumSet.delete f (dumpFlags dfs) }

 -- | Test whether a 'GeneralFlag' is set
 gopt :: GeneralFlag -> DynFlags -> Bool
+gopt Opt_ExternalDynamicRefs _ = True
 gopt f dflags = f `EnumSet.member` generalFlags dflags

 -- | Set a 'GeneralFlag'

otherwise I'd run into errors such as:

/usr/lib64/gcc/x86_64-suse-linux/15/../../../../x86_64-suse-linux/bin/ld: /home/hasufell/git/ghc/_build/stage2/build/host/x86_64-linux/ghc-9.14/ghc-internal-9.1400.0/build/GHC/Internal/Event/TimerManager.o: warning: relocation against `stg_INTLIKE_closure' in read-only section `.text'
/usr/lib64/gcc/x86_64-suse-linux/15/../../../../x86_64-suse-linux/bin/ld: /home/hasufell/git/ghc/_build/stage2/build/host/x86_64-linux/ghc-9.14/ghc-internal-9.1400.0/build/GHC/Internal/AllocationLimitHandler.o: relocation R_X86_64_PC32 against undefined symbol `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC
/usr/lib64/gcc/x86_64-suse-linux/15/../../../../x86_64-suse-linux/bin/ld: final link failed: bad value

But that would open issues with cabal not knowing which interface/object files to pick and invoking GHC incorrectly. After fixing that... I realized it now invokes the boot compiler (non-stable-haskell) wrongly xD

At that point, I wasn't sure if I want to continue this route.

@angerman angerman force-pushed the feature/remove-dyn-too branch 2 times, most recently from 0bb7adf to 6a4d55f Compare February 11, 2026 04:21
This commit deprecates the -dynamic-too flag and removes the infrastructure
that generated separate .dyn_o and .dyn_hi files alongside regular .o and .hi
files.

Key changes:
- Flag -dynamic-too now emits a deprecation warning and is a no-op
- Remove auto-enablement of -dynamic-too for TemplateHaskell
- Remove pipeline double-run that generated both static and dynamic objects
- Remove DynamicTooState type and dynamicNow field from DynFlags
- Remove dynamicTooState and setDynamicNow functions
- Unify dyn/non-dyn file paths (mkDynObjPath = mkObjPath, etc.)
- Remove dynamic interface loading and checking
- Update linker to use .o files for dynamic loading

The ModLocation fields (ml_dyn_obj_file, ml_dyn_hi_file) are kept for API
compatibility but now return the same paths as their non-dyn counterparts.

Build systems that rely on .dyn_o files will need to be updated to use
regular .o files instead.
@angerman angerman force-pushed the feature/remove-dyn-too branch from 6a4d55f to 2f7b22e Compare February 14, 2026 04:12
Since -dynamic-too is now a deprecated no-op, reporting YES caused Cabal
to use single-pass mode expecting both .o and .dyn_o output. Only .o was
produced, breaking shared library linking in DYNAMIC=1 builds.

Reporting NO makes Cabal fall back to two-pass compilation (vanilla +
dynamic), which correctly produces both .o and .dyn_o files. The double
compilation is slightly wasteful since both passes yield identical
dynamic-capable objects, but it is correct and unblocks all DYNAMIC=1 CI
jobs.
Since -dynamic-too is deprecated and all .o files are now
dynamic-capable, WayDyn no longer implies a separate object file
suffix (.dyn_o). The checkNonStdWay function previously returned
Just "dyn_o" when the host GHC was dynamic but the target ways
didn't include WayDyn, causing the linker to look for non-existent
.dyn_o files when loading TH/plugin/GHCi code.

Fix by comparing ways modulo WayDyn: since .o files are always
dynamic-capable, only non-dynamic ways (like WayProf) affect the
object file suffix. This resolves ~45 TH/plugin test failures.
Since -dynamic-too is deprecated and a no-op (all .o files are now
dynamic-capable), skip all tests that specifically exercise -dynamic-too
functionality:

- dynamicToo001, dynamicToo001boot, dynamicToo001MakeA/B, dynamicToo002,
  dynamicToo003, dynamicToo004, dynamicToo005, dynamicToo006,
  dynamicTooMake, dynamicTooRecomp, dynamicTooOnlyInterface
- T20348A-E (test -dynamic-too output file options)
- T25837 (tests dynamic interface mismatch detection)
- recomp-boot-dyn-too (tests -dynamic-too with boot files)
- implicit-dyn-too (tests missing .dyn_o recompilation)

Updated tests:
- T20348: removed .dyn_o/.dyn_hi checks from Makefile and stdout
- T20436: updated expected stderr to new deprecation warning
- T23944: removed -dynamic-too from compilation flags
- T12983: replaced -dynamic-too with -dynamic in build.sh
- recompPluginPackage: replaced -dynamic-too with -dynamic in q.cabal
…bjects

Since all .o files are now dynamic-capable and -dynamic-too is a no-op,
compilation progress messages no longer show .dyn_o output files. Update
golden files and test configurations accordingly:

- Remove .dyn_o from progress messages in golden files (T20696, fat015,
  SI07, T22840, multipleHomeUnits_single5)
- Replace -dynamic-too with -dynamic in test configs (T22840, T19264,
  T21035, T14931)
- Update T21035 Makefile to use .o files directly for shared lib creation
- Update T20696 wasm32-specific stderr to match new output
With dynamic-too deprecated and all .hi/.o files unified, the Finder's
package_hisuf computation must ignore WayDyn when computing the build
tag. Previously, when WayDyn was in finder_ways, the tag would be "dyn"
causing lookups for ".dyn_hi" files in package directories - but
packages now install unified ".hi" files only.

This is the same pattern as the checkNonStdWay fix in Linker/Deps.hs
(commit 8a64142): use removeWay WayDyn so only non-dynamic ways (e.g.
profiling) contribute to the suffix.

Fixes T14304 and T16219 (backpack signature interface lookup failures
under -dynamic builds).
T21035: Remove -dynamic from HsDep.hs compilation. With unified object
files, all .o files are dynamic-capable, so plain compilation produces
a .hi with empty profile tag compatible with non-dynamic consumers.
The old -dynamic flag wrote profile tag "dyn" into the .hi, causing
a mismatch when M.hs compiled without -dynamic tried to read it.

T20436: Remove leading newline from golden stderr. The deprecation
warning is now emitted during flag parsing (via deprecate) rather than
after flag processing (via makeDynFlagsConsistent), so no leading
blank line is produced.

T22840: Update golden file to expect "interpreted" for T22840A. With
-dynamic-too gone, the --make pipeline propagates byte-code compilation
to T22840A (a dependency of TH-using modules) since -dynamic without
-dynamic-too triggers the byte-code+object-code path for dependencies.
With -dynamic-too deprecated and all .hi/.o files unified, WayDyn no
longer affects the ABI of interface or object files. The profile build
tag (used for interface file compatibility checks in Iface/Binary.hs)
must not include the "dyn" component, otherwise we get:

    mismatched interface file profile tag (wanted "dyn", got "")

This occurs when Cabal builds packages with --enable-shared (-dynamic)
using a stage2 compiler whose libraries were compiled without -dynamic.
The .hi files have tag "" but the reader expects "dyn".

By filtering WayDyn from the ways before computing waysBuildTag, both
the writing and reading sides produce consistent tags regardless of
whether -dynamic is passed. This follows the same pattern as the Finder
and Linker fixes (commits 59cc152, 8a64142).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants