Search code examples
gccnix

Nix and GCC - `cannot find crt1.o`


I'm running Nix on WSL with Ubuntu 18.x.

I installed GCC with $ nix-env -i gcc which installed gcc-7.3.0.

I'm trying to use GCC to compile a simple CPP file (generated by Ferret). But GCC is coming up with the following error:

$ g++ -std=c++11 -x c++ test_1.cpp -o test_1
/usr/bin/ld: cannot find crt1.o: No such file or directory
/usr/bin/ld: cannot find crti.o: No such file or directory
collect2: error: ld returned 1 exit status

It seems that I expected Nix to include common dependencies along with GCC (build-essential equivalents), which I assume is not true.

Searching using Nix (nix-env -qaP 'gcc', nix-env -qaP --description | grep -i gcc) doesn't provide much help.

Other posts mention installing gcc-multilib (apt package). The only mention of that in Nix are testing packages:

$ nix-env -qaP --description | grep -i multilib
nixpkgs.tests.cc-multilib-gcc                                            cc-multilib-test                               
nixpkgs.tests.cc-multilib-clang                                          cc-multilib-test

I'm at a loss as to how to get a build environment working. I cannot find any documentation as to what packages I need to get going. This is pretty simple stuff.


Solution

  • In short, things are done differently with Nix. Instead of installing tools and libraries like you'd do with most distros, when using Nix you create a "Nix expression" which declares your build dependencies and instructions for compiling your program. For example, say you have a hello.cc with this source code:

    #include <iostream>
    using namespace std;
    
    int main() 
    {
        cout << "Hello, World!";
        return 0;
    }
    

    To compile it with Nix you can use a default.nix file (in the same directory) like this:

    let
        pkgs = (import <nixpkgs>) {};
        gcc = pkgs.gcc;
        stdenv = pkgs.stdenv;
    in
        stdenv.mkDerivation {
            name = "hello";
            version = "1.0.0";
            src = ./.;
            phases = [ "unpackPhase" "buildPhase" "installPhase" ];
    
            buildPhase = ''
                ${gcc}/bin/g++ -std=c++11 -x c++ hello.cc -o hello
            '';
    
            installPhase = ''
                mkdir -p $out/bin
                cp hello $out/bin
            '';
        }
    

    ...which you can build like this: nix build

    You'll end up with a ./result symbolic link which points to the $out directory used above. The installPhase above copies the binary to $out/bin, so the program can be executed by running ./result/bin/hello

    The Nix language is described in its documentation and you can get an overview of how to use it to build things from the Nixpkgs documentation.