{
  description = "auto-opt-cpp";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs =
    {
      self,
      nixpkgs,
      flake-utils,
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        pkg =
          {
            stdenv,
            cmake,
            ninja,
            lib,
            eigen,
            gtest,
            python313,
            python313Packages,
            withTests ? false,
          }:
          let
            fs = lib.fileset;
          in
          stdenv.mkDerivation {
            pname = "autoopt-cpp";
            version = "0.1.0";

            src = fs.toSource {
              root = ./.;
              fileset = fs.unions [
                ./include
                ./CMakeLists.txt
                ./tests
                ./src
                ./pysrc
              ];
            };

            buildInputs = lib.optionals withTests [ gtest ];

            nativeBuildInputs = [
              cmake
              ninja
              eigen
              (python313.withPackages (
                ps: with ps; [
                  nanobind
                  matplotlib
                  numpy
                ]
              ))
            ];
          };
      in
      rec {
        packages = rec {
          autoopt-cpp = pkgs.callPackage pkg { };
          autoopt-cpp-with-tests = pkgs.callPackage pkg { withTests = true; };
          default = autoopt-cpp;
        };
        devShells = {
          default = pkgs.mkShell {
            inputsFrom = [
              packages.autoopt-cpp-with-tests
            ];

            shellHook = ''
              echo "Development shell for autoopt-cpp"
            '';
          };
        };
      }
    );
}
