Repository navigation
How to use the debugger #12416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
How to use the debugger #12416
Changes from all commits
8420901
ecfe593
557b616
97ea84a
dfc7d76
9cd6ff3
45f9484
797f414
ce68f96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,6 +167,183 @@ For these test executables, `-p` which applies a regex filter to the test | |
| names. When running `cabal-install` test suites, one need only use `cabal test` or | ||
| `cabal run <test-target>` in order to test locally. | ||
|
|
||
| ## Using the Haskell Debugger | ||
|
|
||
| We can debug `cabal` with the [Haskell debugger][hdb] to set breakpoints, step | ||
| through, and watch variables. This can be done from the command line or within | ||
| any editor that supports the [Debug Adapter Protocol][debug-protocol], such as | ||
| VS Code. | ||
|
|
||
| To get set up: | ||
|
|
||
| 1. Install `hdb`. It needs GHC 9.14 or later, and the `ghc` on your `PATH` when | ||
| you run `hdb` has to be the version `hdb` was built with. | ||
|
|
||
| 2. Make sure the `cabal` on your `PATH` supports `cabal repl --with-repl` | ||
| (cabal-install 3.16 or later). `hdb` uses [hie-bios][hie-bios] to find out | ||
| how to load the project and hie-bios in turn runs this command. | ||
|
|
||
| [hdb]: https://well-typed.github.io/haskell-debugger/ | ||
| [debug-protocol]: https://microsoft.github.io/debug-adapter-protocol/ | ||
| [hie-bios]: https://github.com/haskell/hie-bios | ||
|
|
||
| ### Debugging Project and Cradle | ||
|
|
||
| We have a project and cradle for debugging: | ||
|
|
||
| * [`cabal.hdb.project`](./cabal.hdb.project) with a subset of packages, leaving | ||
| out `cabal-testsuite`. | ||
|
|
||
| * [`hie-hdb.yaml`](./hie-hdb.yaml) uses this project and lists which components | ||
| to load. Breakpoints can only be set in those components. Everything else is | ||
| a compiled dependency. The cradle is not named `hie.yaml` so that the Haskell | ||
| Language Server won't pick it up. This means it has to be given explicitly to | ||
| `hdb`. | ||
|
|
||
| > [!WARNING] | ||
| > Do not use `cabal.project`, the default project, for debugging. `hdb` tries to | ||
| > load every component of every package but will fail with: | ||
| > | ||
| > ``` | ||
| > Failed to get compiler options using hie-bios cradle | ||
| > ``` | ||
| > | ||
| > This is because `cabal-testsuite` and its custom setup uses an older and | ||
| > incompatible version of `Cabal`. | ||
|
|
||
| ### Debugging from the Command Line | ||
|
|
||
| Run `hdb` from the root of the repository, giving it the cradle, the file with | ||
| `main` in it and, after `--`, the arguments for `cabal`: | ||
|
|
||
| ``` | ||
| $ hdb --cradle-file hie-hdb.yaml cabal-install/main/Main.hs -- --version | ||
| ``` | ||
|
|
||
| Each time it starts, `hdb` loads all of the components as bytecode, more than | ||
| 500 modules. Expect this to take a while and a decent chunk of memory. The first | ||
| time, `hie-bios` also builds the dependencies into its own build directory, | ||
| under `~/.cache/hie-bios`, leaving `dist-newstyle` alone. | ||
|
|
||
| Once loaded, set breakpoints by file and line, with the path relative to the | ||
| root of the repository, and then `run`: | ||
|
|
||
| ``` | ||
| (hdb) break cabal-install/src/Distribution/Client/Main.hs 323 | ||
| (hdb) run | ||
| Stopped at breakpoint | ||
| (hdb) variables | ||
| _result : IO () = <fn> :: IO () | ||
| args : [String] = [...] | ||
| 0 : [Char] = "--version" | ||
| (hdb) next | ||
| (hdb) continue | ||
| cabal-install version 3.19.0.0 | ||
| compiled using version 3.19.0.0 of the Cabal library | ||
| (hdb) exit | ||
| ``` | ||
|
|
||
| The `cabal` being debugged runs in the root of the repository. To have it work | ||
| on another project, use `--project-dir`: | ||
|
|
||
| ``` | ||
| $ hdb --cradle-file hie-hdb.yaml cabal-install/main/Main.hs -- \ | ||
| build all --dry-run --project-dir=/path/to/project | ||
| ``` | ||
|
|
||
| > [!TIP] | ||
| > If a breakpoint is not hit, check that `cabal` has not skipped that work. | ||
| > For instance, the solver does not run when the project already has an | ||
| > up-to-date plan. If `hdb` fails to start, add `-v 3` to see what hie-bios | ||
| > and `cabal repl` are doing. | ||
|
|
||
| > [!TIP] | ||
| > Each time it stops or evaluates an expression, `hdb` repeats some warnings | ||
| > from GHC, such as `<interactive>:1:1: warning: [GHC-15328] [-Wdeprecations]`. | ||
| > Add `--extra-ghc-args=-w` before the file with `main` in it to silence these. | ||
|
|
||
| ### Debugging from VS Code | ||
|
|
||
| Install the [Haskell Debugger | ||
| extension](https://marketplace.visualstudio.com/items?itemName=Well-Typed.haskell-debugger-extension) | ||
| and start VS Code from a shell that has the right `ghc` and `hdb` on its | ||
| `PATH`. Then add a configuration to `.vscode/launch.json`, changing `entryArgs` | ||
| to the arguments for `cabal`: | ||
|
|
||
| ```json | ||
| { | ||
| "version": "0.2.0", | ||
| "configurations": [ | ||
| { | ||
| "type": "haskell-debugger", | ||
| "request": "launch", | ||
| "name": "cabal --version", | ||
| "projectRoot": "${workspaceFolder}", | ||
| "entryFile": "cabal-install/main/Main.hs", | ||
| "entryPoint": "main", | ||
| "entryArgs": ["--version"], | ||
| "extraGhcArgs": ["-w"], | ||
| "cradleFile": "hie-hdb.yaml" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| The `cradleFile` is relative to the `projectRoot`. The `-w` in `extraGhcArgs` | ||
| keeps the debug console free of the warnings GHC would otherwise repeat each | ||
| time the debugger stops or evaluates an expression. | ||
|
|
||
| ### Debugging a Test Suite | ||
|
|
||
| To debug a test suite, add its component to `componentsToLoad` in | ||
| `hie-hdb.yaml`, for example `cabal-install:test:unit-tests`, and give `hdb` the | ||
| file with the `main` of the test suite and the arguments for the test suite. | ||
| Where we would run a test with: | ||
|
|
||
| ``` | ||
| $ cabal run cabal-install:test:unit-tests -- --pattern simpleTest1 | ||
| ``` | ||
|
|
||
| The equivalent for debugging that test is: | ||
|
|
||
| ``` | ||
| $ hdb --cradle-file hie-hdb.yaml cabal-install/tests/UnitTests.hs -- --pattern simpleTest1 | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > A test suite ends by exiting with an exit code, which is an exception that | ||
| > the debugger reports as uncaught. So when all tests pass, expect to see | ||
| > `ExitSuccess`, and from VS Code: | ||
| > | ||
| > ``` | ||
| > Uncaught exception of type SomeException was thrown! | ||
| > ExitSuccess | ||
| > ``` | ||
| > | ||
| > This goes to the debug console. The output of the test suite itself, with the | ||
| > results of the tests, can be seen in the terminal window. | ||
|
|
||
| A test suite runs in the root of the repository, not in the directory of its | ||
| package. Some tests read or write files relative to the directory of their | ||
| package. To run a test suite from there with the command line debugger, start | ||
| `hdb` in the package directory, giving it the absolute path of the cradle and | ||
| paths relative to the package for the file with `main` and for breakpoints: | ||
|
|
||
| ``` | ||
| $ cd cabal-install | ||
| $ hdb --cradle-file "$(realpath ../hie-hdb.yaml)" tests/UnitTests.hs -- --pattern simpleTest1 | ||
| (hdb) break tests/UnitTests.hs 32 | ||
| ``` | ||
|
|
||
| `hdb` has no setting for the working directory of the program being debugged. | ||
| When it is started from an editor, the way to change directory is to stop at a | ||
| breakpoint on the first line of `main` and evaluate this, in the debug console | ||
| for VS Code, before continuing: | ||
|
|
||
| ``` | ||
| System.Directory.setCurrentDirectory "cabal-install" | ||
| ``` | ||
|
Comment on lines
+326
to
+345
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alt-romes is this a good way to get a test suite to run next to its fixtures when being debugged?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That snippet has two examples, one for the command line and one for use with an editor. |
||
|
|
||
| ## Running other checks locally | ||
|
|
||
| Various other checks done by CI can be run locally to make sure your code doesn't | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| -- A project for debugging cabal with the Haskell debugger (hdb), used by the | ||
| -- hie-hdb.yaml cradle. See the "Using the Haskell debugger" section of | ||
| -- CONTRIBUTING.md. | ||
| -- | ||
| -- This leaves out cabal-testsuite because `cabal repl --with-repl`, that the | ||
| -- debugger relies on, needs Cabal >= 3.16 for the setup of every package in the | ||
| -- project and the custom setup of cabal-testsuite depends on an older Cabal. | ||
| import: project-cabal/ghc-options.config | ||
| import: project-cabal/ghc-latest.config | ||
| import: project-cabal/pkgs/cabal.config | ||
| import: project-cabal/pkgs/install.config | ||
| import: project-cabal/pkgs/tests.config | ||
| import: project-cabal/constraints.config | ||
|
|
||
| tests: True | ||
|
|
||
| -- The debugger loads packages as bytecode, ignoring optimization flags and | ||
| -- warning that it does so. | ||
| optimization: False | ||
|
|
||
| -- Keep compiler warnings out of the debugger's console. | ||
| program-options | ||
| ghc-options: -w |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # A hie-bios cradle for debugging cabal with the Haskell debugger (hdb), see | ||
| # the "Using the Haskell debugger" section of CONTRIBUTING.md. | ||
| # | ||
| # This file is deliberately not named hie.yaml so that HLS does not pick it up. | ||
| # Pass it to hdb explicitly, with --cradle-file or "cradleFile". | ||
| cradle: | ||
| cabal: | ||
| cabalProject: cabal.hdb.project | ||
| # Breakpoints can only be set in the components loaded here. To debug a | ||
| # test suite, add its component, e.g. cabal-install:test:unit-tests. | ||
| componentsToLoad: | ||
| - cabal-install:exe:cabal | ||
| - cabal-install:lib:cabal-install | ||
| - cabal-install-solver:lib:cabal-install-solver | ||
| - Cabal:lib:Cabal | ||
| - Cabal-syntax:lib:Cabal-syntax |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be condensed? Or portions moved somewhere where only the debugger users look? Or maybe the link to the blog post already covers most of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can assume anyone using the debugger would know what debugging is but I thought I should say something about it as an intro. What do you suggest? Should I dive right into the setup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The link is to a flashy new web site for the Haskell Debugger!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted the list of commands.
A lot of the other stuff is cabal-specific. The warning about
cabal-testsuiteand its setup-depends can go when we merge #12369. I'd like the tips to stay. It is important to mention the way to change directory before debugging a testsuite with relative fixtures. Perhaps the "Debugging from VS Code" section could go but having it means we cover the most common editor case in a paste and go fashion.