The papercut thread - post your small annoyances/confusions here

The output of a nix/os command should never be empty. Ever. What does it mean if a command takes 30 seconds to run and returns nothing? It’s incredibly context-dependent. Sometimes it means success, other times it means it has no idea what you’re talking about.

Seems like such a simple fix.

I filed an issue about this already, but the documentation does a very bad job of explaining that syntax.

Here’s my biggest pet peeve (other than the with keyword as mentioned above):

Sometimes I’m writing a derivation and realize I may need to use propagatedBuildInputs instead of the normal buildInputs. I have a vague understanding that propagatedBuildInputs will “propagate” those build inputs, but I don’t really know what’s going on, so I google for the difference.

I normally find the following section in the nixpkgs manual:

https://nixos.org/nixpkgs/manual/#ssec-stdenv-dependencies

I try to read this section, get completely lost about half way through, give up, and go back to just randomly trying propagatedBuildInputs or buildInputs until something seems to work.


I think the explanation for how propagation works is too detailed for a user manual. I think the first thing in that section should really just be a couple examples of when propagatedBuildInputs is needed and not needed. I think the detailed explanation of exactly how dependencies are propagated and in what way should be saved for a different document. Maybe a wiki page?

6 Likes

And, oh, please, stop littering my tree with ./result* symlinks :wink: . The worst being nixos-rebuild build, which pins a whole system in whatever location you happen to be.

2 Likes

Running man nix on NixOS gives me

No manual entry for nix

While nix --help works.

5 Likes

12 posts were split to a new topic: Documentation improvements

I think it is sufficient! I think we should heavily document this; it seems very useful!!

Example usage that I am now using in a module I’m building

{ lib, config, ...}: 
let
  inherit (lib) mkIf mkMerge mkOption mkEnableOption ;
  inherit (lib.types) attrsOf str;
in
{
  options.services.journal-upload = {
    enable = mkEnableOption "journal-upload";
    config = mkOption {
      type = attrsOf str;
    };

  };
  options.services.journal-remote = {
    enable = mkEnableOption "journal-remote";
    config = mkOption {
      type = attrsOf str;
    };
  };

  config = mkMerge [

    (mkIf config.journal-upload.enable {
      systemd.sockets.systemd-journal-upload.wantedBy = [ "sockets.target"];
      environment.etc."journal-upload.conf".text = "";
    })

    (mkIf config.journal-remote.enable {
      systemd.sockets.systemd-journal-remote.wantedBy = [ "sockets.target"];
      environment.etc."journal-remote.conf".text = "";
    })
  ];
  
}


5 Likes

I have a lot of trouble finding the definitions of particular functions.

I have a lot of trouble with having to cleanroom a compiler toolchain (Rust in this case) when the version I want to use isn’t in nixpkgs.

Several compiler toolchains (again, Rust) depend on the auto-updater (rustup) instead of on a precise .tar.gz.

(I know I should really get involved with the Rust derivation maintenance, or at least talk to the people involved to understand the philosophy.)

2 Likes

Yeah, that explanation is really very internals-focused. Here’s a (hopefully) more comprehensible explanation that focuses more on how to use it, and only on implementation details that directly affect the use of it:

Putting a dependency a in the propagatedBuildInputs of derivation b has two main effects:

  1. It treats a as a dependecy of b, just as if you had buildInputs = [ a ]; in b
  2. It “propagates” this dependency relationship onwards to all derivations that depend (directly or transitively) on b

For example, if you have a derivation c with b specified as a buildInput, the underlying nixpkgs machinery will ensure that c also effectively has a as a propagatedBuildInput, meaning it gets a as a direct dependency (available in its builder) rather than simply depending on it transitively (as a result of b being built with it).

As a is effectively added to c's propagatedBuildInputs, anything that depends on c will also get a added to their own propagatedBuildInputs. The overall effect is that anything that has b anywhere in its dependency closure gets a direct dependency on a (at least if we ignore cross-compilation cases).

This effect is used in several ways in nixpkgs and NixOS. A few of the language-specific infrastructures make use of it to ensure that executables have access to their run-time dependencies.

For example: Python library/module dependencies are specified as propagatedBuildInputs, and the Python mkDerivation wrapper (buildPythonPackage) wraps any Python executable scripts produced by it to give them references to the paths of all their Python dependencies. This ensures that Python scripts have access to their full (Python) dependency closure at run-time, which is necessary because it is an interpreted language.

For the languages-specific infrastructures that do this, propagatedBuildInputs can also be seen as “a list of dependencies that need to be available to $lang scripts at run-time”.

12 Likes

Thanks, this did indeed solve my problem!

@Shados This is a really great explanation. Thanks for taking the time to write this!

  1. It “propagates” this dependency relationship onwards to all derivations that depend (directly or transitively) on a

I guess this should be "derivations that depend (directly or transitively) on b"?

any propagatedBuildInputs in the dependency closure of a profile will also find their way into the profile’s paths.

The net effect is that propagatedBuildInputs can also be seen as a list of “dependencies that need to be available at run-time”.

I think this is the part I was really missing! This makes total sense, and I can see how useful it could be when writing derivations!

In general nix requires a lot of upfront investment to be efficient with it. Unlike guix a lot of things like generating arbitrary containers are relegated to 3rd party projects. For example using cntr to debug derivations is great but I’m not using it because it’s relatively hidden and forgot how to use it.

Some good old ones:

  • multiple installation instructions: nix-env -iA nixpkgs.hello vs nix-env -iA nixos.hello
  • too many channels; I think it’s confusing to have a nixos-* and nixpkgs-* channels.
  • channels don’t map to hydra jobset names. Eg nixpkgs-unstable is nixpkgs/trunk on Hydra.
  • nix-collect-garbage -d doesn’t clean the old /boot entries. This affects everyone using NixOS.
7 Likes

Are you sure about this? I thought we needed to use propagatedUserEnvPkgs for that, otherwise I do not see why would it exist.

For Python libraries, I think they are included in the runtime closure by buildPythonApplication, not that they are picked up from profile.

Edit: In my mental model, the profiles are managed by Nixʼs buildEnv which is different from Nixpkgsʼs so I do not see how it would know about Nix specific features like propagated build inputs.

Edit2: Thinking about that, Nix would have to know about propagatedUserEnvPkgs as well. And looking at the source code, it seems to. I see no such case for propagatedBuildInputs.

Edit3: Really, being a derivation is not anything magical. Rather Nixʼs derivation is rather useless by itself. There is a lot of orchestration done by the generic builder used by default by stdenv.mkGeneration which adds lot of data used by other such derivations instrumented by it. Look at Nix pills to learn how it works.

For what it’s worth, specifically for Rust there is the Mozilla overlay, which is (more or less) feature-equivalent to rustup where Rust tooling is concerned. It does unfortunately also suffer from a bit of a lack of documentation.

I have never heard of this. Where do I find more information about it?

1 Like

I do need to try that. Do you know who would be the proper folks for me to contact? I keep wanting to contribute to nixpkgs, but I’m really intimidated.

As a preface to my comments, I really like NixOS and have championed it with others. But there are some things that could use some devoted attention:

  • nix-env -qaP is too slow. There are other tools being proposed but none of them are canonical and promoted in the manual.
  • A more complex search capability for packages and options is needed. Many searches return too many results to sort through efficiently. This is especially important given that the packages/options documentation are huge lists without any structure.
  • I’ve used NixOS for a couple of years but I am still tripped up by the sub-categories, like vimPlugins, gnome{2,3}, python{27,37}Packages, etc. Having hierarchical namespaces isn’t bad but the tools/docs for easily using them are lacking. (It should be possible to automatically generate a drop-down menu of the sub-spaces to support more sophisticated searches for example.)
  • Configuring emacs and extensions is still a pain and I can’t figure out how to do it well. (There are other packages as well.)
  • Documentation, documentation, documentation! :slight_smile: It seems like there are docs for getting started and docs supporting “power users” but very little in the middle. Especially for those of us who like and use NixOS but for whom our day job is something else so we won’t become power users anytime soon (without help).
3 Likes

I may not be your best offer, but you are much welcome to contact
me :-).

1 Like

Sometimes you can use builtins.unsafeGetAttrPos in the REPL to find them, though often what you actually find is a trivial wrapper.