Use `buildInputs` or nativeBuildInputs` for `nix-shell`?

According to the Nixpkgs manual,

  • buildInputs is for

    programs and libraries used by the new derivation at run-time

  • whereas nativeBuildInputs contains

    programs and libraries used at build-time that, if they are a compiler or similar tool, produce code to run at run-time—i.e. tools used to build the new derivation

So does it matter? Worked with Nix expressions using both, and never experienced any issues, but I’m wondering if there is a “right way” or if there’s a situation where one of them could backfire?

(See more on buildInputs vs nativeBuildInputs in Nixpkgs issue #19370.)

9 Likes

for nix-shell, most people use a shell.nix + mkShell. In which case it doesn’t really matter as nix-shell doesn’t really make distinctions between them. https://github.com/NixOS/nixpkgs/blob/8d57f75f7a1d04ecbf30333c104c9124cfca9331/pkgs/build-support/mkshell/default.nix#L31

In general though, nativeBuildInputs is useful for cross-compilation as commands from those derivations will be available on the buildPlatform and execute at build time. Whereas buildInputs will likely be the architecture of the hostPlatform, so the derivation can link against those inputs (and be used at run-time).

There’s some cases like python where you may need to list them both as a nativeBuildInputs and as a buildInput, if the package needs to run python during build and will link against it.

EDIT:

This has gotten a lot of views over the years, wanted to expand on this:

  • nativeBuildInputs: Should be used for commands which need to run at build time (e.g. cmake) or shell hooks (e.g. autoPatchelfHook). These packages will be of the buildPlatforms architecture, and added to PATH.
  • buildInputs: Should be used for things that need to be linked against (e.g. openssl). These will be of the hostPlaform’s architecture. With strictDeps = true; (or by extension cross-platform builds), these will not be added to PATH. However, linking related variables will capture these packages (e.g. NIX_LD_FLAGS, CMAKE_PREFIX_PATH, PKG_CONFIG_PATH)

In the early days of nix, packages were expected to be built by x86_64 and target x86_64. It wasn’t until later where cross compilation support was adopted. But to not break nix expressions outside of nixpkgs, the transition to enforcing the differences never happened. Individual packages can “opt-in” to using the more strict tooling divide by setting strictDeps = true; which will roughly emulate how PATH, NIX_CLFAGS_COMPILE, NIX_LD_FLAGS and other environment variables are constructed similar to a cross-platform build.

Outside of cross-compilation, adhering to good practices for nativeBuildInputs is still recommended because certain variables (e.g. XDG_DATA_DIRS) are safe to append to when of the same buildPlatform, but same is not true of hostPlatform packages. This can result in other quality-of-life additions such as bash completion being available for packages listed in nativeBuildInputs, but not for packages in buildInputs.

Additional Context:

  • Taking a package and pulling either the build or host platform variant is called splicing.
    • Packages specific to the buildPlatform can be found in buildPackages. This sometimes can be useful when using overrides, which may not respect splicing.
    • Similarly targetPackages have packages specific to the target platform (generally not useful for most packages except toolchains).
    • The default package set already targets hostPlatform, so you those are just referenced by pkgs in a general sense.
  • nativeBuildInputs and buildInputs are technically “legacy” terms, although still the standard convention in most nix packages. However, unless you’re writing packages which export toolchains (e.g. gcc, clang, interpreters), you likely wont need to use the more accurrate depsXXXYYY variants.
14 Likes

Thanks, and there’s a lot to unpack. What follows are mostly just notes so that it will make sense to me later.

Looking at the source of mkShell that you linked, it will call mkDerivation in the end.

As you stated that nix-shell treats both buildInputs and nativeBuildInputs the same (does this apply to other *Inputs as well?), I went ahead and poked around in NixOS/nix to find the source of nix-shell. Am I on the right track looking at nix-build.cc? My C knowledge is next to nothing, but the line below tells me that I’m probably am.

// nix-build.cc, line 89
auto myName = runEnv ? "nix-shell" : "nix-build";

Couldn’t figure out yet how and where *Inputs end up though.

1 Like

Is there a reason why mkShell puts all inputs together?

I wanted to setup a shell for cross compilation using the following:

with import <nixpkgs> {
  crossSystem = (import <nixpkgs> {}).lib.systems.examples.aarch64-multiplatform;
};

mkShell {
  nativeBuildInputs = [ cmake ];
  buildInputs = [ poco boost ];
}

My expectation was to have cmake that can run on the host, while the poco and boost library are available for aarch64.

But it seems everything, even cmake is available only for aarch64.

Is there another way to setup a cross compilation shell?

1 Like

you will want buildPackages.cmake in this case

$ nix repl
Welcome to Nix version 2.4pre20201205_a5d85d0. Type :? for help.

nix-repl> :l
Added 13482 variables.

nix-repl> pkgsCross.aarch64-multiplatform.cmake
«derivation /nix/store/y68j9l006dp3mcpd5dx32rm6278k1i73-cmake-3.19.3-aarch64-unknown-linux-gnu.drv»

nix-repl> pkgsCross.aarch64-multiplatform.buildPackages.cmake
«derivation /nix/store/br19j78h50ihp2yw8jfmgnn5fwkvgivd-cmake-3.19.3.drv»

nix-repl> cmake
«derivation /nix/store/br19j78h50ihp2yw8jfmgnn5fwkvgivd-cmake-3.19.3.drv»

notice that the last two are from the host machine.

4 Likes