Inside a flake, is there a way to do things conditionally, depending on whether the underlying OS is NixOS or MacOS, as opposed to any other system?
I’m trying to provide something that depends on graphics drivers and works seamlessly for the end user. On NixOS and MacOS, everything works fine; on everything else, nixGL is needed. I want a robust way of absolving the user from needing to care about whether nixGL is used or not.
How does system distinguish between NixOS and non-NixOS? For example, the system on the machine where I am writing this is x86_64-linux. How does this help the flake determine whether this is NixOS as opposed to Debian, Ubuntu, Alpine, Arch or anything else that is NOT NixOS?
You were asking about NixOS /MacOS and that would give you x86_64-linux and aarch64-darwin.
Distinguishing between e.g. NixOS and Debian is something different: It is essentially the same system, so it gets te same value in system and the resulting binaries should be runnable on each Distro.
You either have to explicitly create two outputs (e.f. foo and fooWrapped) and manually select the right one depending on where you want to run your flake output, or create an intelligent wrapper that looks into /etc/os-release and calls dynamically runs the program with or without nixGL.
In essence, this is a runtime decision and can only happen after the build.
What do you need this distinction for? Packages are already scoped by system… NixOS and Darin configurations can only be one, not the other, and in HM you can check for pkgs.stdenv.isLinux/pkgs.stdenv.isDarwin respectively.
Perhaps I should have avoided the word ‘system’ as it might be confused for Nix’ system.
As I said in the original question:
the point being that on NixOS and MacOS everything graphics related Just Works, whereas on other OSes nixGL is required to make it work.
I want the flake not to waste time and space and otherwise complicate matters by including nixGL where it is not needed (MacOS and NixOS), and I want whatever interface I give the user to run the software, to wrap things in nixGL where needed, and not do so where not needed.
I can imagine a number of different approaches, as long as I can reliably distinguish between these two categories:
NixOS or MacOS,
everything else.
Thus, before getting into any other details, I’d like to have a reliable way of telling apart the above categories inside a flake.
Obviosuyl, nixGL is not needed if stdenv.isDarwin.
For Linux there is no pure way.
So I would do the following:
Always pull it
create a wrapper that checks for the existence of /etc/NIXOS and if it is missing runs through nixGL, and directly if it exists.
provide an argument via overrides, that allows to disable nixGL completely for users who know what they are doing.
Or just tell users that they should learn how and when to use nixGL themselves, because I might get aggressive when using your program would require me to use --impure to build my config all of a sudden, just because you depend on nixGLs impure or nvidia thing…
As NobbZ wrote, whether you need nixGL is a property of the runtime environment and not known to the build environment. On the other hand, a flake output is supposed to give a reproducible result, regardless of the build environment.
If you put in the constraint that your flake is always built on the same system where it runs, you can build it with the --impure flag and branch in your build. Note that this will conflict with using a cache etc.
With a little hack you can, however get a pure build and lazy fetching of nixGL:
Instead of building nixGL and putting it in your wrapper function, you can have the wrapper function check for the runtime environment and then have the wrapper run
nixGL as nix run --override-input nixpkgs nixpkgs/pinned-to-commit --impure github:nix-community/nixGL-pinned-to-commit -- your-program. The commit-hashes for pinning can be derived during the build.
This will increase startup-time on Non-NixOS (first time and probably after GC) and require internet access, but may be the closest you can achieve to what you are aiming for.
We have a wrapper like this (written when 23.05 was the latest stable):
if system_requires_nixgl && cli_requires_nixgl $@
then
echo Running with nixGL
nix run --impure --inputs-from .# github:guibou/nixGL -- "$@"
else
echo Running without nixGL
"$@"
fi
but ran into issues with mismatching versions of glibc between nixGL and everything else.
Can you comment on the difference between --override-input and --inputs-from?
I’m afraid that, under our circumstances, this is simply not an option. We have to cater for users who have never head of Nix, do not care about Nix, might be hostile to the idea that something like Nix might be used, and whose capacity to learn anything is already being stretched beyond breaking limits by the complexity and bugginess of the underlying software. Our value proposition is that, if they can just install nix on their machine once, then they are entirely absolved of the burden of installing and configuring the software. Asking them to learn anything about Nix or its ecosystem, beyond how to run the installer once, is simply not an option in our situation.
You can not get rid of this. A similar problem exists with running graphical programs from unstable on stable as well, especially close to the end of a releases lifetime.
The only solution for this is to make sure that the hosts GLIBC and the nixpkgs GLIBC are of the same version.
Essentially only whether you pass the pins via command line or read them from a another flake. With your solution above the pins are resolved at runtime, depending on whatever flake nix can locate. With --override-input it is easier to pin the inputs to nixgl to a fixed revision.
The host’s glibc? I was under the impression that the flake’s outputs use a glibc defined by the flake, and that this is independent of the host. So I assumed that making nixGL follow the inputs of the flake should ensure compatibility of the glibcs between them, and that the host doesn’t matter.
We’re talking about a scientific framework that has been developed over three decades (if you ignore its previous incarnation in FORTRAN). It has many huge flaws and problems, but it is the only game in town as far as this topic in this culture is concerned. I’m trying to mitigate some of its problems, but telling people to use something else, or rewriting it, is simply not an option.
I agree, thats not an option, though this was some context that you missed to tell us before.
In that case you are basically out of luck and using a docker container might be more reliable, once you managed to configure GPU passthrough correctly…
It is sad to say, but once you are combining GPU and nixpkgs and FHS-linux, things will break one way or the other.
There is no “I do not care to understand and want to have it work out of the box” solution to this.
Other than telling your users “here is your system, built for this one purpose, don’t install steam on it, it is for your research with this one program”