1# hie-bios 2 3- [hie-bios](#hie-bios) 4 - [Explicit Configuration](#explicit-configuration) 5 - [Stack](#stack) 6 - [Debugging a `stack` cradle](#debugging-a-stack-cradle) 7 - [Ignoring directories](#ignoring-directories) 8 - [Internal Libraries](#internal-libraries) 9 - [Cabal](#cabal) 10 - [Debugging a `cabal` cradle](#debugging-a-cabal-cradle) 11 - [Ignoring directories](#ignoring-directories-1) 12 - [Bios](#bios) 13 - [Debugging a `bios` cradle](#debugging-a-bios-cradle) 14 - [Direct](#direct) 15 - [Debugging a `direct` cradle](#debugging-a-direct-cradle) 16 - [None](#none) 17 - [Multi-Cradle](#multi-cradle) 18 - [Cradle Dependencies](#cradle-dependencies) 19 - [Configuration specification](#configuration-specification) 20 - [Testing your configuration](#testing-your-configuration) 21 - [Implicit Configuration](#implicit-configuration) 22 - [Priority](#priority) 23 - [`cabal-install`](#cabal-install) 24 - [`stack`](#stack-1) 25 - [`bios`](#bios-1) 26 - [Supporting Bazel and Obelisk](#supporting-bazel-and-obelisk) 27 28`hie-bios` is the way to specify how 29[`haskell-language-server`](https://github.com/haskell/haskell-language-server) 30and [`ghcide`](https://github.com/digital-asset/ghcide) set up a GHC API session. 31 32Given a Haskell project that is managed by Stack, Cabal, or other package tools, 33`haskell-language-server` needs to know the full set of flags to pass to GHC in 34order to build the project. These flags might contain some compilation options 35like `-O2`, but a lot of the time they are package dependencies such as 36`-package-id directory-1.3.6.0`, which also need to be built beforehand. 37`hie-bios` satisfies both these needs. 38 39Its design is motivated by the guiding principle: 40 41> It is the responsibility of the build tool to describe the environment 42> which a package should be built in. 43 44Using this principle, it is possible 45to easily support a wide range of tools including `cabal-install`, `stack`, 46`rules_haskell`, `hadrian` and `obelisk` without major contortions. 47`hie-bios` does not depend on the `Cabal` library nor does it 48read any complicated build products and so on. 49 50How does a tool specify a session? A session is fully specified by a set of 51standard GHC flags. Most tools already produce this information if they support 52a `repl` command. Launching a repl is achieved by calling `ghci` with the 53right flags to specify the package database. `hie-bios` needs a way to get 54these flags and then it can set up a GHC API session correctly. 55 56Further it means that any failure to set up the API session is the responsibility 57of the build tool. It is up to them to provide the correct information if they 58want the tool to work correctly. 59 60## Explicit Configuration 61 62The user can place a `hie.yaml` file in the root of the workspace which 63describes how to set up the environment. There are several supported ways to setup the environment. 64 65### Stack 66 67To explicitly state that you want to use `stack`, the basic configuration `hie.yaml` would look like: 68 69```yaml 70cradle: 71 stack: 72``` 73 74This configuration suffices if your whole project can be loaded by the command `stack repl`. As a rule of thumb, this works if the project consists of only one executable, one library and one test-suite. 75 76Some projects have multiple `stack-*.yaml` files for multiple versions of ghc/resolvers. In this case you 77can specify an alternate relative file to use by using the `stackYaml` option. The path is relative to the 78configuration file. 79 80```yaml 81cradle: 82 stack: 83 stackYaml: "./stack-8.8.3.yaml" 84``` 85 86If your project is more complicated, you need to specify which [components](https://docs.haskellstack.org/en/stable/build_command/#components) you want to load. A component is, roughly speaking, a library/executable/test-suite or benchmark in `stack`. You can view the components/targets of a stack project by executing the command: 87``` sh 88$ stack ide targets 89``` 90 91Since we have two test-suites, one executable and a library, for `hie-bios`, this would output the following: 92 93``` sh 94$ stack ide targets 95hie-bios:lib 96hie-bios:exe:hie-bios 97hie-bios:test:bios-tests 98hie-bios:test:parser-tests 99``` 100 101For an explanation of the target syntax, we refer to the documentation of the [target syntax](https://docs.haskellstack.org/en/stable/build_command/#target-syntax). 102 103To tell `hie-bios` which component it should load, the following `hie.yaml` can be used: 104 105```yaml 106cradle: 107 stack: 108 component: "<component name>" 109``` 110 111where `<component name>` is the name of the component/target you want to load. 112While the component is optional, this is recommended to make sure the correct component is loaded. 113 114Why is this not enough? Usually, you have multiple components with different dependencies. Your library won't depend on `tasty` or `hspec`, but your test-suite might. With this setup, you would only be able to load files from the given component. 115 116Since you rarely only want to load a single component in a `stack` project, we have special syntax to be able to conveniently specify which directory belongs to which component. It is basically a [multi-cradle](#multi-cradle). 117 118```yaml 119cradle: 120 stack: 121 - path: "./src" 122 component: "hie-bios:lib" 123 - path: "./exe" 124 component: "hie-bios:exe:hie-bios" 125 - path: "./tests/BiosTests.hs" 126 component: "hie-bios:test:hie-bios" 127 - path: "./tests/ParserTests.hs" 128 component: "hie-bios:test:parser-tests" 129``` 130 131Here you can see two important features: 132 * We provide a mapping from a filepath to component. 133 * That way, we specify that a file such as `./src/HIE/Bios.hs` belongs to the component `hie-bios:lib`. 134 * The filepath can be a file. 135 * This is convenient if components are overlapping. 136 137This way we specified which component needs to be compiled given a source file for our whole project. 138 139If you use both, multiple components and an alternate `stack.yaml` file, there is a way to specify defaults 140for the path-specific configurations. 141 142```yaml 143cradle: 144 stack: 145 stackYaml: "stack-8.3.3.yaml" 146 components: 147 - path: "./src" 148 component: "hie-bios:lib" 149 - path: "./exe" 150 component: "hie-bios:exe:hie-bios" 151 - path: "./tests/BiosTests.hs" 152 component: "hie-bios:test:hie-bios" 153 - path: "./tests/ParserTests.hs" 154 component: "hie-bios:test:parser-tests" 155``` 156 157A word of warning: Due to current restrictions in the language server, as mentioned in [this bug report](https://github.com/haskell/haskell-language-server/issues/268#issuecomment-667640809) all referenced stack.yaml files must specify the same version of GHC, as only one version of ghcide is loaded at a time per workspace root. This restriction might be lifted in the future. 158 159#### Debugging a `stack` cradle 160 161If you find that `hie-bios` can't load a certain component or file, run `stack repl` and `stack repl <component name>` to see if `stack` succeeds in building your project. Chances are that there is a problem in your project and if you fix that, `hie-bios` will succeed to load it. 162 163Also, see notes for [testing your configuration](#testing-your-configuration). 164 165Otherwise, please open an [issue](https://github.com/mpickering/hie-bios/issues/new). 166 167#### Ignoring directories 168 169You can combine the [multi-cradle](#multi-cradle) with a [none-cradle](#none-cradle) to ignore all source files in a certain directory. The syntax is a bit verbose: 170 171```yaml 172cradle: 173 multi: 174 - path: "./tests/projects" 175 config: 176 cradle: 177 none: 178 - path: "./" 179 config: 180 cradle: 181 stack: 182 - path: "./src" 183 component: "hie-bios:lib" 184 - path: "./exe" 185 component: "hie-bios:exe:hie-bios" 186 - path: "./tests/BiosTests.hs" 187 component: "hie-bios:test:hie-bios" 188 - path: "./tests/ParserTests.hs" 189 component: "hie-bios:test:parser-tests" 190``` 191 192This way, we specify that we do not want to load any files in our test project directories. 193 194#### Internal Libraries 195 196Internal libraries are not well supported in `stack`. Since the syntax `stack repl <internal library name>` [doesn't work](https://github.com/commercialhaskell/stack/issues/4564), `hie-bios` will generally not work with internal libraries using `stack`. 197 198### Cabal 199 200To use `cabal`, the basic explicit configuration looks similar to `stack`'s configuration. 201 202```yaml 203cradle: 204 cabal: 205``` 206 207The implication of this configuration is a bit different, though. Given a source file to load, we will use `cabal repl <filename>` to find the component of the given filepath. 208 209This configuration should work in (almost) every standard project setup, since `cabal` finds the component associated to a given source file. 210However, due to an unfortunate [bug](https://github.com/haskell/cabal/issues/6622), this fails on some files with `cabal` versions older than `3.4`. 211So, to make your project loadable by older `cabal` versions, you can specify a component to load. 212A [component](https://cabal.readthedocs.io/en/latest/nix-local-build.html?highlight=component#cabal-v2-build) is roughly speaking a library, executable, test-suite or benchmark in `cabal`. 213The `hie.yaml` file looks like this: 214 215```yaml 216cradle: 217 cabal: 218 component: <component name> 219``` 220 221This tells `hie-bios` that whichever source file it tries to load, this source file should be handled as if it belongs to `<component name>`. 222 223As an example, to load the library of `hie-bios`, the following `hie.yaml` can be used: 224 225```yaml 226cradle: 227 cabal: 228 component: "lib:hie-bios" 229``` 230 231The component syntax `"lib:hie-bios"` refers to the library of the package `hie-bios`. For a complete reference of the component syntax, we refer to the [documentation](https://cabal.readthedocs.io/en/latest/nix-local-build.html?highlight=component#cabal-v2-build). 232 233Note that `cabal` and `stack` have different ways of specifying their 234components. 235 236 237If we only specify a single component, then we can only load source files from this component. This is unsatisfactory as we want to be able to navigate our project freely and work on multiple components (test-suite, library, executable, etc...) in parallel. 238 239In a project such as `hie-bios`, we have more than one component, in particular we have four: 240 241 * An executable 242 * A library 243 * Two test-suites 244 245The component syntax can easily be extracted from the `hie-bios.cabal` file. Relevant sections are: 246 247```cabal 248... 249Name: hie-bios 250... 251 252Library 253 ... 254 HS-Source-Dirs: src 255 256Executable hie-bios 257 ... 258 Main-Is: Main.hs 259 HS-Source-Dirs: exe 260 261test-suite parser-tests 262 ... 263 hs-source-dirs: tests/ 264 main-is: ParserTests.hs 265 266test-suite bios-tests 267 ... 268 hs-source-dirs: tests/ 269 main-is: BiosTests.hs 270``` 271 272Using the documentation of cabal, we extract the four component names of the `hie-bios` project: 273 274* `lib:hie-bios` 275* `exe:hie-bios` 276* `test:bios-tests` 277* `test:parser-tests` 278 279Since you rarely only want to load a single component in a `cabal` project, we have special syntax to be able to conveniently specify which directory belongs to which component. It is basically a [multi-cradle](#multi-cradle). 280 281```yaml 282cradle: 283 cabal: 284 - path: "./src" 285 component: "lib:hie-bios" 286 - path: "./exe" 287 component: "exe:hie-bios" 288 - path: "./tests/BiosTests.hs" 289 component: "test:hie-bios" 290 - path: "./tests/ParserTests.hs" 291 component: "test:parser-tests" 292``` 293 294Here you can see two important features: 295 * We provide a mapping from filepath to component. 296 * That way, we specify that a file such as `./src/HIE/Bios.hs` belongs to the component `lib:hie-bios`. 297 * The filepath can be a file. 298 * This is convenient if components are overlapping. 299 300Similarly to `multi-stack` configurations, you can also specify multiple components using a `components` subkey. 301While this is currently not used for anything, this syntax gives you a place to put defaults, directly under 302the `cabal` entry. 303 304```yaml 305cradle: 306 cabal: 307 # Reserved for future default options 308 components: 309 - path: "./src" 310 component: "lib:hie-bios" 311 - path: "./exe" 312 component: "exe:hie-bios" 313 - path: "./tests/BiosTests.hs" 314 component: "test:hie-bios" 315 - path: "./tests/ParserTests.hs" 316 component: "test:parser-tests" 317``` 318 319This way we specified which component needs to be compiled given a certain source file for our whole project. 320 321#### Debugging a `cabal` cradle 322 323If you find that `hie-bios` can't load a certain component or file, you may run `cabal repl <filename>` and `cabal repl <component name>` to see if `cabal` succeeds in building the components. Chances are that there is a problem and if you fix that, `hie-bios` will succeed to load the project. 324 325Also, see notes for [testing your configuration](#testing-your-configuration). 326 327Otherwise, please open an [issue](https://github.com/mpickering/hie-bios/issues/new). 328 329#### Ignoring directories 330 331You can combine the [multi-cradle](#multi-cradle) with a [none-cradle](#none-cradle) to ignore all source files in a certain directory. The syntax is a bit verbose: 332 333```yaml 334cradle: 335 multi: 336 - path: "./tests/projects" 337 config: 338 cradle: 339 none: 340 - path: "./" 341 config: 342 cradle: 343 cabal: 344 - path: "./src" 345 component: "lib:hie-bios" 346 - path: "./exe" 347 component: "exe:hie-bios" 348 - path: "./tests/BiosTests.hs" 349 component: "test:hie-bios" 350 - path: "./tests/ParserTests.hs" 351 component: "test:parser-tests" 352``` 353 354This way, we specify that we do not want to load any files in our test project directories. 355 356### Bios 357 358Alternatively you can explicitly state a `program` or shell command which should 359be used to collect the options. This is the most general approach and can be extended to handle arbitrary build systems. 360 361The path of the `program` attribute is interpreted relative to the current 362working directory if it isn't absolute. A program is passed the file to 363return options for as its first argument, and a shell command will have it 364available in the `HIE_BIOS_ARG` environment variable. 365 366There are two important environment variables: 367 368* `HIE_BIOS_OUTPUT`: describes the filepath the options should be written to. If this file does not exist, the `program` should create it. 369* `HIE_BIOS_ARG`: the source file that we want to load. Options returned by the `program` should be able to compile the given source file. 370 * This environment variable is *only* available if a shell program is given. 371 372The program flow is roughly as follows: 373The process must consult the `HIE_BIOS_OUTPUT` environment variable and write a 374list of options to this file, separated by newlines. Once the process finishes 375running, `hie-bios` reads this file and uses the arguments to set up the GHC 376session. This is how GHC's build system is able to support `hie-bios`. 377Note, the `program` is intended to produce the build flags to compile the *whole* component the given source file belongs to. This entails that the `program` lists all of the component's module- and file targets. 378 379A good guiding specification for this file is that the following commands 380should work for any file in your project. 381 382``` sh 383$ export HIE_BIOS_OUTPUT=./options.txt # this is usually some temporary file 384$ ./<program> /path/to/foo.hs 385$ ghci $(cat $HIE_BIOS_OUTPUT | tr '\n' ' ') 386``` 387 388where `HIE_BIOS_OUTPUT` is some chosen output file and `HIE_BIOS_ARG` contains the file parameter. 389 390The `hie.yaml` configuration looks like this: 391 392```yaml 393cradle: 394 bios: 395 program: "<program>" 396``` 397 398Alternatively, you may specify shell code directly. 399This is helpful, if your `program` executable consists of only a single call to another executable. 400 401```yaml 402cradle: 403 bios: 404 shell: "<build-tool flags $HIE_BIOS_ARG>" 405``` 406 407Additionally, you may specify the path to ghc. Otherwise, the one in the PATH will be used: 408 409```yaml 410cradle: 411 bios: 412 program: "<program>" 413 with-ghc: "<ghc>" 414``` 415#### Debugging a `bios` cradle 416 417The most common error in creating `bios` cradle is to not list all targets of the component. Please make sure, that you always list all targets of the component, associated with the filepath you want to load. 418 419Also, see notes for [testing your configuration](#testing-your-configuration). 420 421### Direct 422 423The `direct` cradle allows you to specify exactly the GHC options that should be used to load 424a project. This is good for debugging but not a very good approach in general as the set of options 425will quickly get out of sync with a cabal file. 426 427```yaml 428cradle: 429 direct: 430 arguments: [arg1, arg2] 431``` 432 433#### Debugging a `direct` cradle 434 435The arguments of a `direct` cradle will be passed almost directly to `ghc`. If the command `ghc <cradle arguments>` succeeds, then `hie-bios` can load the project. 436 437### None 438 439The `none` cradle says that the IDE shouldn't even try to load the project. It 440is most useful when combined with the [multi-cradle](#multi-cradle) which is specified in the next section. 441 442```yaml 443cradle: 444 none: 445``` 446 447## Multi-Cradle 448 449For a multi-component project you can use the multi-cradle to specify how each 450subdirectory of the project should be handled by the IDE. 451 452The multi-cradle is a list of relative paths and cradle configurations. 453The path is relative to the configuration file and specifies the scope of 454the cradle. For example, this configuration specifies that files in the 455`src` subdirectory should be handled with the `lib:hie-bios` component and 456files in the `test` directory using the `test:bios-tests` component. 457 458```yaml 459cradle: 460 multi: 461 - path: "./src" 462 config: 463 cradle: 464 cabal: 465 component: "lib:hie-bios" 466 - path: "./test" 467 config: 468 cradle: 469 cabal: 470 component: "test:bios-tests" 471``` 472 473If a file matches multiple prefixes, the most specific one is chosen. 474Once a prefix is matched, the selected cradle is used to find the options. This 475is usually a specific cradle such as `cabal` or `stack` but it could be another 476multi-cradle, in which case, matching works in exactly the same way until a 477specific cradle is chosen. 478 479This cradle type is experimental and may not be supported correctly by 480some libraries which use `hie-bios`. It requires some additional care to 481correctly manage multiple components. 482 483Note: Remember you can use the multi-cradle to declare that certain directories 484shouldn't be loaded by an IDE, in conjunction with the `none` cradle. 485 486```yaml 487cradle: 488 multi: 489 - path: "./src" 490 config: { cradle: {cabal: {component: "lib:hie-bios"}} } 491 - path: "./test" 492 config: { cradle: {cabal: {component: "test:bios-tests"}} } 493 - path: "./test/test-files" 494 config: { cradle: { none: } } 495``` 496 497For cabal and stack projects there is a shorthand to specify how to load each component. 498 499```yaml 500cradle: 501 cabal: 502 - path: "./src" 503 component: "lib:hie-bios" 504 - path: "./test" 505 component: "test:bios-tests" 506``` 507 508```yaml 509cradle: 510 stack: 511 - path: "./src" 512 component: "hie-bios:lib" 513 - path: "./test" 514 component: "hie-bios:test:bios-tests" 515``` 516 517Remember you can combine this shorthand with more complicated configurations 518as well. 519 520```yaml 521cradle: 522 multi: 523 - path: "./test/testdata" 524 config: { cradle: { none: } } 525 - path: "./" 526 config: { cradle: { cabal: 527 [ { path: "./src", component: "lib:hie-bios" } 528 , { path: "./tests", component: "parser-tests" } ] } } 529``` 530 531## Cradle Dependencies 532 533Sometimes it is necessary to reload a component, for example when a package 534dependency is added to the project. Each type of cradle defines a list of 535files that might cause an existing cradle to no longer provide accurate 536diagnostics if changed. These are expected to be relative to the root of 537the cradle. 538 539This makes it possible to watch for changes to these files and reload the 540cradle appropiately. 541However, if there are files that are not covered by 542the cradle dependency resolution, you can add these files explicitly to 543`hie.yaml`. 544The file dependencies are not required to actually exist, since it can be useful 545to know when they are created, e.g. if there was no `cabal.project` 546in the project before and now there is, it might change how a file in the 547project is compiled. 548 549Here's an example of how you would add cradle dependencies that may not be covered 550by the `cabal` cradle. 551 552```yaml 553cradle: 554 cabal: 555 component: "lib:hie-bios" 556 557dependencies: 558 - package.yaml 559 - shell.nix 560 - default.nix 561``` 562 563For the `Bios` cradle type, the newline-separated cradle dependencies must be written out 564to the file specified by the `HIE_BIOS_DEPS` environment variable. 565 566Previous versions implemented a different mechanism for collecting cradle dependencies 567by means of a second program/shell field. This is still supported for backwards 568compatibility: 569 570```yaml 571cradle: 572 bios: 573 dependency-program: ./dependency.sh 574``` 575```yaml 576cradle: 577 bios: 578 dependency-shell: build-tool dependencies $HIE_BIOS_ARG > $HIE_BIOS_OUTPUT 579``` 580 581## Configuration specification 582 583The complete configuration is a subset of 584 585```yaml 586cradle: 587 cabal: 588 component: "optional component name" 589 stack: 590 component: "optional component name" 591 bios: 592 program: "program to run" 593 dependency-program: "optional program to run" 594 shell: build-tool flags $HIE_BIOS_ARG 595 dependency-shell: build-tool dependencies $HIE_BIOS_ARG 596 with-ghc: "optional path to ghc" 597 direct: 598 arguments: ["list","of","ghc","arguments"] 599 none: 600 multi: - path: ./ 601 config: { cradle: ... } 602 603dependencies: 604 - someDep 605``` 606 607## Testing your configuration 608 609The given `hie-bios` executable is provided to test your configuration. 610 611The `flags` command will print out the options that `hie-bios` thinks you will need to load a file. 612 613``` sh 614$ hie-bios flags exe/Main.hs 615``` 616 617The `check` command will try to use these flags to load the module into the GHC API. 618 619``` sh 620$ hie-bios check exe/Main.hs 621``` 622 623The `debug` command prints verbose information about the cradle, such as where the `hie.yaml` file was found, which file is loaded and the options that will eventually be used for loading a session. 624 625``` sh 626$ hie-bios debug exe/Main.hs 627``` 628 629## Implicit Configuration 630 631There are several built in modes which capture the most common Haskell development 632scenarios. If no `hie.yaml` configuration file is found then an implicit 633configuration is searched for. It is strongly recommended to just explicitly 634configure your project. 635 636### Priority 637 638The targets are searched for in the following order. 639 6401. A specific `.hie-bios` file. 6412. A `stack` project 6423. A `cabal` project 6434. The direct cradle which has no specific options. 644 645### `cabal-install` 646 647The workspace root is the first folder containing a `cabal.project` file. 648 649The arguments are collected by running `cabal v2-repl <filename>`. 650 651If `cabal v2-repl <filename>` fails, then the user needs to configure the correct 652target to use by writing a `hie.yaml` file. 653 654### `stack` 655 656The workspace root is the first folder containing a `stack.yaml` file. 657 658The arguments are collected by executing `stack repl`. If this fails, the user needs to configure the correct target to use by writing a `hie.yaml` file. 659 660### `bios` 661 662The most general form is the `bios` mode which allows users to specify 663which flags to provide themselves. 664 665The program will receive the file to return options for as its first argument. 666 667The program flow is roughly as follows: 668The process must consult the `HIE_BIOS_OUTPUT` environment variable and write a 669list of options to the file pointed to by `HIE_BIOS_OUTPUT`, separated by newlines. Once the process finishes running, `hie-bios` reads this file and uses the arguments to set up the GHC 670session. This is how GHC's build system is able to support `hie-bios`. 671Note, the `program` is intended to produce the build flags to compile the *whole* component the given source file belongs to. This entails that the `program` lists all of the component's module- and file targets. 672 673A good guiding specification for this file is that the following commands 674should work for any file in your project. 675``` sh 676$ export HIE_BIOS_OUTPUT=./options.txt # this is usually some temporary file 677$ ./.hie-bios /path/to/foo.hs 678$ ghci $(cat $HIE_BIOS_OUTPUT | tr '\n' ' ') 679``` 680 681This is useful if you are designing a new build system or the other modes 682fail to setup the correct session for some reason. For example, this is 683how hadrian (GHC's build system) is integrated into `hie-bios`. 684 685## Supporting Bazel and Obelisk 686 687In previous versions of `hie-bios` there was also support for projects using `rules_haskell` and `obelisk`. 688This was removed in the 0.3 release as they were unused and broken. There is no conceptual barrier to adding back support but it requires a user of these two approaches to maintain them. 689