How to link package contents to /usr/<path> inside FHS env

Hello,
I am currently trying to include openfx plugins in my Davinci Resolve installation.
I already have the plugins building via a custom flake. As far as I was able to research, Resolve expects OFX plugins at /usr/OFX/Plugins with no way to override that (which, AFAIU, means that a wrapper is not a valid solution to my problem). My packages output result/usr/OFX/Plugins/... .
As resolve is using a FHSenv, including additional packages is more difficult, because I can not just use overrideAttrs.
I then tried to modify the Resolve package directly in a local fork of nixpkgs.
I read somewhere that adding my packages to the attribute targetPkgs of the FHSenv would make the files available inside the env at the proper locations, but that also did not work.
As a last resort I tried to add "--bind-try ${<plugin package>}/usr/OFX/Plugins /usr/OFX/Plugins/" to extraBrwapArgs, but this also fails with

bwrap: Can’t mkdir parents for /usr/OFX/Plugins/: Read-only file system

If I understand the FHS and bubblewrap correctly, I should be able to link arbitrary files to arbitrary locations in the created environment, regardless of the underlying permissions.

Is what I am trying to accomplish even possible, or did I stumble into a XY-problem?

Could you explain in what way that didn’t work? This would be the correct way of doing this; making the builder of the FHSEnv link it in to the correct place.

Though, glancing at pkgs/build-support/build-fhsenv-bubblewrap/buildFHSEnv.nix, I think we might only be taking a few specific directories out of the paths passed.

This doesn’t work because /usr’s actual location is a directory inside the Nix store which is read-only.

We have full control over the FHSEnv’s contents, so it ought to be possible.

Ideally though, this would be a high-level override interface where the davinic-resolve program would have a parameter to pass additional plugins which it’d then pass on to the fhsenv builder. The fhsenv builder would then need a way to link arbitrary paths to arbitrary locations inside the fhsenv.

First of all, thank you for your reply.

I added the packages to targetPkgs by adding a parameter to the default.nix for Resolve

<...>
, OFXPlugins ? []
, common-updater-scripts
, writeShellApplication
}:
targetPkgs = [<...>] ++ OFXPlugins;

and then overriding that inside the definition of the devshell I am using to test my work.

devShells.${system}.default = pkgs.mkShell {
        buildInputs = with pkgs; [
          (davinci-resolve.override (prev: {
            OFXPlugins = [
              ofx.packages.${system}.openfx-misc
              ofx.packages.${system}.openfx-arena
            ];
          }))
<...>

Checking the usr directory from the Resolve filepicker did not show a OFX directory which should be there if this solution works. I recall reading somewhere that only /etc and /lib are copied, but I might be misremembering.

I think I am having trouble understanding here. The archwiki made it seem like bubblewrap could just “overlay” anywhere at runtime. Obviously the package contents are inside the nix store, but the /usr directory is not? The source being readonly should not matter, because it does not get modified? I tested with --ro-bind instead of --try-bind, same issue.

That is what I am trying to implement (I think)

On a sidenote: Is there a way to override the attributes of the FHSEnv from outside the package definition as one would do with overrideAttrs in most cases?

That’s perfect :slight_smile:

Your misunderstanding here is that it’s not an “overlay”, it’s just bind-mounts. It does something to the effect of mount -o bind /nix/store/eeeeeeee-fhsenv/usr/ /path/to/new/root/usr/. (It then changes the root to /path/to/new/root/ in the namespace.)

You are attempting to modify it. If you look closely at the initial error message, it says that it’s unable to mkdir. It has to do this because, in order to mount something somewhere, that somewhere must be a valid mount-point. In the case of directory bind-mounts or filesystem mounts, the mount-point must be a directory.

No, overrideAttrs concerns mkDerivation arguments. buildFHSEnv is its own builder. This could be useful to have though.


I think what might be needed here is an argument to buildFHSEnv that decides which paths under usr/ are linked.

While doing this, we should look into whether we could just build on buildEnv’s pathsToLink to do this. We’d need a two-staged approach here as we want to construct some subdirs manually (i.e. etc/) while all others can just be linked by buildEnv.

I tried my luck at implementing something, but was ultimately unsuccessful.

First of all, pathsToLink is set to / if unspecified. Based on the comment in the source wouldn’t that mean everything is linked, because everything is inside the filesystem root?

I can get the /usr/OFX directory to appear in the FHSEnv, if I add mkdir $out/OFX to staticUsrProfileTarget.postBuild. That is obviously not useful, because it only gets me an empty directory. As far as I understand it, I somehow need to convince the env builder to link my files before this step occurs, because, from the source code I have read, what is linked indeed depends on the paths parameter passed to the env builder. This in turn is set to targetPkgs, which means my initial approach could have worked, but did not. I should mention that my nix is not that great and my perl-fu is abysmal, so I am almost certainly overlooking something.

I then tried modifying the builder.pl, but gave up quickly, because adding a single print statement and recreating the env caused numerous packages to be rebuilt, including llvm and rustc.

Is there a way I can hack on the builder without having to rebuild half of nixpkgs every time?

Okay, now I am even more confused.

I looked around nixpkgs for packages which needed to solve similar issues and stumbled upon Houdini (nixpkgs/pkgs/applications/misc/houdini/default.nix at cbd64d71ea0585c10970ce1c4127ea635945fcd2 · NixOS/nixpkgs · GitHub).

They seem do what I wanted to do initially, the only difference is that it works for them.

The difference is that they use /etc which IIRC is a tmpfs.