Description
There are a bunch of tickets around some weird behaviors when trying to apply ghc-options
. I've linked some below, but there are others that are semi-related as well.
This issue tries to capture most of the problems in a single place to resolve them.
There are a few ways to pass ghc-options
(or, more generally ${program}-options
for programs like ld
, gcc
, alex
, happy
)
cabal.project
In cabal.project
:
-- Applies globally, see [1]
program-options
ghc-options: -fno-full-laziness
-- Applies globally
package *
ghc-options: -fno-full-laziness
-- Applies only to package foo
package foo
ghc-options: -fno-full-laziness
[1] The configureCompiler
phase pulls the options from the local config, which then gets applied to the entire plan's config, triggering a full rebuild. Reproducer:
cabal clean
cabal build all
# add "program-options" block to cabal.project
cabal build all
# all dependencies get built too
Problematic code:
cabal/cabal-install/src/Distribution/Client/ProjectPlanning.hs
Lines 464 to 515 in 65318cc
Related tickets:
- Package sections in cabal.project are insufficient, need local section #3579 (includes a comment that the
program-options
stanza was intended to only apply locally) - v2-cabal: Don't rebuild dependencies when
-O0
or-fno-code
is supplied as--ghc-options
#7368 - ghc-options applies to all dependencies, not just local packages #3883
Command line
Input from the command line suffers a similar fate:
cabal clean
cabal build all
cabal build --ghc-options=-fno-full-laziness all
# all dependencies get built too
This time it is more intentional:
cabal/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs
Lines 198 to 220 in 65318cc
This note indicates that the idea behind applying these options globally is that you want a consistent tool-chain for the entire build. While that seems reasonable for program paths, I can't think of any good examples for program args.
Related tickets:
- --prog-option(s) (e.g. gcc-options) CLI flags get duplicated #6183
- Explicitly support building with -fno-code #1176 (the last two comments are about trying to apply local-only flags)
Caching and Recompilation Avoidance
These problems are complicated by recompilation avoidance. Some flags do not affect output, so are excluded from the package hash. This same logic is used to determine whether or not the config has changed:
cabal/cabal-install/src/Distribution/Client/ProjectBuilding.hs
Lines 346 to 349 in 65318cc
This causes some flags to get stuck in the config cache until either a cabal clean
or a non-ignored flag is applied. Reproducer:
cabal clean
cabal build --ghc-options=-ddump-simpl all
# -ddump flags are ignored, so don't trigger dependency rebuilds, but are included in fresh builds
# modify a module
cabal build all
# -ddump-simpl still applied
Related tickets:
- Some ghc-options should not be considered part of build hash #4247 (exclusion of certain flags from package hash)
--ghc-options
are cached, but shouldn't be #7816
Proposal
- To fix the local flags applying globally, we should be able to just rip out the two linked pieces of code that duplicate the flags. Note that this code correctly constructs the list of flags anyway:
cabal/cabal-install/src/Distribution/Client/ProjectPlanning.hs
Lines 1969 to 1982 in 65318cc
This makes only-local flags possible, and the previous functionality is still available with:
package *
ghc-options: ...
- At that point it would probably be best to remove this stanza:
program-options
ghc-options: ...
and make a top-level ghc-options
legal to be consistent with all the other package settings. This is technically a breaking change, but the stanza is currently undocumented and broken, so it's unlikely to break too many workflows.
- To fix the caching, the best option I can think of is:
a. Only cache the normalized config so that we aren't left with a-ddump-simpl
that we can't get rid of
b. Use the non-normalized config when building so that the user still gets what they want