Conditionally use `x86_64-unknown-linux-musl` for `flake.nix` package build

I have a simple flake like

{
  description = "Simple Flake";

  nixConfig = {
    extra-substituters = [
      # Nix community's cache server
      "https://nix-community.cachix.org"
    ];
    extra-trusted-public-keys = [
      "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
    ];
  };

  inputs = {
    # Nixpkgs (stuff for the system.)
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";

    # Nixpkgs (unstable stuff for certain packages.)
    # Also see the 'unstable-packages' overlay at 'overlays/default.nix'.
    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs =
    {
      self,
      nixpkgs,
      ...
    }@inputs:
    let
      inherit (self) outputs;

      # Supported systems for your flake packages, shell, etc.
      systems = [ "aarch64-linux" "x86_64-linux" "aarch64-darwin" ];

      # This is a function that generates an attribute by calling a function you
      # pass to it, with each system as an argument
      forAllSystems = nixpkgs.lib.genAttrs systems;

      packages = forAllSystems (
        system:
        let
          pkgs = (import inputs.nixpkgs-unstable) {
            system = system;
            crossSystem = "x86_64-unknown-linux-musl"; // This build with musl but is incorrect here.
          };
        in
        {
          mypackage = pkgs.xz;
        }
      );

    in
    {
      inherit
        packages
        ;
    };
}

I am trying to figure out a solution to basically set libc to musl on a certain condition:

  • In CI I want to run nix build ".#mypackage but with musl instead of glibc.

Questions:

  • Is there a global way to influence nix to build with musl. From outside, nix.conf, or env variables?

  • How would I instantiate a separate pkgsMusl for the system argument in forAllSystems such that I can `nix build “.#musl.mypackage”:

    in {
      mypackage = pkgs.xz;
      musl.mypackge = pkgsMusl.xz;
    }
    

    With this I however always need musl. infront of everything. With such a solution I also need that to launch nix develop ".#musl.default" etc, which is cumbersome. Is there a better way?

1 Like

I have seen there exists pkgsCross.musl64 when I instantiate nixpkgs normally:

pkgs = (import inputs.nixpkgs-unstable) {
            system = system;
};

mypackage = pkgsCross.musl64.xz;

But that only solved half my problem.

You could use an environment variable and --impure, but affecting the build from the outside defeats the purpose of having pure builds.

Note that packages is required to be a flat attributes set, you would need to name it package-musl or something similar.

1 Like

Is it really that I cannot influence the default platform with Nix, when
using nix build .#mypackage? So sad.

So the only option is to really specify what I want to build and run:

nix build .#legayPackages.mynamespace.musl.mypackage

here I use legacyPackages because it does not require a flat map.

or kind of use an env. variable USE_MUSL=true which then I use with builtins.getEnv("USE_MUSL) to switch like

{
  description = "Simple Flake";

  nixConfig = {
    extra-substituters = [
      # Nix community's cache server
      "https://nix-community.cachix.org"
    ];
    extra-trusted-public-keys = [
      "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
    ];
  };

  inputs = {
    # Nixpkgs (stuff for the system.)
    nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";

    # Nixpkgs (unstable stuff for certain packages.)
    # Also see the 'unstable-packages' overlay at 'overlays/default.nix'.
    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs =
    {
      self,
      nixpkgs,
      ...
    }@inputs:
    let
      inherit (self) outputs;

      # Supported systems for your flake packages, shell, etc.
      systems = [
        "aarch64-linux"
        "i686-linux"
        "x86_64-linux"
        "aarch64-darwin"
        "x86_64-darwin"
      ];
      # This is a function that generates an attribute by calling a function you
      # pass to it, with each system as an argument
      forAllSystems = nixpkgs.lib.genAttrs systems;

      getSystem =
        system:
        if builtins.getEnv "USE_MUSL" == "true" then
          inputs.nixpkgs-unstable.legacyPackages.${system}.pkgsMusl.stdenv.hostPlatform.config
        else
          inputs.nixpkgs-unstable.legacyPackages.${system}.stdenv.hostPlatform.config;

      packages = forAllSystems (
        system:
        let
          pkgs = (import inputs.nixpkgs-unstable) {
            localSystem = getSystem system;
          };
        in
        {
          mypackage = pkgs.xz;
        }
      );

    in
    {
      inherit
        packages
        ;
    };
}

with USE_MUSL=true nix build --no-pure-eval -L ".#mypackage"

kind of unsatisfying…