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