Using an externally-provided C compiler

Hello all,

I have a project which I need to build using a specific C compiler (not available on nixpkgs, but just a specific version of GCC). I’ve created a derivation which builds this compiler (as newCompiler in the example below), but I’m having some trouble bringing it in to the project derivation. In line with the instructions here: C - NixOS Wiki, I’ve tried the following:

getThisStdenv = { pkgs, ... }: with pkgs; (overrideCC stdenv newCompiler);
pkgs = import nixpkgs {
  system = "x86_64-linux";
  config.replaceStdenv = getThisStdenv;
};

If I then try to build, I get errors like the following:

{ bintools, libc ? if stdenv.targetPlatform != stdenv.hostPlatform then libcCross else stdenv.cc.libc

It seems that stdenv.cc is expected to have some specific set of attributes (libc, cc, targetPrefix etc), which makes me feel that my naive approach is probably not going to work.

Is there either:

  1. Some way to wrap the newCompiler package so that it works as expected - I notice there’s a cc-wrapper.nix, but how to use it isn’ clear to me, or
  2. Some way to hack this, ie using stdenvNoCC.mkDerivation but then stating CC = ${newCompiler}/bin/gcc in the derivation?

Thanks for any help!

This looks like a cross-compiling-scenario to me, even if you end up using the same arch.

https://matthewbauer.us/blog/beginners-guide-to-cross.html

Look at how the cross-compiling targets are defines and probably add one that uses your compiler.
Then packaging is as usual…

Other useful things:

Thank you. To check my understanding, before I get too deep into these links, I am not looking to do cross-compilation in the sense that I’d normally understand it. The build machine and host machine will both be x86-64_linux, and the compiler I’m trying to use is the same. Is your advice consistent with that?

If you need to make sure all dependencies are also compiled with newCompiler, I’d suggest to use the cross-compilation-framework to benefit from the abstraction.

If it is only a single package, the quickest way might be to start from stdenvNoCC and bring in newCompiler as build dependeny as reported here.

For something in between, see the Wiki on how to construct a stdenv with a custom C compiler using overrideCC.

Thanks! I ended up going with the second approach - in case it’s useful to anyone, my flake.nix now has:

    thisSystem = "x86_64-linux";
    getThisStdenv = { pkgs, ... }:
      with pkgs;
      let
        newCompilerWrapped = wrapCCWith {
          cc = newCompiler;
          bintools = wrapBintoolsWith {
            bintools = binutils-unwrapped;
            libc = glibc;
          };
        };
      in
        (overrideCC stdenv newCompilerWrapped);

    pkg = import nixpkgs {
      system = thisSystem;
      config.replaceStdenv = getThisStdenv;
    };