*Very* basic: How do I build a go package?

Hi,

I’d like to build a nix package for a go project.

I can find some examples about the contents of what should go into my file, but I have no idea what filename to use, what commands to run or how to include the package I end up building in my configuration.nix file. Could I get a couple of pointers to get me off the ground?

I’d like to create a nix package for this go-based executable:

which has a go.mod file in the root. go build works.

So I’m trying to follow

https://nixos.org/manual/nixpkgs/stable/#sec-language-go

(keep in mind, I’ve never built a package before let alone tried to create my own).

And it has this example:

{
  pet = buildGoModule rec {
    pname = "pet";
    version = "0.3.4";

    src = fetchFromGitHub {
      owner = "knqyf263";
      repo = "pet";
      rev = "v${version}";
      hash = "sha256-Gjw1dRrgM8D3G7v6WIM2+50r4HmTXvx0Xxme2fH9TlQ=";
    };

    vendorHash = "sha256-ciBIR+a1oaYH+H1PcC8cD8ncfJczk1IiJ8iYNM+R6aA=";

    meta = {
      description = "Simple command-line snippet manager, written in Go";
      homepage = "https://github.com/knqyf263/pet";
      license = lib.licenses.mit;
      maintainers = with lib.maintainers; [ kalbasit ];
    };
  };
}

Questions

I think I could figure out how to change that example to match github.com/m-manu/rsync-sidekick if only I had an idea what to do with that text to get the pet example to work.

  • Is the above example complete? If not, what is missing?
  • What file name should I put the file contents in?
  • What command should I run to test if it works?
  • Assuming I can get it to build, and put that file on github e.g. as my own package, how do I include that as a package in my configuration.nix?
  • Is this flake or old-school?

Also, under Obtaining and overriding vendorHash for buildGoModule, it suggests:

The following command gets the value of vendorHash for package pet :

cd path/to/nixpkgs
nix-prefetch -E "{ sha256 }: ((import ./. { }).my-package.overrideAttrs { vendorHash = sha256; }).goModules"

Uhm… What are path/to/nixpkgs and my-package? And do I even need this, if I use vendorHash = lib.fakeHash as suggested?

What I tried

Go - NixOS Wiki

I also looked at Go - NixOS Wiki which is very similar to the above and simply assumes even more that I already know what to do with buildGoModule.

Search for buildGoModule

Having no idea what to do with this text blob, I found

https://github.com/NixOS/nixpkgs’s pkgs/by-name/ff/ffuf/package.nix

Which also has this pre-amble in addition to a buildGoModule block:

{
  lib,
  buildGoModule,
  fetchFromGitHub,
  fetchpatch,
}:

So I downloaded ff/ffuf/package.nix as a local package.nix file, but then what? Neither nix-build package.nix nor nix build package.nix work.

Hacking Your First Package — nix-tutorial documentation

I tried following:

Hacking Your First Package — nix-tutorial documentation

and it has a chord_example.nix file. If I copy that into a chord_example.nix file and run nix-build chord_example.nix it does actually work. But nix-build package.nix from pkgs/by-name/ff/ffuf/package.nix above didn’t. Huh?

Lots of questions here, but that’s totally understandable!

If you’re looking at things in Nixpkgs, what you want to do is create a package file. A package file is just:

  • A .nix file (use any name you want)
  • …that contains a function expression with named parameters (these parameters should include any other packages or Nixpkgs functions that your package requires)
  • …that returns a derivation.

So, if you’re looking at that pet example, what you want to do is create a package.nix file that looks like this:

# First, the named parameters.
{
  # you almost always want to depend on lib
  lib,

  # these are Nixpkgs functions that your package uses
  buildGoModule,
  fetchFromGitHub,

  # more dependencies would go here...
}: # this means end of named parameters

# Now, the definition of your package.
# This should be something that produces a derivation, not
# a string or a raw attribute set or anything else.
# buildGoModule is a function that returns a derivation, so
# you want `buildGoModule ...` here, not `{ pet = ...; }` here;
# the latter is an attribute set.

buildGoModule rec {
  pname = "pet";
  version = "0.3.4";

  src = fetchFromGitHub {
    owner = "knqyf263";
    repo = "pet";
    rev = "v${version}";
    hash = "sha256-Gjw1dRrgM8D3G7v6WIM2+50r4HmTXvx0Xxme2fH9TlQ=";
  };

  # this hash is updated from the example, which seems to be out of date
  vendorHash = "sha256-6hCgv2/8UIRHw1kCe3nLkxF23zE/7t5RDwEjSzX3pBQ=";

  meta = {
    description = "Simple command-line snippet manager, written in Go";
    homepage = "https://github.com/knqyf263/pet";
    license = lib.licenses.mit;
    maintainers = with lib.maintainers; [ kalbasit ];
  };
}

Now create a second file called default.nix containing the following:

let
  # You could also pin Nixpkgs to a specific version here; that is not the
  # subject of today's lesson.
  pkgs = import <nixpkgs> { };
  # This empty attribute set is for parameters to Nixpkgs one might wish
  # to configure.
in
pkgs.callPackage ./package.nix { }
# And this empty attribute set is for providing dependencies or configuration
# parameters to your package file that aren't automatically selected from
# Nixpkgs. This callPackage call is kinda the same thing as writing:
#     import ./package.nix {
#       inherit (pkgs) lib buildGoModule fetchFromGitHub;
#     }
# but it automatically injects the named dependencies.

And to build your package, run nix-build default.nix.

If you prefer, you could shortcut the above two steps (and I frequently do) as follows:

nix-build --expr '(import <nixpkgs> { }).callPackage ./package.nix { }'

To use a local package file in your environment.systemPackages, include (with parentheses!):

(pkgs.callPackage path/to/your/package.nix { })

If you’re putting a repository of your custom packages on GitHub, the thing to do would be to create an overlay containing your package file, and then include that overlay in nixpkgs.overlays. A tutorial on that is probably a second thread.

Both. Where the flakes instructions would diverge is at the step of how to reference your overlay-containing GitHub repository, I think. (I don’t use flakes, so I’m not the best person to walk you through that if you want it.)

Nah, you are just fine if you start with fakeHash and then update it with the hash printed in the build failure message.

You should be able to use any of the same callPackage tricks on this package file and it will work—either create a second file that imports <nixpkgs> and invokes callPackage, or use the nix-build --expr shortcut.

Good luck!

2 Likes

Thanks for your answer. I got the pet example to work.

How on earth was I supposed to know any of that?

If I now try the
nixpkgs/pkgs/by-name/ff/ffuf/package.nix at 73d6cb7190ad6387f70dc90f955a80c6874af34d · NixOS/nixpkgs · GitHub example from before:

$ nix-build --expr '(import <nixpkgs> { }).callPackage ./package.nix { }'
error:
       … while calling the 'derivationStrict' builtin

         at /builtin/derivation.nix:9:12: (source not available)

       … while evaluating derivation 'ffuf-2.1.0'
         whose name attribute is located at /nix/store/1h99qq6970gkx3j0m9w4yrrl9y99y1nk-source/pkgs/stdenv/generic/make-derivation.nix:333:7

       … while evaluating attribute 'configurePhase' of derivation 'ffuf-2.1.0'

         at /nix/store/1h99qq6970gkx3j0m9w4yrrl9y99y1nk-source/pkgs/build-support/go/module.nix:175:5:

          174|
          175|     configurePhase = args.configurePhase or (''
             |     ^
          176|       runHook preConfigure

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: function 'anonymous lambda' called without required argument 'rev'

       at /nix/store/1h99qq6970gkx3j0m9w4yrrl9y99y1nk-source/pkgs/build-support/fetchgithub/default.nix:4:1:

            3| lib.makeOverridable (
            4| { owner, repo, rev, name ? "source"
             | ^
            5| , fetchSubmodules ? false, leaveDotGit ? null

None of the stack trace frames reference package.nix file that I have downloaded or the nix-build --expr parameter, not even if I run with the suggested --show-trace.

Nix does not make this easy.

I give up for now. It is 1:20 AM and bed time.

https://nix.dev/tutorials/packaging-existing-software
https://nix.dev/tutorials/callpackage

1 Like

The error you’re getting for ffuf is because there was an API change in Nixpkgs (to fetchGitHub, specifically) between whatever you have your nixpkgs channel set to and the commit you’re using for the ffuf package file. It’s not your fault; just unlucky. An earlier commit should work; try this one.

If one git clones all of Nixpkgs, which is what the experienced hackers generally do, one generally replaces <nixpkgs> with path/to/checked-out/nixpkgs in order not to experience this sort of problem.

1 Like

Thanks for that.

FYI, I’ve reviewed why I didn’t read these:

I started with a google search for how to create a go nixos package which doesn’t include any of these links, so I didn’t see them. It does include:

Go - NixOS Wiki whose first chapter is “Packaging go modules” which starts with:

The nixpkgs library function buildGoModule (implementation) works in most cases of packaging go modules or applications. See nixpkgs manual Language: Go

And I (falsely, it turns out) believed that the #sec-language-go section would point me in the right direction.

Upon review, the “Preface” chapter on the very first page of 874 pages does point to

To discover other kinds of documentation:

  • nix.dev: Tutorials and guides for getting things done with Nix

So reminder to self: Check out https://nix.dev in the future.