How to express system-dependent differences in flakes

I am trying to write a flake which caters for both Darwin and Linux. On Darwin, I need to include pkgs.darwin.apple_sdk.frameworks.{AppKit,CoreText}, which are completely absent on Linux. Other than that, the expressions are pretty much identical.

How should these differences be encoded in a flake that uses numtide/flake-utils to reduce the boilerplate?

EDIT: Pre-flakes, I hacked around with pkgs.stdenv.isDarwin etc., but

  • I’m wondering whether flakes offer some better way.
  • Something isn’t working when I try to apply the technique in flakes (but that could be caused by some mistake I’ve made somewhere).

Can you share your flake or a sample of it?

If you were using raw flakes, then you would just include different definitions for each system. However, by mentioning flake-utils, I assume you’re using eachSystem (or one of its variants). In that case, the most straightforward way would be to special case on the system variable or use pkgs.stdenv.isDarwin (etc) in the function you pass to it.

I guess you could concatenate a system-specific attrset to the output of eachSystem, but that seems really hacky and likely to be more of a maintenance burden.

For Example (using pkgs.stdenv.isDarwin)

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-21.11";
    utils.url = "github:numtide/flake-utils";

  outputs = inputs@{ self, nixpkgs, utils, ... }:
    utils.lib.eachDefaultSystem (system: {
      devShell =
          pkgs = nixpkgs.legacyPackages.${system};
        pkgs.mkShell {
          buildInputs =
              inherit (pkgs.darwin.apple_sdk.frameworks) AppKit CoreText;
            in [
            ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
              AppKit CoreText

I’ve tried to extract the essential stuff here: jacg/rust-darwin-flake - rust-darwin-flake -

Everything goes swimmingly until I add some Rust code that depends on OpenGL.

Executing nix run .#hdf:

  • Runs fine on the appkit-not-needed branch, on both x86_64-linux and aarch64-darwin.
  • On the appkit-not-found branch it fails with an extremely verbose error on Darwin, and runs fine on Linux. The tail end of the error on Darwin contains
     = note: ld: framework not found AppKit
             clang-11: error: linker command failed with exit code 1 (use -v to see invocation)         
  • On the appkit-added-but-not-found branch, I’ve tried to add the framework (just about anywhere I could think of stuffing it in) using a technique that worked for me a few Nix versions ago and without flakes. Fundamentally, it’s a variation on the idea as the one suggested in the parent post, and uses isDarwin at its core. The results are the same: success on Linux, identical failure on Darwin.

Thanks, that helps a lot. There appears to be a typo on line 79: buildInupts instead of buildInputs. Fixing that wasn’t enough though. I had to add the AppKit dependency to the rust-darwin-flake crate. Once I did that, it built and ran (assuming ogl is supposed to show a red cube). That was the only place that required the Darwin-specific dependency.

project = pkgs.callPackage
  (generatedCargoNix {
    inherit name;
    src = ./.;
    # See "Handling external dependencies" on
    defaultCrateOverrides = pkgs.defaultCrateOverrides // {
      rust-darwin-flake = _: {
        buildInputs = [
          (darwin darwin darwin-frameworks.AppKit)
      hdf5-sys = old-attributes: {
        buildInupts = [
        HDF5_DIR = pkgs.symlinkJoin { name = "hdf5"; paths = [ pkgs.hdf5 ]; };

It’s astounding how long it took me to understand what the typo was, even though you pinpointed it: I was staring at buildInupts for far too long before spotting it. And it’s not as if I’m unaccustomed to this sort of activity. The human brain is a fascinating thing.

(Incidentally, this is precisely why I insist on aligning my code to highlight symmetries, and consequently hate automatic code formatters (which insist on breaking my symmetry-highlighting layouts, and on putting many inches between bits of code that I want right next to each other) with a passion.)

There’s a little error in the code you posted:

two darwins where there should only be one.

I thought I had tried adding the framework to the local crate in one of my million attempts, but I must have messed it up somehow and forgotten about it. It makes perfect sense when you can think about without distractions.

Many, many thanks for this. In isolation, I might have got there on my own, eventually, but given the thousands of mysteries that I am battling with in the slightly broader context, I don’t see how I would have got there without this help.

1 Like