Cmake install fails with "file cannot create directory"

Hi there! I want to package GitHub - n4n0GH/hello: the complete KDE theme. First for my personal configuration and if it comes out good, I can see myself making a PR to nixpkgs or package it for the NUR.

My derivation looks like this atm:

    (pkgs.libsForQt5.callPackage({mkDerivation}: mkDerivation) {} rec {
      name = "hello";
      version = "Hidden Hedgehog";
      src = pkgs.fetchFromGitHub {
        owner = "n4n0GH";
        repo = "hello";
        rev = "master";
        sha256 = "sha256:1898swsq07rwnd3gdff7v153hzyv9k1hf5817z7a7gr8rphbn3km";
      };
      nativeBuildInputs = with pkgs; [
        cmake
      ];
      buildInputs = with pkgs; [
        extra-cmake-modules
        epoxy
        xorg.libXdmcp
        libsForQt5.kconfig
        libsForQt5.kconfigwidgets
        libsForQt5.kcrash
        libsForQt5.kglobalaccel
        libsForQt5.kio
        libsForQt5.kinit
        libsForQt5.kwin
        libsForQt5.knotifications
        libsForQt5.qt5.qtbase
        libsForQt5.qt5.qttools
        libsForQt5.qt5.qtx11extras
      ];
      configurePhase = "mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=$out/usr/ ..";
      buildPhase = "make -j 4";
      installPhase = "make install";
    })

I’m particularily uncertain about the install-prefix. It’s /usr in the README of the GitHub-page linked above; however I thought I would have to add $out to that, so that it gets added to the nix-store.

The actual error says, that it can’t create the directories, that are specified in the Makefile, and that it maybe needs privileges. I don’t think that privileges are the problem, since I already run it as root (package is built on nixos-rebuild switch).

Here is the error on which the build-process failed:

Install the project...
-- Install configuration: ""
-- Installing: /nix/store/nciszr4vcyg3zzyikzxdzh7iqzlh26gd-hello/usr/share/color-schemes/HelloDark.colors
-- Installing: /nix/store/nciszr4vcyg3zzyikzxdzh7iqzlh26gd-hello/usr/share/color-schemes/HelloLight.colors
CMake Error at kwin-effects/cmake_install.cmake:60 (file):
  file cannot create directory:
  /nix/store/z07clcr9p0zx91b69bmy1k17j1sjalvj-kdelibs4support-5.79.0/lib/qt-5.15.2/plugins/kwin/effects/plugins.
  Maybe need administrative privileges.
Call Stack (most recent call first):
  cmake_install.cmake:48 (include)


make: *** [Makefile:105: install] Error 1
builder for '/nix/store/f5jz9s4zbp2ramnjs6ah8xfwg6cdffw1-hello.drv' failed with exit code 2
cannot build derivation '/nix/store/syc1kfwy53jaybblclw8v7n0wyj49k5l-system-path.drv': 1 dependencies couldn't be built
cannot build derivation '/nix/store/6y09rlrhfy3j0vf7jpcw38bzv6k1n0dx-nixos-system-nixos-21.05pre283367.0a5f5bab0e0.drv': 1 dependencies couldn't be built
error: build of '/nix/store/6y09rlrhfy3j0vf7jpcw38bzv6k1n0dx-nixos-system-nixos-21.05pre283367.0a5f5bab0e0.drv' failed

Did anyone encounter a similar thing before or know how to resolve this? I’m still quite new to Nix and NixOS, so please forgive me, if I overlooked a basic thing.

  1. you should be able to get rid of your configurePhase, buildPhase, installPhase. That’s just what the default builder does by default.
  2. It definitely should have permissions to create that directory, since it’s under $out. Whether you run it as root doesn’t really make a difference, since it’s the nix daemon running the show (and the individual builds are sandboxed, so that can introduces permissions issues, though shouldn’t be in this case)
  3. I’m looking into the error now. what’s weird to me is if I add a preConfigure hook that makes that directory, it still complains about not being able to make it.

Ohhh, of course. It’s not trying to install it in $out, it’s trying to install it into the $out of another package. Yeah, that’s illegal in nix. I’m not sure why it needs to do that (nor am I at all familiar with Qt infrastructure). But yeah, that’s your problem. It’s trying to install something into another package’s output path.

This gets it to compile for me (added the preCompile hook). But I have two disclaimers:

  1. The package might not actually work. I don’t know if the files that I redirected actually needed to be where they were being put.
  2. This is just a kludge to get it working. For instance, hard-coding qt-5.15.2 is almost certainly not good practice.
(pkgs.libsForQt5.callPackage({mkDerivation}: mkDerivation) {} rec {
  name = "hello";
  version = "Hidden Hedgehog";
  src = pkgs.fetchFromGitHub {
    owner = "n4n0GH";
    repo = "hello";
    rev = "master";
    sha256 = "sha256:1898swsq07rwnd3gdff7v153hzyv9k1hf5817z7a7gr8rphbn3km";
  };
  nativeBuildInputs = with pkgs; [
    cmake
  ];
  buildInputs = with pkgs; [
    extra-cmake-modules
    epoxy
    xorg.libXdmcp
    libsForQt5.kconfig
    libsForQt5.kconfigwidgets
    libsForQt5.kcrash
    libsForQt5.kglobalaccel
    libsForQt5.kio
    libsForQt5.kinit
    libsForQt5.kwin
    libsForQt5.knotifications
    libsForQt5.qt5.qtbase
    libsForQt5.qt5.qttools
    libsForQt5.qt5.qtx11extras
  ];
  preConfigure = ''
    substituteInPlace kwin-effects/CMakeLists.txt \
      --replace "\''${MODULEPATH}" "$out/qt-5.15.2/plugins" \
      --replace "\''${DATAPATH}"   "$out/share"
  '';
})

Why does it do that? Isn’t $out supposed to be usable to the derivation at hand? Why would it make sense to let $out point to another package?

It’s not that $out points to a different package. If you look in the kwin-effects/CMakeLists.txt file, you’ll see:

execute_process(COMMAND kf5-config --install module OUTPUT_VARIABLE MODULEPATH OUTPUT_STRIP_TRAILING_WHITESPACE)

This sets the cmake variable MODULEPATH to the output of the kf5-config --install module command. This command looks up where to install modules, but it does it wrong for Nix’s purposes, and finds a path in another package.

Later on, that variable is used as follows:

install(TARGETS ${HELLOSHADERS} DESTINATION ${MODULEPATH}/kwin/effects/plugins)

So what I’ve done in the preConfigure step is just replace that ${MODULEPATH} with the equivalent path in $out. There’s a similar thing happening for DATAPATH

Ah, ok got it. Thanks for the great explanation! :slight_smile: So basically the last thing to change is to make it more general; i.e. not depend on paths like qt-5.12.2

I can confirm, that at least the package is functional, when building it the way you showed it!

Great!

Yeah, that’s what I’d do. My first question would be: "is this a common issue that Qt applications / libraries run into when people try to package them for Nix? If so, is there a standard way to deal with it? For instance, I can imagine some kind of kf5-config replacement shim that gives the right path to programs. Or maybe there’s some kind of automated patch script (like patchShebangs) that will adjust the CMake files.

Looking around packages that use kdelibs4support (which, by the way, is where kf5-config comes from, so now it makes sense that it’s looking in it’s own out path, instead of the current package’s), it looks like almost none of them need this kind of adjustment, so it seems like there isn’t a standard / simple solution.

I did find qtcurve, which seems to do something similar:

So you’re probably good with the changes I put in. Maybe this preConfigure instead:

  # kwin-effects tries to put things in kdelibs4support's out path.
  # this redirects it to our $out, but keeps the same directory structure
  preConfigure = ''
    local modulepath=$(kf5-config --install module)
    local datapath=$(kf5-config --install data)
    substituteInPlace kwin-effects/CMakeLists.txt \
      --replace "\''${MODULEPATH}" "$out/''${modulepath#/nix/store/*/}" \
      --replace "\''${DATAPATH}"   "$out/''${datapath#/nix/store/*/}"
  '';

Instead of hard-coding the paths, it uses the same method that the CMakeLists.txt is using (kf5-config) and then stripping the /nix/store/*/ prefix and replacing it with the proper $out prefix. It’s a little ugly, but I can’t think of a cleaner solution.