Create a default.nix that inherits system and buildInputs from flake devShell?

Hi Nix community, I am fairly new to Nix and even newer to nix flakes (have been using shell.nix for awhile) and I like how the devShell in the flake is structured hence venturing into flakes. I’ve manage to create a simple devShell with CMake, gcc-12 and Boost but I was wondering how do I go about creating a default.nix that inherits the system and buildInputs from the devShell of the flake and has a buildPhase that runs a simple command to compile and link to boost for the boost::format() in my executable. This is how my flake is currently set up:

{
  description = "A simple development environment with g++ for x86-64 Linux and ARM-based MacBooks";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/master";
    utils.url = "github:numtide/flake-utils";
    utils.inputs.nixpkgs.follows = "nixpkgs";
  };

  # This is for running on X86-64 Linux (the norm), Intel and M1 Macs.
  outputs = { self, nixpkgs, ... }@inputs: inputs.utils.lib.eachSystem [
      "x86_64-linux" "x86_64-darwin" "aarch64-darwin"
    ] (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShell = pkgs.mkShell {
          buildInputs = [
            pkgs.gcc12
            pkgs.cmake
            pkgs.boost180
          ];

          shellHook = ''
            echo "Welcome to the Nix g++ development environment!"
          '';
         };
      }
    );
}

The executable just includes boost/format.hpp and does a std::cout with that formatted string.

I was hoping to create a default.nix that could inherit the system and devShell buildInputs so that I don’t have to redefine them again and also keep track of them in place.

Appreciate any help and advice I can get on this.

You would typically do the opposite. Create a package derivation first, and then make a shell from it, e.g. using inputsFrom attribute.

And since you are already using Flakes, I would create a packages output rather than use default.nix. If you really want to have a fallback for the legacy nix-build command, you can use flake-compat shim.

1 Like

Ok I followed the recommendation and tried to add a packages.${system}.default below the devShell and get this error: error: flake does not provide attribute ‘packages.x86_64-linux.default’ or ‘defaultPackage.x86_64-linux’ when I try to run nix build

{
  description = "A simple development environment with g++ for x86-64 Linux and ARM-based MacBooks";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/master";
    utils.url = "github:numtide/flake-utils";
    utils.inputs.nixpkgs.follows = "nixpkgs";
  };

  # This is for running on X86-64 Linux (the norm), Intel and M1 Macs.
  outputs = { self, nixpkgs, ... }@inputs: inputs.utils.lib.eachSystem [
      "x86_64-linux" "x86_64-darwin" "aarch64-darwin"
    ] (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShell = pkgs.mkShell {
          buildInputs = [
            pkgs.gcc12
            pkgs.cmake
            pkgs.boost180
          ];

          shellHook = ''
          echo "Welcome to the Nix g++ development environment!"
          '';
        };
        packages.${system}.default =
        with import nixpkgs { inherit system; };
        stdenv.mkDerivation {
          name = "nix_testing";
          src = self;
          inputsFrom = [ devShell.buildInputs ];
          buildPhase = "g++ ./nix_testing.cpp -o nix_testing";
          installPhase = "echo Installing";
        };
      }
    );
}

I’ve tried changing the build outputs to:

        defaultPackage.x86_64-linux = pkgs.stdenv.mkDerivation {
          name = "nix_testing";
          src = self;
          buildInputs = [
            pkgs.gcc12
            pkgs.cmake
            pkgs.boost180
          ];
          buildPhase = "g++ ./nix_testing.cpp -o nix_testing";
          installPhase = "echo Installing";
        };

But then it says: error: flake output attribute 'defaultPackage.x86_64-linux' is not a derivation or path

For this I had to copy and paste the buildInputs again because it throws this other error:
error: undefined variable 'devShell'

You are passing that definition to inputs.utils.lib.eachSystem function so you do not need to specify the system again – just use packages.default like you use devShells.default.

1 Like

Ok changing that last part to:

        packages.default = pkgs.stdenv.mkDerivation {
          name = "nix_testing";
          src = self;
          buildInputs = [
            pkgs.gcc12
          ];
          buildPhase = "g++ ./nix_testing.cpp -o nix_testing";
          installPhase = ''
              mkdir -p $out/bin
              cp nix_testing $out/bin/
            '';
        };

worked. Thank you for the advice!