Search code examples
swiftgccnixos

How to build Swift project on NixOS?


I'm trying to build a simple Swift project on NixOS. Here are the steps to reproduce:

git clone https://github.com/PerfectlySoft/PerfectTemplate.git
cd PerfectTemplate
touch shell.nix

Add shell.nix with following contents:

with import <nixpkgs> {};

stdenv.mkDerivation {
  name = "swift-env";

  buildInputs = [
    openssl
    stdenv
    binutils
    cmake
    pkgconfig
    curl
    glibc
    icu
    libblocksruntime
    libbsd
    libedit
    libuuid
    libxml2
    ncurses
    sqlite
    swig
  ];

}

Running nix-shell --pure shell.nix and from there swift build, gives me:

gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: unrecognized command line option ‘-target’
gcc: error: x86_64-unknown-linux: No such file or directory
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: unrecognized command line option ‘-fblocks’
gcc: error: unrecognized command line option ‘-target’
gcc: error: unrecognized command line option ‘-fmodule-name=PerfectCZlib’
gcc: error: unrecognized command line option ‘-fmodules’; did you mean ‘-fmudflap’?
gcc: error: unrecognized command line option ‘-fmodules-cache-path=/home/dmi3y/Dev/Swift/PerfectTemplate/.build/x86_64-unknown-linux/debug/ModuleCache’
gcc: error: unrecognized command line option ‘-fblocks’

I'd appreciate any help with this as I'm pretty much new to nix-shell and NixOS.

EDIT:

I changed my shell.nix to this:

{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  name = "swift-env";

  buildInputs = with pkgs; [
    openssl
    clang
    swift
  ];

  shellHook = ''
    CC=clang
  '';
}

However, when I run nix-shell followed by swift build, I'm now getting:

[1/25] Compiling PerfectCZlib zutil.c
[2/25] Compiling PerfectCZlib uncompr.c
[3/25] Compiling PerfectCZlib inftrees.c
[4/25] Compiling PerfectCZlib inflate.c
[5/25] Compiling PerfectCZlib trees.c
[6/25] Compiling PerfectCZlib inffast.c
[7/25] Compiling PerfectCZlib infback.c
[8/25] Compiling PerfectCZlib gzwrite.c
/nix/store/iz6k7x3l14ykr56crz3dizas1rrkcyzr-clang-wrapper-7.1.0/resource-root/include/module.modulemap:24:8: error: redefinition of module '_Builtin_intrinsics'

#  warning _FORTIFY_SOURCE requires compiling with optimization (-O)
   ^
1 warning and 3 errors generated.
1 warning and 3 errors generated.

Full log can be found here.

This is now looks like a missing library dependency or a version conflict.

For the record, here's additional information about my setup that might shed more light:

$ nix-channel --list                                                    
home-manager https://github.com/rycee/home-manager/archive/master.tar.gz
nixos https://nixos.org/channels/nixos-19.09  

$ nix-shell --run 'swift -version'                                      
Swift version 5.0.2 (swift-5.0.2-RELEASE)
Target: x86_64-unknown-linux-gnub

After searching the web I found a Jira issue for Swift compiler and this specific comment. I decided to exclude clang from dependencies and only include swift, since this combination seem to be conflicting:

{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  name = "swift-env";

  buildInputs = with pkgs; [
    openssl
    swift
  ];

  shellHook = ''
    CC=clang
  '';
}

And that worked! I was finally able to build the project!


Solution

  • Since your using the --pure option, nothing from your previous environment will be imported into the shell. This includes the swift binary itself. So first I would add swift to the buildInputs.

    The error your getting indicates that gcc doesn't even understand the command line options being passed. I don't know anything about Swift, but after seeing that I assumed that it needs a different compiler. Sure enough, after a quick search it looks like it is llvm based. You will thus need to also add clang to your build inputs. In addition, you'll need to use mkShell instead of mkDerivation to setup the proper environment.

    The former is a wrapper to the latter that is specifically designed to set up a nix-shell, and ensures the environment is handled correctly. You'll need to pass in the shellHook attribute to override the default c compiler to clang using the CC envvar. The shellHook is a way of running arbitrary commands at the start of the shell.

    As a final note, the nix-shell command searches for shell.nix by default so you don't have to pass it as an argument. If shell.nix does not exist, then it will try default.nix. If neither exist, then you'll have to explicitly specify the nix expressions location.

    TLDR

    to put it all together:

    # a more idiomatic way to import nixpkgs, overridable from the cmdline
    { pkgs ? import <nixpkgs> {} }:
    pkgs.mkShell {
      name = "swift-env";
    
      buildInputs = with pkgs; [
        # your other inputs
        clang
        swift
      ];
    
      shellHook = ''
        CC=clang
      '';
    }
    
    

    Just to be sure my logic was correct I downloaded the repo and gave it go. Everything compiles and runs successfully.