haskell / haskell/cabal

Implementation and purpose of Show-Build-Info

Open
#7,489 17 comments 4 reactions 1 assignee Claimed by @fendor View on GitHub
blocked: decision-needed type: discussion
Dominant language
Haskell
Stars
1.7k
Forks
750
Avg merge
4d 3h
Merged PRs (30d)
28

Description

EDIT:

# Final implementation

Finally the chosen implementation has been the third ("Dump build info as side effect of `Setup.hs build`") with the pr #7498

---

Nomenclature (uses recursive name bindings)
```
Cabal = `lib:Cabal`
cabal = `exe:cabal`
v2-build = nix-style build command for project building (happens in exe:cabal)
Setup.hs build = Cabal build system, e.g. what happens under the hood (happens in lib:Cabal)
v2-show-build-info = nix-style show-build-info command, cli interface for users (happens in exe:cabal)
Setup.hs show-build-info = Cabal show-build-info system, performs actual work (happens in lib:Cabal)
```
---

The command `show-build-info` is intended to help tooling based on Cabal to find detailed information on how to build each component individually. It is not intended to expose Cabal details, such as what preprocessors are executed, etc... It also does not subsume Cabal's build process, i.e. having the output of `show-build-info` does not suffice to build a cabal component in certain situations. For example it is still Cabal's task to generate `Paths_*.hs`. Therefore, `show-build-info` only works to compile a project, if Cabal has basically built the project, already.

But then tooling such as [hie-bios](https://github.com/mpickering/hie-bios/) and [hsinspect](https://gitlab.com/tseenshe/hsinspect) can use the output of `show-build-info` to feed them into a GHC session and provide IDE functionality.

## Implementation

Extracting compiler information is theoretically not a problem for cabal. Since we parse the `.cabal` file description and already solve for which dependencies to use, basically all information should be present, right? However, Cabal has been designed with extensibility in mind and achieved that by allowing developers to overwrite certain cycles of a build via custom Setup.hs hooks. These hooks are basically a way for a developer of a Cabal package to overwrite or redefine various build-steps in Cabal.
This means that while `exe:cabal` knows everything about the package to build, `lib:Cabal` can change compilation flags when building the project.
Therefore, `exe:cabal` alone can not provide us with the low-level details on how to compile a component, as only lib:Cabal has the full build information (when using `build-type: Custom`). Thus, `show-build-info` must be a part of lib:Cabal, as long as we have build hooks in order to generate the correct build-info reliably.

For the implementation itself, we present three ideas:

### Dump build info as side effect in `v2-build`

**Idea:** Add an option to `exe:cabal` v2-build to dump the build information during the build. We would explicitly invoke `Setup.hs show-build-info` from the `v2-build` command.

**Pros:**

* No extra command
* Keeps build-info up-to-date automatically
* Can be easily used by editors without extra invocation

**Con:**

* Performs more work than necessary
* `build` will compile a component, although we might not need to (e.g. build a component of which we only need the ghc options)
* Could be mitigated by additional flag, such as `--only-prebuild`
* Maintaining a Cabal command is a lot of work and error-prone.
* Handling build hooks correctly is non-trivial.

**Issues:**

* What components are available?
* Solvable via `plan.json`
* Doesn't include disabled components right now.
* Which ghc is going to be used?
* How to tell whether build-info is outdated?
* `--dry-run` to the rescue! Tells you when a component needs to be rebuilt.

### New command, `v2-show-build-info`, which calls `Setup.hs show-build-info`

**Idea:** manually trigger the generation of build information.

**Pros:**

* Manual control
* Can be explicitly instructed to give possibly outdated information
* Minimal amount of work possible
* Don't build a component if you don't have to.
* Extensible
* New flags might be added, such as `--buildinfo-project` that prints project global information (quickly).

**Con:**

* Preprocessing of relevant files might be missing
* Maintaining a cabal command is a lot of work and error-prone
* Handling build hooks correctly is non-trivial.

**Issues:**

* What components are available?
* Solvable via `plan.json`
* Doesn't include disabled components right now.

### Dump build info as side effect of `Setup.hs build`

**Idea:** Generate build info whenever `Cabal` builds a component and put it into the "old-style" builddir of `Setup.hs build`, i.e. next to `setup-config`.

**Pros:**

* Probably the quickest solution as we already parsed LocalBuildInfo/setup-config. Standalone s-b-i command has to redo that work.
* Keeps build-info up-to-date automatically
* Can be easily used by editors without extra invocation
* Best way to avoid missing bugs and corner-cases
* Handles custom hooks correctly

**Con:**

* Discovering build-info files is not as trivial as possible.

**Issues:**
* What components are available?
* Solvable via `plan.json`
* Doesn't include disabled components right now.
* How to tell whether build-info is outdated?
* `--dry-run` to the rescue! Tells you when a component needs to be rebuilt.

#### Implementation details

We can generate the build-info and write it to the `build` directory of each component (e.g. `dist-newstyle/build/.../`).

After performing a `v2-build`, `exe:cabal` writes out `build-info.list` file to `dist-newstyle/cache`, containing the list of all build-info files which might exist, i.e. all enabled components. This file can be parsed by external tools to discover all build-infos of the project.

Optionally, we can add a command `v2-ide` that does:
* Give us the location of each individual build info file
* Give us the build-information for a given filepath/target.
* List all components in the project (enabled and disabled)
* Give us project wide information (such as compiler version) without running the solver (really fast!)

## Summary

I discussed `show-build-info` quite thoroughly with @DanielG, and we concluded that the third approach is probably the cleanest solution.

Current PR: https://github.com/haskell/cabal/pull/7478 which basically implements approach 2.

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.