Adding custom package

I would like to add several custom packages to my configuration.nix file to create a custom OS.

According to the "Adding Custom Packages’"wiki, I should be able to do the following:

Create a ‘custom-package.nix’ in this case the my-hellow.nix file:

with import <nixpkgs> {}; # bring all of Nixpkgs into scope
stdenv.mkDerivation rec {
  name = "hello-2.8";
  src = fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6";
  };
}

And then the construction/inclusion by doing the following, which should build and execute the 'hello world package.

$ nix-build my-hello.nix$ ./result/bin/hello
Hello, world!

I’m getting the following error when I execute the above:

ix-build my-hello.nix ./result/bin/hello
error: getting status of '/home/talos/projects/custom-nix-package/result/bin/hello': No such file or directory

Can someone explain why and how to fix it?

Thx!

You would probably be interested in: Simple C program - Nix-Book

Or my video: https://www.youtube.com/watch?v=LiEqN8r-BRw

@jonringer Thanks for the pointers.

I was able to code up your ‘hello-world’ example from a combination of both your video and the Simple C program - Nix-Book reference. Thx.

I was also able to get the ‘my-hello.nix’ example working as documented on the Adding Custom Packages wiki – albeit with some minor scoping modifications.

I changed it from this:

with import <nixpkgs> {}; # bring all of Nixpkgs into scope

stdenv.mkDerivation rec {
  name = "hello-2.8";
  src = fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6";
  };
}

To this (not the addition of the ‘pkgs’ to both the 'pkgs.stdenv.mkDerivation ’ and the ‘pkgs.fetchurl’ ):

let 
  pkgs =  import <nixpkgs> {}; # bring all of Nixpkgs into scope
in
pkgs.stdenv.mkDerivation rec {
  name = "hello-2.8";
  src = pkgs.fetchurl {
    url = "mirror://gnu/hello/${name}.tar.gz";
    sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6";
  };
}

Ironically, I noticed that in your video, you also bumped up against this same scoping issue and the use of the ‘with’ keyword.

I’m not sure I still completely understand the implications of the ‘with’ keyword and when or when not to use it.

If you can explain and/or point to a source that better defines the use of ‘with’ that would be much appreciated.

Now, I’m moving on to fetching a pre-built binary package for inclusion. Hopefully, that process is a simple. :slight_smile:

There’s an example: Language Basics - Nix-Book

1 Like

I’m in the camp of “never use it”, and I’m not alone there. Making the variable binding structure dependent on runtime data has some pretty strange consequences and is best avoided in most situations.

The main uses that seem to be considered acceptable in the wild are:

  • with lib, which refers to a very well known attrset, which rarely changes.
  • when it’s in front of a very simple expression, like a list, especially if it’s with pkgs.

Beyond that, it’s at least a little iffy in most people’s minds.

There are alternatives, like

let
  inherit (someattrset) foo bar baz;
in

which makes the source of specific variables much clearer.

1 Like

@jonringer @tejing Thanks for your feedback on the use of ‘with’. For now, I’m going to avoid it until I have time to investigate it further.

To follow up on my previous question, our CI/CD pipeline currently builds several custom applications and packages them up as zip files (including all their dependencies) for a variety of OSes (Windows, Linux and Mac).

We’d like to leverage this environment as-is, and download and install these custom applications into a NixOS.

Is this supported? What would be the proper ‘nix-way’ of accomplishing this task?

We’ve worked thru the ‘hello-world’ examples cited in the docs, however, these examples illustrate use the ‘stdenv’ which is designed to build (compile), package and install a package – not install a prebuilt package.

We’re currently doing the following, which works, but …

let 
  pkgs =  import <nixpkgs> {}; # bring all of Nixpkgs into scope
in
pkgs.stdenv.mkDerivation rec {
  name = "custom-app";
  version = "1.0.0-alpha-20221003.2";
  src =  pkgs.fetchzip {
    url = "http://192.168.1.11:8000/custom-app-1.0.0-alpha-20221003.2.zip";
    sha256 = "sha256-Bj2Ea65ohBw0ToMaKruO7iUv9AC+tfd8407dWGLpaRg=";
  };

  dontConfigure = true;
  dontBuild = true;

   installPhase = ''
      mkdir -p $out/bin
      cp -r $src  $out/bin/custom-app
    '';
}

Thanks.

Usually you’ll want to use fetchurl and have stdenv unpack the zip file (which will happen automatically so long as you put unzip into your nativeBuildInputs). The reason to use fetchzip is if the zip file is auto-generated on the fly on the server, and thus doesn’t have a stable hash. fetchzip fixes this problem by unpacking before the hash is checked, so the hash is of the contents instead.

You also don’t usually actually need dontConfigure and dontBuild for something like this, since if there’s no obvious way to accomplish those phases (no configure script, no makefile), stdenv will just do nothing and move on.

Generally speaking, for packaging precompiled binaries, you may also need to use autoPatchelfHook to encode the path to a proper ELF loader and proper libraries, though it sounds like here your binaries are static so it may not be necessary.

Otherwise, you’ve got the gist. You still use stdenv for precompiled stuff, just not all of it.

I am also quite new to nix, but I think there has been a small mistake in the docs
The line $ nix-build my-hello.nix$ ./result/bin/hello should have been split into two lines:

$ nix-build my-hello.nix
$ ./result/bin/hello

Running it like this, worked on two of my machines!

1 Like