Let me give you a couple high-level tips first:
-
A lot of people who are pretty familiar with Nixpkgs spend a lot of time looking through the Nixpkgs source code. If you want to build up a good understanding of how Nixpkgs works, and be able to look up answers to your own questions, you’ll likely want to get in the habit of grepping through Nixpkgs for things. I know this can be quite annoying at first, but it is quite common if you’re really trying to get a good handle on Nixpkgs.
-
I don’t know if I’d call things like
buildInputs
vsnativeBuildInputs
,prev
vsfinal
, packages from the top-level vs from internal package sets, etc as internal or esoteric, but I get what you’re trying to say. Depending on what you’re trying to do, using eitherbuildInputs
ornativeBuildInputs
may work. Using eitherprev
orfinal
may work. Pulling packages from the top-level vs internal package sets may work. But when myself and others write examples and code snippets, we try to do the “most correct” thing, even if it is a little more confusing. You’re of course always welcome to question why something is written like it is!
And now to answer your actual questions:
buildInputs
is for libraries that are used a run-time. nativeBuildInputs
is for compilers/tools that are run at build-time. It is sort of hand-wavey for something like HLS, which both needs to run at “build-time” (since you’ll be running it in your dev environment), but also needs to be able to link into your own Haskell code.
As long as you’re not cross-compiling, it is often okay to mix up buildInputs
vs nativeBuildInputs
. (But there are a non-insignificant number of people who use Nixpkgs for cross-compiling, so you will often get corrected in PRs and forum posts if you mess it up.)
Nixpkgs contains “top-level” derivations, that are all mostly defined in this single file:
If you grep through this file, you should find an entry for haskell-language-server
. This is the “top-level” haskell-language-server. It is directly under final
.
Nixpkgs also contains sub-package sets. haskellPackages
is an example of a sub package set. This gets a little more complicated, but things in haskellPackages
are effectively defined here:
(You should also be able to find haskellPackages
defined in the above all-packages.nix
file)
If you dig into how final.haskell-language-server
is defined, vs how final.haskellPackages.haskell-language-server
is defined, you’ll see that there are some minor differences, but it mostly doesn’t matter which one you use.
However, you do have to be sure to use haskell-language-server
that was compiled with the same GHC version as you’re using for your project. So if your project uses haskell.packages.ghc94
instead of haskellPackages
, you’ll need to make sure to use haskell.packages.ghc94.haskell-language-server
instead of the top-level haskell-language-server
, or haskellPackages.haskell-language-server
.
This is just sort of how haskellPackages.shellFor
works. There is an example in the source code:
Although now that you mention it, it is kind of confusing that this doesn’t throw an error, or at least a warning or something.
GHC has a concept of a package, and a package database:
- 5.9. Packages — Glasgow Haskell Compiler 9.0.1 User's Guide
- https://medium.com/@zw3rk/building-ghc-the-package-database-50c37cf6ce33
Cabal and cabal-install work directly with GHC packages and package databases, but give users a high-level tool over-top of them. Most users aren’t really directly aware of GHC package databases, but just work with them through cabal-install.
Basically what Nix does is build a GHC package database, and directly hands it to Cabal. Cabal is able to use it without having to build any dependencies on its own. For your nix develop
shell, if you run ghc-pkg list
, you should see what this looks like.