haskell / haskell/cabal

Cabal-3.12.0.0 passes include dirs to GHC in a new order

Open
#10,060 6 comments 0 reactions 0 assignees View on GitHub
breaking build-type: custom cabal-install: v1- Cabal: custom can-workaround re: build-tool
Dominant language
Haskell
Stars
1.7k
Forks
750
Avg merge
4d 3h
Merged PRs (30d)
28

Description

A full reproducer with analysis is at https://github.com/andreasabel/bug-cabal-3.12-setup .

I noticed this issue when using ghc-9.10.1 for the first time to build Agda using `cabal v1-install`. The Agda parser was malfunctioning. Turned out I had a stale `Lexer.hs` next to my `Lexer.x`, and this would be used when building with ghc-9.10 but not when building with ghc-9.8. After some hours I traced the problem down to the version of the `Cabal` library shipped with these GHCs.

## In short

Cabal-3.12 passes the include directories to GHC in a different order than Cabal-3.10. Cabal-3.10 puts `dist/build` before the `hs-source-dirs` whereas Cabal-3.12 does it the other way round. This leads GHC to pick up a different `.hs` file:
- In case of `Cabal-3.10` the one generated by the build-tool.
- In case of `Cabal-3.12` the one sitting in the source tree.

The problem is reproduced in a GitHub workflow run here: https://github.com/andreasabel/bug-cabal-3.12-setup/actions/runs/9291884301 . Passes with GHC 9.8, fails with GHC 9.10, independent of the version of `cabal-install`.

## Full description

It follows a longer description copied from https://github.com/andreasabel/bug-cabal-3.12-setup/blob/61cdad9444a3b13e2b833e1dde36019c4a31f782/README.md

__Cabal-3.12 passes include dirs in wrong order to GHC__

Conditions:
- GHC 9.10
- `cabal v1-install`
- custom setup (can be default `Setup.hs`), so that `Cabal-3.12` is used
- building a `library` (not just an `executable`)
- using a build-tool: we use `happy` here to shadow a `.hs` file by a `.y` file
- `hs-source-dirs` is not `.` but e.g. `src`

Files:
- `fred.cabal` with
* `build-type: Custom`
* `library` with `hs-source-dirs: src` (in particular not `.`)
- `Setup.hs` (standard)
- `src/Fred.y`: processed by `happy`
- `src/Fred.hs`: stale code that should be shadowed by `Fred.y` always

In this setting `cabal v1-install` malfunctions if `ghc` is `ghc-9.10.1`. (Works with older GHCs.)
It picks up `src/Fred.hs` instead of `dist/build/Fred.hs` that is created by `happy` from `src/Fred.y`.

Looking at the verbose output `cabal v1-install -v3`, we notice a difference in the call to `ghc` when the GHC is 9.10.1.

- GHC 9.10 / Cabal-3.12

/usr/local/bin/ghc --make -fbuilding-cabal-package \
...
-isrc -idist/build \
... \
Fred

[1 of 2] Compiling Main ( Fred.hs, dist/build/Main.o, ...

- GHC 9.8 / Cabal-3.10

/usr/local/bin/ghc --make -fbuilding-cabal-package \
... \
-idist/build -isrc \
... \
Fred

[1 of 1] Compiling Parser ( dist/build/Parser.hs, ... )

When building with GHC 9.8, library `Cabal-3.10` is used which places the path `dist/build` with the generated files correctly before the path `.` of the source files; but with GHC 9.10, library `Cabal-3.12` is used which does it the other way.

Full calls:

- GHC 9.10 / Cabal-3.12

/usr/local/bin/ghc --make -fbuilding-cabal-package -O -static -dynamic-too -dynosuf dyn_o -dynhisuf dyn_hi \
-outputdir dist/build -odir dist/build -hidir dist/build \
-hiedir dist/build/extra-compilation-artifacts/hie \
-stubdir dist/build -i \
-i. -idist/build \
-idist/build/autogen -idist/build/global-autogen \
-Idist/build/autogen -Idist/build/global-autogen -Idist/build \
-I/usr/local/opt/icu4c/include -I/usr/local/opt/libxml2/include/libxml2 \
-optP-include -optPdist/build/autogen/cabal_macros.h \
-this-unit-id stale-0-Ly26ql3fYpuLnJ9xynYGbf \
-hide-all-packages -Wmissing-home-modules -package-db dist/package.conf.inplace \
-package-id array-0.5.7.0-2002 -package-id base-4.20.0.0-8a80 \
-XHaskell2010 \
Fred

[1 of 2] Compiling Main ( Fred.hs, dist/build/Main.o, ...

- GHC 9.8 / Cabal-3.10

/usr/local/bin/ghc --make -fbuilding-cabal-package -O -static -dynamic-too -dynosuf dyn_o -dynhisuf dyn_hi \
-outputdir dist/build -odir dist/build -hidir dist/build \
-stubdir dist/build -i \
-idist/build -i. \
-idist/build/autogen -idist/build/global-autogen \
-Idist/build/autogen -Idist/build/global-autogen -Idist/build \
-I/usr/local/opt/icu4c/include -I/usr/local/opt/libxml2/include/libxml2 \
-optP-include -optPdist/build/autogen/cabal_macros.h \
-this-unit-id stale-0-F795SeGwWezHPbPW8onWYj \
-hide-all-packages -Wmissing-home-modules -package-db dist/package.conf.inplace \
-package-id array-0.5.6.0-28ee -package-id base-4.19.1.0-654f \
-XHaskell2010 \
Fred

[1 of 1] Compiling Parser ( dist/build/Parser.hs, ... )

Contributor guide

Open the contributing guide

Research direction

Start with the linked reproducer and its README, then inspect fred.cabal, Setup.hs, src/Fred.y, and the stale src/Fred.hs. Run the GitHub Actions reproduction with GHC 9.8 and 9.10 using cabal v1-install, and compare the verbose GHC include-directory ordering; done means the generated file is selected consistently in the reported library setup.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.