How to add a new cross compilation target?

I’m trying to build applications for Windows on Linux and I have the requirement that they should be compatible with Visual Studio, so the existing MinGW target won’t work.

I’ve figured out that I can download the proprietary msvc headers and libraries using msvc-wine.

After downloading those files and setting the NIX_CFLAGS_COMPILE and NIX_LDFLAGS variables I’ve been able to compile a simple application directly using clang on NixOS using a command like this:

clang --target=x86_64-windows-msvc hello.c -fuse-ld=lld -o hello.exe

The next step that I want to take is to compile a whole package using this approach. Ideally that should work just like pkgsCross.mingwW64. So I want to be able to do nix-build -A pkgsCross.x86_64-clang-mvsc.hello and have it produce a hello.exe file that runs under wine (or on another Windows machine).

Now I’m running into the problem that the lib.systems.examples all seem way to small to actually contain al the intricate details of cross compilation. It seems like the config triples are resolved elsewhere, but I can’t find where that actually is. Adding an entry like this obviously doesn’t work:

  x86_64-clang-msvc = {
    config = "x86_64-pc-windows-msvc";
    libc = "msvcrt";
    useLLVM = true;
  };

But what would need to be done to make it work?

I think this should be somewhere in lib/systems. I would look at a previous commit that added a new triple lib/systems: add mips64el definitions · NixOS/nixpkgs@12371a5 · GitHub

Thanks for the pointer. It helps me to understand how some of those lib/systems files are related.

However, I think that change doesn’t really touch the C compiler flags and such, so I think I’ll need to look further than that.

I also found out that the first problem with that x86_64-pc-windows-msvc config is that libtool’s config.sub doesn’t recognize it and it seems like these configurations must pass through config.sub. Unfortunately, it seems like config.sub doesn’t really know much about windows. The only valid windows string that I’ve found is x86_64-windows.

I tried using that:

  x86_64-clang-msvc = {
    config = "x86_64-windows";
    libc = "msvcrt";
    useLLVM = true;
  };

It fails with a more promising error:

clang-11: error: unsupported option '-fPIC' for target 'x86_64-unknown-windows-msvc'

So I’ll need to figure out how to disable -fPIC for this target. And I know I’ll also need to use clang-13 to be able to use the msvc libraries.

For the record some more info I’ve uncovered:

The -fPIC option is probably passed in the pkgs/build-support/cc-wrapper/add-hardening.sh script. That could possibly be controlled temporarily by setting the NIX_HARDENING_ENABLE flag, but I am looking for a better solution.

The lib/systems/default.nix file has an elaborate function which also needs updating, in particular libc seems incorrect for non-MinGW windows builds.

I still don’t know how to change the version of clang and lld that are used.