Working on compilers in NixOS

Hi all, I’ve tried a couple times to use NixOS, but I’ve found that it’s quite hard to use NixOS on the projects I tend to work on.

For example, if I compile LLVM and clang locally so I can make some patches to them, then the resulting compiler won’t have been wrapped like the clang packages in nixpkgs and so won’t be able to find the libcxx include paths (or other things that are normally in system include paths). This all happens in a pure nix-shell environment that has all the build dependencies I need.

I asked on IRC about this, and it was suggested that I manually replace the clang binary in my build folder with a wrapper script like that of the wrapped clang packages. However, I don’t feel that this is an elegant solution.

The script will be replaced whenever I rebuild (if it is named clang and I move the binary to clang-unwrapped or something like that). As all of the test suites will execute the clang binary directly, a script that lives as a sibling to the clang binary isn’t feasible either. Further, as I want to be able to iterate, re-build and test within the nix-shell with different commands and flags, I don’t want to have to specify these in the default.nix file and do all building and testing through that, so that I can call wrapCC.

While my use case isn’t common, I feel it is an area where there the Nix tooling makes working on a project much harder and less streamlined that it would be in other distributions (I otherwise love Nix for other projects, this is certainly an outlier). I was wondering if anyone had any suggestions for better solutions to this problem (if Nix can already handle this elegantly), or any ideas for how the Nix tooling could make this problem easier to solve?

Thanks.

5 Likes

Is there any way to tell clang where the sysroot is via environment variables? Could just set such variables in shell.nix (and make sure to not introduce them in the regular nix build).

EDIT: Or maybe the default sysroot location can be set during configure time?

I regret to inform you that the majority of the compilers in Nix, and many of the applications are operated by wrappers. After poking your nose around the packages for a while you will find there are a handful of problems, especially with older stubborn languages, that are just easier to manage through wrappers.
You use them constantly probably without even realizing it because they have overwritten the name of the original program. (This is likely a fix for your testing concern).
Take a crack at writing one, you might find that there are elegant ways to handle it.

Maybe buildFHSUserEnv would be helpful for you.

I can’t find any environment variables or build time options for setting the default sysroot. But you could make a wrapper script that you can point to a dev binary

$ wrapper ./build/bin/clang ...

We could even modify wrapCC in nixpkgs to support using the proper wrapper script with pluggable compilers / libcs / binutils.

I am using something ressembling the following shell.nix to create a environment with custom version of gcc48.
It is based on officlal <nixpkgs> once, where I add (with an overlay) a new package inherited from gcc48, and I change some configure flags and add some patches.
In reality, you maybe want to pin <nixpkgs> to a specific revision.
Overlay can be extracted to ~/.config/nixpkgs/overlays/, if you want to install your custom compiler outside of nix-shell.

let
  my-pkgs = import <nixpkgs> {
    overlays = [
      (self: super: with self; {
        my-gcc = lowPrio (wrapCC (super.gcc48.cc.overrideAttrs(old: {
          configureFlags = old.configureFlags ++ [
            "--disable-shared"
            "--disable-multilib"
            # add the flags you want to pass to configure
          ];
          patches = old.patches ++ [
            # add the patches you want to apply
          ];
        })));
      })
    ];
  };
in
my-pkgs.stdenv.mkDerivation {
  name = "my-env";

  buildInputs = with my-pkgs; [
    my-gcc
  ];
}

Apologies for the delay in responding, it took a while for me to get an opportunity to set up a new NixOS system to experiment with, I appreciate everyone’s responses.

This would be ideal for running the compiler manually, but unfortunately, as it will be invoked by test suites and other tools, I wouldn’t be able to make sure that those tools also prepend the wrapper script.

Thanks! This seems promising. I’ve done some local experimentation and this seems like it’d work, the only issue I’ve ran into is that the headers in ${glibc}/include don’t get put into /usr/include, other packages like libcxx do seem to have their headers put into /usr/include.

Hey, are you still working on this? If so, you could try adding glibc.dev to your targetPkgs, or try adding "dev" to extraOutputsToInstall.

I’m currently also trying to use a buildFHSUserEnv, but I’d like it to work with gcc-unwrapped. If you have time I’d be super happy if you could take a look: Using a "raw" `gcc` inside `buildFHSUserEnv`. Thanks anyway!