Create an offline C development environment

I have a set of development vagrant VMs which traditionally have been provisioned using ansible which I am trying to port to nix and nixos-generators for all the normal nix reasons (reproducability, fine-grained control of package versions, etc). The end use of these VMs is to provide a C/C++ development environment which will run on a Windows host, but disconnected from the internet.

My current approach has been to install the desired tools system wide in the VM’s system.environmentPackages. This has mostly worked, but I’ve hit a roadblock getting tools like gcov which are available in a nix-shell -p gcc but not when gcc is added to system.environmentPackages. Somewhat less of an issue for me currently, but this approach also does not allow me to link against “system” libraries.

@lovesegfault @adisbladis on IRC suggested that I need to somehow build an offline nix-shell (thanks again for your help! I’m re-posting here because this is a little more async, and my work/life schedule isn’t allowing much access to IRC at the momement). The first approach attempted for doing this was to add a mkShell “package” to my system.environmentPackages per their suggestion like below:

( (mkShell{ buildInputs = [gcc]; }).overrideAttrs(_: {nobuildPhase = "touch $out";}) )

Unfortunately, this leas to the following error when building the VM:

The store path /nix/store/6lni8hzpqbbgiq6hwnda5cnlrv79fp88-nix-shell is a file and can't be merged into an environment using pkgs.buildEnv! at /nix/store/ line 109. 

I’ve also tried adding gcc-unwrapped to my systemPackages. This makes gcov available, but the gcc it provides doesn’t work (I haven’t looked into it extensively, but I think that without the wrap it doesn’t have a stdlib).

I’ve also since tried to do a similar thing to mkShell with a buildEnv like below, which I add to my systemPackages:

gccEnv = ( (pkgs.buildEnv rec{ name = "gccEnv"; paths=buildInputs; buildInputs = [pkgs.gcc]; }) );

This results in a working VM, but the gccEnv directory in the nix-store only has what I would get with gcc in systemPackages, so things like gcov are not included.

Are there any other approaches to producing an offline C development environment with NixOS? Is there some sort of override I need to supply gcc to get it to spit out gcov (I’ve been able to manage overrides for simpler packages but the expression for gcc is a bit over my head :slight_smile: ). I realize this use case is not completely typical, but I don’t think it’s that insane either?

Greatly appreciate any ideas and help!

If you mean by offline C development mean that you environment is not garbage collected you can also look at approaches like
An alternative approach would be using this: Caching nix shell build inputs - NixOS Wiki

Notice that nix-shell usually also sets a number of environment variables that gcc needs to find header and library files as documented here: C - NixOS Wiki

1 Like

Thanks for the suggestions.

I tried adding the inputDerivation attribute from my mkShell to my systemPackages, but I seem to get a similar error as before about nix-shell being a file which can’t be merged with buildEnv.

My hope was that the eventual solution could be described in a configuration.nix which would define how to build the nix-shell and add it to the VMs store automatically. Unless I’m missing something, the other approaches I see in those links seem to all involve a set of shell commands I could run manually in the VM - which would be disappointing since it somewhat defeats the purpose of defining the VM with nix. Is this accurate, or am I missing a way to incorporate this into configuration.nix?

So I’m still tinkering with this on and off.

I came across myEnvFun function which doesn’t seem to be documented in the manual, but in the couple simple tests I’ve done so far seems to work (although it looks like it’s missing nativeBuildInputs).

Is this a good approach for my use case? It seems like nix-shell is obviously more actively used and better supported, but I have not yet found a way to cache a nix-shell at build time.

Yes, this is a good solution for your approach. But I do wonder about your approach.

Why do you want to fix your development environments in your system configuration, instead of having your development environments defined in the folders for each of your projects? You mentioned you need an “offline” environment. As soon as you have downloaded the artifacts once, and have an out-link, they’re there and won’t be garbage collected. You just need to make sure the evaluation leads to the same derivations, and hence you need to pin your inputs (such as nixpkgs). In that case having a flake for each project seems preferable to me.


Well, obviously I would prefer to have a shell.nix per project. However, the underlying context is I’m trying to build this environment into a VM once, then move it to a closed network to be used. I’m pretty comfortable with pinning nixpkgs, but building it as a VM is not really about reproducibility per-say, it’s about being able to move this environment to a Windows host on the closed network and run it there.

The first attempts were to cache shell.nix before moving the VM so that I could run nix-shell offline and all the necessary artifacts would be there. However, none of the suggested approaches to do this work declaratively in configuration.nix, they would all involve some secondary operation to force caching of the artifacts which I thought kind of reduces the value of using nix for this.

You will also be interested in GitHub - nix-community/nixos-generators: Collection of image builders [maintainer=@Lassulus] in which you can target many vm platforms with a configuration.nix

1 Like

Yes, in fact I’m using exactly that! I actually currently have an some questions with the current implementation of the vagrant-virtualbox target that I should update. It looks like that thread got buried here or was otherwise just not seen by the people using nixos-generators so maybe I should open a GitHub issue. I started here because I wasn’t sure if I was doing something incorrectly.

I think the devshell project provides a buildable development environments. It’s still a quite new project. There is also a module for C as well.

1 Like

Oh nice, thanks for pointing out devshell - I hadn’t come across that. I don’t have my full environment in it yet, but I’ve kicked the tires a bit and it seems pretty promising!

I’m marking this as solved, because after working with devshell for a while it does pretty much everything I need it to. There are a few rough edges to still work on for sure, but it seems like a good path forward. Thanks for the tip @mic92!