I've packaged Darkest Dungeon for nix!

Hi there!

I’m quite happy as recently I’ve finished my first (software) package for nix. It being the GoG, Linux native, version of the game Darkest Dungeon, which, btw I totally recommend.

As I was encountering issues with Lutris, minigalaxy, etc… I’ve decided to package it myself.

Contrary to what’s advised here I’ve choose not to use steam-run or steam-run-native and just patch the binary using the libs from nixpkgs.

As this is my first time doing anything like that I would like to receive some feedback. I want to stick to best practices whenever possible. I should also state that the following code is NOT YET FINISHED.

TODO:


There are a few things which I need to fix (I do have an important exam this week so it will happen afterwards) like:

  • It does not work with the installation shellscript provided by GoG, this was due to testing purposes and would be changed soon.
  • There’s duplicated code.
  • I have to add a formatter.
  • It might be possible to delete some unused files in order to reduce the closure size.

Code


That being said, the code of the flake:

{
  description = "Darkest Dungeon (GoG) Flake";

  inputs = {
    nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;

    flake-utils.url = github:numtide/flake-utils;
  };
  
  outputs = { self, nixpkgs, flake-utils }:
    with flake-utils.lib; eachDefaultSystem (system:
      let
        inherit (self) outputs;
      pkgs = nixpkgs.legacyPackages.${system};
      
    in rec {
      
      packages = {
        darkest-dungeon = pkgs.stdenvNoCC.mkDerivation rec {
          name = "darkest-dungeon";

          # TODO: Change this to the official installer instead.
          src = pkgs.requireFile {
            name = "darkest-dungeon.tar";
            url = "https://www.gog.com/game/darkest_dungeon & some whichcraft";
            sha256 = "b3001d41c28279b39a9b5fdee08930f51479d3472f1f049781cebcd6bf62c81d";
          };

          nativeBuildInputs = with pkgs; [
            autoPatchelfHook
            makeBinaryWrapper
            SDL2
            libcxx
            libGL
            fmodex
            libmx
            fmodex
            xorg.libX11
            xorg.libXext
            xorg.libxcb
            xorg.libXau
            xorg.libXdmcp
          ];

          runtimeDependenciesPath = with pkgs; pkgs.lib.makeLibraryPath [
            SDL2
            libcxx
            libGL
            fmodex
            libmx
            fmodex
            xorg.libX11
            xorg.libXext
            xorg.libxcb
            xorg.libXau
            xorg.libXdmcp
          ];
          
          phases = [ "unpackPhase" "installPhase" "fixupPhase" ];

          
          installPhase = ''
            mkdir -p $out/share/${name}
            cp -r . $out/share/${name} 

            makeBinaryWrapper $out/share/${name}/darkest.bin.x86_64 $out/bin/darkest \
            --prefix LD_LIBRARY_PATH : "$runtimeDependenciesPath"
          '';
        };
      };

      defaultPackage = packages.darkest-dungeon;
    });
}

Help


And now a list of things in which I need some help:

  • What is this missing, if any, to be a “correct package”?
  • How can I use flake-utils to avoid having to define a formatter for each system?
  • How can I specify the license, maintainer, supported systems and etc?
  • How would you add feral gamemoderun support only if already installed?
  • If I wanted to delete useless files from the tar, in which phase should it be done?
  • Am I ussing nativeBuildInputs right?

Conclusion


Once everything mentioned in this post has been solved I would like upload this flake to my personal Codeberg and add it to the gaming section in the NixOS wiki, (which I might even end up improving).

Thanks for your attention and time everyone. :heart:

2 Likes

You don’t want to set phases. If some phase is breaking things disable it with eg dontConfigure = true

2 Likes

What do you mean? I need to define specific instructions for certain phases.

You don’t need to define phases to do that, it is set by default. You can have a custom installPhases without setting phases.

The manual explains it here

4 Likes

Oh, okey. Now I get it. Thanks for the link. :slight_smile:

2 Likes

Awesome, very cool to see!

I can’t try it out because I’m on macOS, but

with flake-utils.lib; eachDefaultSystem (system:

is incorrect, as this includes macOS. I don’t know what architectures are supported by the installer, but I assume it’s only x86_64-linux.

Also, is this game for free? Because if it is payed software, I assume that the URL you specified here

will be different for every single user, so this can never be a complete package.

What do you mean by “formatter” here? You mentioned it in your todos as well.

You can use the meta-Attributes. Usually these are put at the very end, so in your case it’s after installPhase.

That is not possible in the way you might imagine. A flake can not depend on external factors and change it’s behavior based on that.

However, you could add a second package darkest-dungeon-optimized or something like that, and define it with gamemode as an additional dependency. You’ll also have to change the installPhase, I assume. To save some typing, you can make packages a recursive set as well and create it like this:

darkest-dungeon-optimized = darkest-dungeon // {
/* add all attributes you need to change */
};

It would be better to avoid the recursive sets by putting the main set into the let part, though.

For static stuff like videos or images that aren’t used, I would recommend postUnpack. For shared libraries etc. the fixupPhase might already do that automatically. But if you want to do it manually, use postFixup.

I’m not sure which of these libs will be used at runtime and what’s required only during build, but it seems you should split it into nativeBuildInputs and buildInputs. Check out this part of the nixpkgs manual for instructions.

1 Like