Error: Missing dependencies on foreign libraries when building sdl2-ttf package

I have started a toy project using Haskell, SDL2 and nix and have been using the SDL2 package from nixpkgs and the sdl2 package from Hackage successfully.

Unfortunately I hit a wall when trying to use the SDL2_ttf package and its Haskell counterpart sdl2-ttf for rendering text. Trying to add them to the project results in an error:

error: builder for '/nix/store/6hhl3ikh9brcdyc20js29f940fj4cp9l-sdl2-ttf-2.1.3.drv' failed with exit code 1; last 10 log lines: 
  > Error: Setup: Missing dependencies on foreign libraries: 
  > * Missing (or bad) C libraries: SDL2_ttf, SDL2

Using pkg-config shows that the libs are available:

❯ pkg-config --list-all | grep sdl
SDL2_ttf                                    SDL2_ttf - ttf library for Simple DirectMedia Layer with FreeType 2 support
sdl                                         sdl - Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
sdl2                                        sdl2 - Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.

I did notice, however, that the output of pkg-config lists sdl2 instead of the SDL2 that was mentioned in the error message above. Could capitalization be the cause of the Haskell package not finding the dependency? Is it something else? Help, this is very frustrating! :disappointed:

Reproducing

Here’s a link to the failing branch. nix develop should do the trick to reproduce the issue. TL;DR:

git clone -b sdl2-ttf git@github.com:cgeorgii/game-sdl.git
nix develop

Extra context

Here are the relevant parts of my flake.nix:

{
  [ ... ]

  outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        packageName = "game-sdl";
        pkgs = nixpkgs.legacyPackages.${system};
        haskellPackages = pkgs.haskellPackages.override {
          overrides = self: super: rec {
            sdl2-ttf =
              pkgs.lib.pipe super.sdl2-ttf
                [
                  pkgs.haskell.lib.unmarkBroken
                  pkgs.haskell.lib.dontCheck
                ];
          };
        };
      in
      {
        defaultPackage = self.packages.${system}.${packageName};
        packages.${packageName} =
          haskellPackages.callCabal2nix packageName self rec { };

          packages = p: [ self.packages.${system}.${packageName} ];

          nativeBuildInputs = with pkgs; [
            pkg-config
          ];

          buildInputs = with pkgs; [
            SDL2
            SDL2_ttf
            go-task
            haskellPackages.cabal-install
            haskellPackages.ghcid
            haskellPackages.haskell-language-server
            haskellPackages.ormolu
            hpack
            jq
            zlib
          ];

          LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
        };
      });
}

And here’s the relevant bit of the package.yaml file:

library:
  source-dirs:      src

dependencies:
  - name: base
    version: ">= 4.14 && < 5"
    mixin: hiding (Prelude)
  - optics
  - name: relude
    mixin: (Relude as Prelude)
  - sdl2
  - sdl2-ttf

Full error logs:

❯ nix log /nix/store/6hhl3ikh9brcdyc20js29f940fj4cp9l-sdl2-ttf-2.1.3.drv
warning: The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '/nix/store/6hhl3ikh9brcdyc20js29f940fj4cp9l-sdl2-ttf-2.1.3.drv^*'
@nix { "action": "setPhase", "phase": "setupCompilerEnvironmentPhase" }
setupCompilerEnvironmentPhase
Build with /nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6.
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking sources
unpacking source archive /nix/store/nc6j72lm1vmkfxkp22a4mg0lidiicpql-sdl2-ttf-2.1.3.tar.gz
source root is sdl2-ttf-2.1.3
setting SOURCE_DATE_EPOCH to timestamp 1000000000 of file sdl2-ttf-2.1.3/src/SDL/Raw/Helper.hs
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "compileBuildDriverPhase" }
compileBuildDriverPhase
setupCompileFlags: -package-db=/build/tmp.gOsdp09JfV/setup-package.conf.d -j8 +RTS -A64M -RTS -threaded -rtsopts
[1 of 2] Compiling Main             ( Setup.hs, /build/tmp.gOsdp09JfV/Main.o )
[2 of 2] Linking Setup
@nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" }
updateAutotoolsGnuConfigScriptsPhase
@nix { "action": "setPhase", "phase": "configurePhase" }
configuring
configureFlags: --verbose --prefix=/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3 --libdir=$prefix/lib/$compiler --libsubdir=$abi/$libname --docdir=/nix/store/0qwah87jvm>
Using Parsec parser
Configuring sdl2-ttf-2.1.3...
Flags chosen: example=False
Dependency base >=4.9 && <5: using base-4.17.2.0
Dependency bytestring >=0.10.4.0: using bytestring-0.11.5.1
Dependency sdl2 >=2.2: using sdl2-2.5.5.0
Dependency template-haskell: using template-haskell-2.19.0.0
Dependency text >=1.1.0.0 && <2 || >=2.0.1: using text-2.0.2
Dependency th-abstraction >=0.4.0.0: using th-abstraction-0.4.5.0
Dependency transformers >=0.4: using transformers-0.5.6.2
Dependency sdl2 >=2.0.3: using version 2.28.1
Dependency SDL2_ttf >=2.0.12: using version 2.20.2
Source component graph: component lib
Configured component graph:
    component sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW
        include base-4.17.2.0
        include bytestring-0.11.5.1
        include sdl2-2.5.5.0-BAzqJ1DAHnHE5ZcU90092A
        include template-haskell-2.19.0.0
        include text-2.0.2
        include th-abstraction-0.4.5.0-CynkUuS8OuAKbGjDnje1Fs
        include transformers-0.5.6.2
Linked component graph:
    unit sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW
        include base-4.17.2.0
        include bytestring-0.11.5.1
        include sdl2-2.5.5.0-BAzqJ1DAHnHE5ZcU90092A
        include template-haskell-2.19.0.0
        include text-2.0.2
        include th-abstraction-0.4.5.0-CynkUuS8OuAKbGjDnje1Fs
        include transformers-0.5.6.2
        SDL.Font=sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW:SDL.Font,SDL.Raw.Font=sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW:SDL.Raw.Font
Ready component graph:
    definite sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW
        depends base-4.17.2.0
        depends bytestring-0.11.5.1
        depends sdl2-2.5.5.0-BAzqJ1DAHnHE5ZcU90092A
        depends template-haskell-2.19.0.0
        depends text-2.0.2
        depends th-abstraction-0.4.5.0-CynkUuS8OuAKbGjDnje1Fs
        depends transformers-0.5.6.2
Using Cabal-3.8.1.0 compiled by ghc-9.4
Using compiler: ghc-9.4.6
Using install prefix:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3
Executables installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/bin
Libraries installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/lib/ghc-9.4.6/x86_64-linux-ghc-9.4.6/sdl2-ttf-2.1.3-KYVkl2WQToIBhDtOt3zdoW
Dynamic Libraries installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/lib/ghc-9.4.6/x86_64-linux-ghc-9.4.6
Private executables installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/libexec/x86_64-linux-ghc-9.4.6/sdl2-ttf-2.1.3
Data files installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/share/x86_64-linux-ghc-9.4.6/sdl2-ttf-2.1.3
Documentation installed in:
/nix/store/0qwah87jvmm96ymrasyfprgza8bzwa4a-sdl2-ttf-2.1.3-doc/share/doc/sdl2-ttf-2.1.3
Configuration files installed in:
/nix/store/fy10ihlprm03nsn97hdm0cyqb3zm3y5i-sdl2-ttf-2.1.3/etc
No alex found
Using ar found on system at:
/nix/store/inq79dwl8sz1ygmfbgsmg77i5cwmdjpz-binutils-2.40/bin/ar
No c2hs found
No cpphs found
No doctest found
Using gcc version 12.3.0 given by user at:
/nix/store/n847wr4vj9f3nszbgnqz9n8w3vnnfmcd-gcc-wrapper-12.3.0/bin/gcc
Using ghc version 9.4.6 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/ghc
Using ghc-pkg version 9.4.6 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/ghc-pkg-9.4.6
No ghcjs found
No ghcjs-pkg found
No greencard found
Using haddock version 2.27.0 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/haddock-ghc-9.4.6
No happy found
Using haskell-suite found on system at: haskell-suite-dummy-location
Using haskell-suite-pkg found on system at: haskell-suite-pkg-dummy-location
No hmake found
Using hpc version 0.68 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/hpc
Using hsc2hs version 0.68.8 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/hsc2hs
Using hscolour version 1.24 found on system at:
/nix/store/h4aml2d9hvachdq1n4v7lybv2bi87c1b-hscolour-1.24.4/bin/HsColour
No jhc found
Using ld found on system at:
/nix/store/h6ynnj5hcw7clv2vmwn7l8blmlchd39i-binutils-wrapper-2.40/bin/ld.gold
Using pkg-config version 0.29.2 found on system at:
/nix/store/bhn19xy6sva5vf6nzz5szljdyyvlnrib-pkg-config-wrapper-0.29.2/bin/pkg-config
Using runghc version 9.4.6 found on system at:
/nix/store/xmvbmsp9yz577kg1hlakcc2q722xmip9-ghc-9.4.6/bin/runghc-9.4.6
Using strip version 2.40 found on system at:
/nix/store/n847wr4vj9f3nszbgnqz9n8w3vnnfmcd-gcc-wrapper-12.3.0/bin/strip
Using tar found on system at:
/nix/store/xxdfv3fr2ivz1lh833n698nd4a935vhh-gnutar-1.35/bin/tar
No uhc found
Error: Setup: Missing dependencies on foreign libraries:
* Missing (or bad) C libraries: SDL2_ttf, SDL2
This problem can usually be solved by installing the system packages that
provide these libraries (you may need the "-dev" versions). If the libraries
are already installed but in a non-standard location then you can use the
flags --extra-include-dirs= and --extra-lib-dirs= to specify where they are.If
the library files do exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.
1 Like

I was able to figure it out after posting in the Nix Haskell room of the NixOS matrix. This reply by @cdepillabout was very helpful. It mentioned a similar issue that contained a snippet that inspired a solution.

In the end, this is the relevant part of the workaround:

  outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        packageName = "game-sdl";
        pkgs = nixpkgs.legacyPackages.${system};
        haskellPackages = pkgs.haskellPackages.override {
          overrides = self: super: rec {
            sdl2-ttf = with pkgs.haskell.lib;
              pkgs.lib.pipe super.sdl2-ttf
                [
                  unmarkBroken
                  dontCheck
                  (p: overrideCabal p (old: old // { __onlyPropagateKnownPkgConfigModules = true; }))
                  (p: addSetupDepends p [ pkgs.pkg-config pkgs.SDL2 pkgs.SDL2_ttf ])
                ];
          };
        };
      in

The really important lines are these two:

(p: overrideCabal p (old: old // { __onlyPropagateKnownPkgConfigModules = true; }))
(p: addSetupDepends p [ pkgs.pkg-config pkgs.SDL2 pkgs.SDL2_ttf ])

Notes

  • overrideCabal and addSetupDepends come from pkgs.haskell.lib.
1 Like