haskell / haskell/cabal

ghc-options mega issue

Open
#7,998 5 comments 6 reactions 0 assignees View on GitHub
meta: tracking
Dominant language
Haskell
Stars
1.7k
Forks
750
Avg merge
4d 3h
Merged PRs (30d)
28

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: https://github.com/haskell/cabal/blob/65318cc6b82fe25cef6ba3b98feae68369bf4f37/cabal-install/src/Distribution/Client/ProjectPlanning.hs#L464-L515

Related tickets:
- #3579 (includes a comment that the `program-options` stanza was intended to only apply locally)
- #7368
- #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: https://github.com/haskell/cabal/blob/65318cc6b82fe25cef6ba3b98feae68369bf4f37/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs#L198-L220

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:
- #6183
- #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: https://github.com/haskell/cabal/blob/65318cc6b82fe25cef6ba3b98feae68369bf4f37/cabal-install/src/Distribution/Client/ProjectBuilding.hs#L346-L349

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:
- #4247 (exclusion of certain flags from package hash)
- #7816

---

### Proposal

1. 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: https://github.com/haskell/cabal/blob/65318cc6b82fe25cef6ba3b98feae68369bf4f37/cabal-install/src/Distribution/Client/ProjectPlanning.hs#L1969-L1982

This makes only-local flags possible, and the previous functionality is still available with:
```
package *
ghc-options: ...
```

2. 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.

3. 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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.