2019-01-24
I’m new to Nix. I’m experimenting
with moving a bunch of development environments to Nix. Part of that is
rubygems, for which we’re using bundix
.
Yesterday, after I taught Bundix how to fetch gems from a private gemserver, I ran into a compile error on one gem (gctrack). Here’s the especially-relevant part of the error:
compiling gctrack.c
gctrack.c:26:7: warning: implicit declaration of function 'clock_gettime' is invalid in C99 [-Wimplicit-function-declaration]
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
^
gctrack.c:26:21: error: use of undeclared identifier 'CLOCK_MONOTONIC'
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
^
1 warning and 1 error generated.
make: *** [Makefile:242: gctrack.o] Error 1
I found this issue on nixpkgs that describes pretty well this exact issue, but without resolution. I’m not sure I’m going to be able to fix this, but I’ll at least document here my attempt to get to the root cause.
default.nix
with import <nixpkgs>{};
let
gems = bundlerEnv {
name = "shopify";
ruby = ruby_2_5;
# nix doesn't really parse these so I'm cheating for this example.
gemfile = ./gemset.nix;
lockfile = ./gemset.nix;
gemset = ./gemset.nix;
};
in
stdenv.mkDerivation rec {
name = "shopify";
buildInputs = [ gems ];
}
gemset.nix
{
gctrack = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1sn5f753lff1kap8dg3msf920p6cnm75q83i7929k3jvqdjzmz0d";
type = "gem";
};
version = "0.1.0";
};
}
Success (or failure): running nix-shell .
gives me the
same failure. Now I want to get bundlerEnv
out of the way
and get gemset.nix
integrated into default.nix
somehow.
I cloned nixpkgs
and
searched it for “bundlerEnv =”, and got:
pkgs/top-level/all-packages.nix
8069: bundlerEnv = callPackage ../development/ruby-modules/bundler-env { };
This points to …/bundler-env/default.nix.
At a really quick read, it kind of looks like it’s just a wrapper around
basicEnv
, but that doesn’t exist in the top-level namespace
so I’m not totally sure how to get at it. Still, I can see that
basicEnv
comes from bundled-common
.
Looking at this file, I don’t see a super easy way to hook into this, or any obvious place that I might want to, but I do spot a function call that seems interesting:
buildGem = name: attrs: (
let
gemAttrs = composeGemAttrs ruby gems name attrs;
in
if gemAttrs.type == "path" then
pathDerivation (gemAttrs.source // gemAttrs)
else
buildRubyGem gemAttrs # <---- this
);
…and searching the top-level does actually turn something up:
$ ag 'buildRubyGem =' pkgs/top-level
pkgs/top-level/all-packages.nix
8065: buildRubyGem = callPackage ../development/ruby-modules/gem { };
There must be a nix command for this. It seemed like
nix-env
might work but I guess buildRubyGem
isn’t a derivation:
$ nix-env -qaPA nixpkgs.firefox
nixpkgs.firefox Firefox-64.0.2
$ nix-env -qaPA nixpkgs.buildRubyGem
error: expression does not evaluate to a derivation (or a set or list of those)
Alright, this is looking like where the gem install is actually happening.
I guess what I’d really like to be able to do here is:
bundlerEnv
; and/ordefault.nix
.For the latter, the gem build is actually its own derivation, so we can just extract it from the store. From the error output:
builder for '/nix/store/nlrp8pbf0y32zp63hbi5k9s0fhiwqrag-ruby2.5.3-gctrack-0.1.0.drv' failed with exit code 1
If I cat $that_file
, I get… a technically-readable but
kinda difficult mess. I think I remember there being a command for this,
and found it:
$ nix show-derivation /nix/store/nlrp8pbf0y32zp63hbi5k9s0fhiwqrag-ruby2.5.3-gctrack-0.1.0.drv
This actually looks useful: https://gist.github.com/burke/a1f1f5838691d4e221027ff4113662ea
So this is an interesting thing to realize a little quicker next time: I can get closer to the root of a failure by just checking the log for the actual derivation path that failed.
I understand from that GitHub issue way back that the issue has
something to do with the impurely-sourced libSystem
, which
I can see in the derivation:
"__impureHostDeps": "/bin/sh /usr/lib/libSystem.B.dylib ...",
And finally I can sort-of-minimally reproduce that error by running:
nix-build /nix/store/nlrp8pbf0y32zp63hbi5k9s0fhiwqrag-ruby2.5.3-gctrack-0.1.0.drv
So that issue mentioned that it’s a mismatch between
libSystem
and whatever headers are available. If we have
the library available as an impure input, we probably need some sort of
explicit buildInput
for the headers, and we don’t seem
to:
nix show-derivation /nix/store/<hash>-ruby2.5.3-gctrack-0.1.0.drv| grep uildInputs
deactivated shadowenv.
"buildInputs": "...-ruby-2.5.3 ...-hook ...-objc4-osx-10.11.6",
"nativeBuildInputs": "",
"propagatedBuildInputs": "",
"propagatedNativeBuildInputs": "",
I’m spending some time googling and whatnot to see if I can figure out what’s missing…