How to cross compile using buildGoModule?

Go supports use of GOOS and GOARCH parameters to cross-compile binaries.

I’m trying to cross-compile using buildGoModule like this:

pkgs.buildGoModule {
  pname = "example";
  version = "1.0.0";
  inherit src;

  GOOS = os;
  GOARCH = arch;
}

But what happens is it just builds for my current architecture.

When I look at the buildGoModule derivation I can see that args are passed to the build:

Bu then they are overwritten by values from go. And they take precedence since // used to merge attribute sets. So how exactly is one supposed to cross-compile using this derivation?

As far as I understand, pkgsCross, as any other XC scenario as well.

But wouldn’t that pull in all of the build dependencies for that given platform? That doesn’t make sense. Why would I need to pull whole stdenv all other dependencies when I can just cross-compile with the Go compiler I already have. Seems silly and unnecessary.

You need all the buildInputs for the target platform anyway. That is exactly why you should use pkgsCross!

No you don’t. You can cross-compile with Go compiler without that.

That might work on regular systems. Where you then have to install dependencies manually on the target host.

Though nix doesn’t build the executable in isolation, it wants to build the full closure.

No, I don’t think you understand. The Go compiler can cross-compile, it doesn’t matter what platform it was built for.

You do not understand.

Anything mentioned in buildInputs (whether you need that feature or don’t need it) needs to be available.

The dynamic linker is part of this, that you do not add it explicitely doesn’t matter, it is still required unless you use pkgsStatic, which again is yet another beast.

A default Go library is build under the assumption by the go compiler, that it will find the dynamic linker at /lib64/ld-linux-x86-64.so.2 or something. This is not a valid location for nix, this is why nix builds the full closure.

Why do you assume I want to build a binary for use within NixOS?

Where did I say “nixos”? I said nix.

Why do you assume I want to build a binary for use within Nix?

Because you use nix to build it.

Nix has the same assumption as I have.

If you do not want to build something for nix, do not build it with nix.

What kind of silly idea idea that. Nix is an extremely good build tool that’s used by many projects to build things not intended for use within Nix ecosystem. You can not use it for that if you’d like, but plenty people do use it like that.

1 Like

I have never seen nix being used to create something that can be used without the nix ecosystem (ignoring that projects like nix-bundle exist, which just hide the nix store within a container like thing or proots)

Here’s one that uses Nix to build android APKs:

nixpkgs, however, is not designed for this usecase, unless you count bundling-style solutions that use a container with a /nix/store at runtime. You’ll probably need to leave most of nixpkgs’ helper code behind if you want to get results that don’t expect a /nix/store on the deployment target.

Perhaps it is was designed with that purpose in mind, but it certainly is a good build tool, and can be made used like that.

1 Like

It definitely can be used that way, but you’re going to need to stop using nixpkgs convenience functions and look at using the underlying derivation keyword from nix itself. See the nix manual. Also, you may want to make use of the allowedReferences attribute to ensure that you’re not accidentally holding onto any nix store references.

Also, although you can, of course, use build-time-only dependencies from nixpkgs, any runtime dependencies you’re on your own for.

2 Likes

Maybe you could try make a PR to change the buildGoModule helper, to not inherit the os/arch from go, but take them from args or fallback to the ones in go.

1 Like

stdenv was designed with that purpose in mind.

Anything that is build on top, inherits this purpose and mindset.

If you want to build something else, you need to write your own builders based on builtins.derivation.

You need to throw away a lot of convenient abstractions, that all are based on the assumption to stay within nix.

What remains left for you, is to use what is in nixpkgs as an equivalent of nativeBuildInputs, at least those that are unwrapped. Or if they are wrapped use the unwrapped originals, and wrap them on your own to still be able to find stuff provided by nix, but produce FHS compatible.

As much as I dislike docker, but to be honest, I think using docker will be much easier and therefore much cheaper!

2 Likes