https://discourse.nixos.org/t/announcing-nomia-a-general-res...
Package names in guix are very consistent, lowercase and hyphen-separated. I recall some nix packages having capital letters in them. It could certainly be confusing.
For declarative user packages, guix has manifests. This is a first class feature. You make a list of packages in a .scm file and apply it, which adds or removes things as needed. With Nix you need to use Home Manager, which isn't part of the main Nix project. A bit of a shame, as this declarative package management is a big selling point, and separating system and user packages lets you have a small system list for fast kernel upgrades and such, while you can keep stuff like icecat in user profile and know that the user package updates may take longer. (especially if there's no substitute and it has to be built)
I think more care is taken to making things simple for the user with guix. What you lose out on is number of things packaged. However, I find guix packages generally have less problems. Nix's mpv package performed worse than guix's with guix being on two generations older hardware (ThinkPad X220T w/ i5 being better than ThinkPad T440p w/ i7). I also ran into strange bugs in some things like pcmanfm. It may be not every package gets much attention and use.
I would say I'm an average user as far as just using my system but not contributing much aside from bug reports.
Note: In all examples I was using each package manager on its home distro, not a foreign distro.
Another advantage of Guix is just how readable package definitions are. Nix packages often contain embedded shell code + a "functional" DSL. Guix packages are written in a much more declarative style. It kind-of looks like executable JSON (I guess that's the point of lisp, right?).
But in terms of support, I must say Nix is currently ahead of Guix. It has a large quantity of packages that surpasses any other distros[1], (almost) all of which goes through review. It also has support for non-Linux platforms, namely macOS and BSDs. The community is large and active, and there are various avenues which you can reach out for help.
So if you're interested in either but don't know which to choose, I'd recommend Nix. If you're feeling adventurous and also like Scheme, Guix would be the way to go.
Isn't there a race-condition here -- like if I invoke a program at the wrong time while it's in the process of changing symlinks, could it pick up the wrong libraries or something? Does Linux OS allow a "changeset" of files to be locked and altered together in a batch, or anything like that?
Each Nix package, as packaged, has a hard-coded dependency on the specific hashed versions of all its dependencies. For instance, if you're building NPM and its build scripts hash to abcd1234, and it depends on Node.js whose build scripts hash to dcba4321, then /nix/store/abcd1234-npm-1.0/bin/npm has a hard-coded reference to /nix/store/dbcd4321-nodejs-1.0/bin/node.
Symlinks come into play with user profiles - you don't want to type in that full path to npm every time, so you put ~/.nix-profile/bin on PATH and you tell Nix to make ~/.nix-profile/bin/npm a symlink to /nix/store/abcd1234-npm-1.0/bin/npm.
But there isn't a race condition in the underlying packages, which are all immutable and more importantly co-installable. If you want to upgrade to Node.js 1.1 and its hash is fedc9876, then it gets installed to /nix/store/fedc9876-nodejs-1.1. And if you rebuild npm against that (even without changing its version), the hash of npm's build scripts changes as a result, and it ends up in, say, /nix/store/aaaa1111-npm-1.0.
If you upgrade your personal profile to the latest version of everything, then Nix will install those two new directories into /nix/store, repoint the symlink in ~/.nix-profile/bin/npm, and then (eventually) garbage-collect the two old directories.
But at no point does the execution of code within Nix rely on mutable symlinks. (As far as I know.)
Simply, if package A depends on package B then A's files will end up mentioning the absolute path to B directly (say, /nix/store/abcdef-b-1.0/bin/some-bin-file, where "abcdef" is a hash).
If package C depends on a different version of package B, then C's files will contain the path to a version of B with another hash and possibly a different version number (say, /nix/store/zywxabc-b-1.1/bin/some-bin-file).
I was thinking that nix would symlink /bin/A -> /nix/store/abcdef-A-1.0/bin/A, and also /usr/share/A.res -> /nix/store/abcdef-A-1.0/usr/share/A.res
So when I'm upgrading to A-1.1, maybe the /bin/A symlink would update a moment before the /usr/share/A.res symlink, which means invoking A at around the same time as the upgrade could pick up the wrong resource.
Do we just try to make sure that binaries know to look for resources relative to their binary-path? Or do we use chroot/containers? Sorry if this is a dumb question :)
Take a Python service started by systemd. The systemd ExecStart points directly to the immutable Nix path of the script, and the script also has a shebang that points directly to the immutable Nix path of the Python interpreter. (The Python interp in turn also links to libraries via direct Nix paths, etc.)
edit: maybe you're describing what happens if a program is run while a Nix expression is being applied; I believe what happens in that case is that the program that was being run will work fine since its environment is pointing to the previous generation, and applying the new expression creates a new generation
By writing a Nix package for it (I don't mean for this to sound flippant, tone is a bit hard to convey over text).
For example I have this alpha quality rust binary that I'm developing but I also want a stable version installed at the OS level. I write a Nix package and simply compose it into my overall NixOS configuration alongside the more official Nixpkgs: https://github.com/rraval/nix/blob/master/git-nomad.nix
> like a source code tarball where you would traditionally run configure && make && make install?
Nix has a bunch of defaults that make a conventional package like this straightforward.
Here's a package for a vanilla C binary + library that does the `autoreconf && ./configure && make && make install` dance: https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/secu...
It's almost a little misleading because the actual steps are largely inherited from the defaults, you can read more about `stdenv.mkDerivation` here: https://nixos.org/guides/nix-pills/fundamentals-of-stdenv.ht...
When it does, I either:
* build it via Nix, 10-15 lines, equivalent to packaging it.
* build it in a nix-shell that contains its dependencies
src = ./some-source-dir;
or src = ./.;
or whateverSure, it still works. And in the off-chance that you need to make a patch that changes the ABI, recompiling the world is exactly what you want. But usually you don't need to change the ABI (at least not in a backwards-incompatible way), and recompiling the world can take a very long time.
1) Decide you want that patch to be applied to everything, resulting in recompiling the world.
2) Apply the patch for only the specific project you are working on/testing/etc. Thus only that thing is recompiled.
3) You can cheat in various ways if your project truly requires being updated by only changing the glibc and no recompilation is feasible. Some options: the way OpenGL and graphics is currently done in NixOS, nix-rewrite (https://github.com/timjrd/nixrewrite), and LD_PRELOAD. Breaking the abstraction in this way may have practical benefits, but you also lose the reproducibility and excellent bookkeeping of all the details that Nix provides.
4) specify a container/project/VM that uses your patched glibc, so only those things are rebuilt that matter in your use-case.
The crux of the matter is that we need to be more precise in the names of things. Most of the time "glibc" refers to whatever is on your system on the same path. Nix has taken the other extreme where you can't just say "glibc", you really mean "this particular source, compiled with this particular set of flags and build script". If you want something more powerful\and between those extremes, there is some work currently on a system called Nomia that attempts to provide a far richer naming semantics, but it is still experimental. https://github.com/scarf-sh/nomia It would allow something like "glibc means anything ABI compatible with this particular thing, plus some other requirements...."
I lack the technical know how behind it, but if the output of a package doesn't change on changing one of the inputs then nix will not rebuild it's cache.
The interesting case would be if you build separate build-time and runtime interfaces - like a libc.so that just has dummy symbols for everything that it defines but no actual implementations, and a libc.so.6 with the actual implementations that can change.
While most Linux distributions have the split of filenames, it's not actually done in this way - libc.so is a symlink to libc.so.6 (or in the specific case of glibc, a linker script), so it requires the actual libc.so.6 to be around and used during the build.
It would also be a bit of a semantic change in how Nix operates, as I understand it: currently you can run ./configure scripts that detect the behavior of libraries by actually running code, and if that behavior changes, Nix guarantees a rebuild. If you remove runtime libraries from what's visible during the build, you can't run such scripts anymore (or you're running them against a version of the library that doesn't trigger rebuilds when it changes).
I've published a correction: https://zeroindexed.com/nix-ejection-problem#on-gentoo
I don't think I've ever actually used boot.kernelPatches, either, and I could see myself overriding the whole kernel package instead
Ourselves, it seems. A Javascript framework is like a jet, and we are the human payload. You can stay in the jet, zooming over the constantly changing landscape. But if you get tired of this zooming around (or if you get scared of hitting a mountain), then you can activate the ejection seat (https://en.wikipedia.org/wiki/Ejection_seat). Of course, now you're a mile high without a plane, but the ejection-seat comes with a parachute, so the descent will be pleasant (or, at least, non-fatal - which is a style of pleasantness).
Erm, wait, I think you were soliciting a more literal answer. :)
"create-react-app" is the Javascript framework/jet. If you want to go for the ride, then you declare a single-dependency on "create-react-app", and they will decide when/what/how to upgrade components in the framework. If you don't want to ride along with "create-react-app"s framework, then you "eject". They'll give you a little bundle (the concrete list of dependencies) and send you off on your way.
(In this context, I think what is being "ejected" is the build dependency automatically added by create-react-app.)
I don't think it's a perfect analogy, but I see what the author is getting at - you need to break the abstraction of some packaging tool, but you want the functionality it provided to still work as well as possible.
You got it. I don't think it's the best analogy either but it is pithy and works if you squint.
The essence is:
1. create-react-app is a monolithic transformation of a bunch of disparate tools into a managed workflow.
2. You can update create-react-app like any other dependency and get updates to the workflow.
3. At any point, you can break the abstraction via `npm run eject`, which drops you down a level into the raw configuration for the "disparate tools" that create-react-app was acting as a veneer over. This ejection is a point in time transformation, you no longer get the managed workflow updates from (2).
The analogy was:
1. The Linux kernel package on $DISTRO is a monolithic transformation of Linux kernel source code to Linux kernel binaries.
2. You can get updates from the package manager.
3. At any point, you can break the abstraction by dropping down a level and forking the current packaging script to adjust the transformation (like applying a patch). This fork is a point in time transformation, you no longer get the package updates from (2).
"You're on your own, buddy. Good luck!"