Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemd: build libudev.so "separately" #97051

Closed
wants to merge 5 commits into from
Closed

Conversation

vcunat
Copy link
Member

@vcunat vcunat commented Sep 3, 2020

Motivation for this change
Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@vcunat
Copy link
Member Author

vcunat commented Sep 3, 2020

So far this is just a quick proof of concept, and in fact tests.installer.lvm.x86_64-linux won't work and I don't know why yet.

@vcunat
Copy link
Member Author

vcunat commented Sep 3, 2020

Note to self: libudev.so build is more tied to systemd than I expected (did I glimpse that it links statically against libsystemd?), so an approach like this might be more maintainable than really trying it to separate from our systemd expression. Of course, without too much work we could additionally reduce the build-time closure (partially) and build time (try instructing ninja to build just specific targets).

@Mic92
Copy link
Member

Mic92 commented Sep 4, 2020

I think it would be easier to build libudev/libsystemd with ninja and than re-use those libraries when building systemd (replacing it with a symlink in postInstall?). Here is an example where I do it for systemd-networkd: https://github.com/Mic92/dotfiles/blob/711f8d5e20fb543267ed0620b9ee0c139675ef27/nixos/modules/networkd.nix#L11

@vcunat
Copy link
Member Author

vcunat commented Sep 4, 2020

I do plan that, but so far there are problems with something else apparently.

@arianvp
Copy link
Member

arianvp commented Sep 4, 2020

We'd have to split systemd and libsystemd first before we can do the systemd and udev split..

@vcunat
Copy link
Member Author

vcunat commented Sep 4, 2020

Can you explain why?

@Mic92
Copy link
Member

Mic92 commented Sep 4, 2020

Libudev seems to not depend on libsystemd.

@Mic92
Copy link
Member

Mic92 commented Sep 4, 2020

But having a separate libsystemd would be also helpful in longterm because it might be easier to patch for musl libc rather than the whole systemd code base.

@vcunat
Copy link
Member Author

vcunat commented Sep 4, 2020

To be clear, it does not depend on dynamic libsystemd. I'm not sure why they link stuff this way ATM: https://github.com/systemd/systemd/blob/v246/src/udev/meson.build#L145

@vcunat
Copy link
Member Author

vcunat commented Sep 4, 2020

Yes, this attempted to separate just the library.

@arianvp
Copy link
Member

arianvp commented Sep 4, 2020

Ignore my ramblings. I thought it was because of udev linking to libsystemd dynamically.

For an initial effort; I wouldn't do too much fancy things; and just keep libudev statically linked to libsystemd. Though I admit it's a bit strange. We could ask upstream why they do this.

If we're building just the libudev target; how large is the output size? Is it significantly smaller than systemd as a whole? Because of not; then this is basically the same as the current PR no? It will come down to still having systemd in the closure twice.

@vcunat
Copy link
Member Author

vcunat commented Sep 4, 2020

Roughly 100x smaller. EDIT: and as written now even libudev isn't twice in there, I think.

@arianvp
Copy link
Member

arianvp commented Sep 4, 2020

But the cycle will be back If you set pkgs.udev to the libudev package. Which I assume is what we eventually want.

However having two udevs (one with and one without cryptsetup) still is a lot better than 2 systemds...

@Mic92
Copy link
Member

Mic92 commented Sep 4, 2020

To be clear, it does not depend on dynamic libsystemd. I'm not sure why they link stuff this way ATM: https://github.com/systemd/systemd/blob/v246/src/udev/meson.build#L145

It seems that libudev was built with a static libsystemd before anyway so this is not big regression size wise. And I still think it should be possible to bring back this libudev in the systemd package by putting a symlink in the package from "$lib/lib/libudev.*" to libudev. Or is the issue that cryptsetup depends on libudev and the other way around?

Copy link
Contributor

@flokli flokli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd feel more comfortable if udev would be its own derivation, in a separate file (and not just an override), only building the udev-related targets (and we pass that into the systemd expression).

Both could use the same src and patches, though.

Comment on lines +29 to +36
[ linuxHeaders libcap curl.dev kmod xz pam acl
libuuid glib libgcrypt libgpgerror libidn2
pcre2 ] ++
stdenv.lib.optional withKexectools kexectools ++
stdenv.lib.optional withLibseccomp libseccomp ++
[ libffi audit lz4 bzip2 libapparmor
iptables gnu-efi
] ++ stdenv.lib.optional withSelinux libselinux;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these probably are not dependencies of just libudev, are they?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was planning to do such reductions after the change actually works.

Copy link
Member Author

@vcunat vcunat Sep 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Now it appears to work fine.)

I tried to start with empty mkDerivation instead of overriding the systemd one, but I couldn't come with anything simple. Just making the meson configure pass isn't easy – it requires lots of stuff that's useless for libudev but I see no easy way of turning these off (*Inputs, mesonFlags, etc.) – honestly it feels that maintainability will be easiest when those two derivations only have minimal differences (full systemd and libudev).

@flokli
Copy link
Contributor

flokli commented Sep 4, 2020

While doing so, we should also remove the udev = systemd; "alias", which would exercise the derivation we built a bit (for example for libfido2)

@andersk
Copy link
Contributor

andersk commented Sep 5, 2020

I suspect that splitting a libudev derivation from the udev+systemd derivation solves problems that splitting a libudev+udev derivation from the systemd derivation does not. The former split means the closure has two compatible versions of libudev.so.1 (and we can replace one with a symlink to the other), but the latter split means the closure has two incompatible versions of libsystemd-shared-246.so.

We apparently didn't fit anymore.  I don't think this test is meant
to (also) check closure size.
@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

@vcunat libudev is in aliases.nix, because it was used at some point (and changed to an alias in April 2018) Nothing inside nixpkgs itself is using it at this point (it'd fail ofborg eval checks too).

I'm talking about the

udev = systemd; # TODO: move to aliases.nix

in all-packages.nix (at around L18299).

We currently use systemd and udev attributes pointing to the identical derivation, which is bad. We don't really know what really needs full systemd, and what only needs the udev bits.

Instead of moving this to aliases.nix (as suggested by the comment), and by this, having to replace udev with systemd everywhere, I'd rather like to see the udev attribute being a proper derivation providing a libudev.so in its udev.lib output (and *udev.pc and libudev.h in the udev.dev output) .

Of course we'd need to verify packages still build after that change (as things like lvm2 also want to see the *systemd.pc file, not the *udev.pc file - which might be an upstream bug).

In the longer run, having packages who only really need udev to declare udev as a build input seems much more desirable, both for closure sizes as well as cyclic dependency problems.

I don't think resurrecting libudev from aliases.nix, and using it inside nixpkgs as well as the systemd and udev attribute is desirable.

@andersk I don't really understand your comment. Why couldn't we (re-)symlink libudev.so.1 inside the systemd derivation to the udev.lib location? Why would we need this in first place? Other applications wanting to link against libudev.so could just ask pkgconfig, and get a location from the udev.lib output back?
If we need to still provide symlinks, why would they be incompatible?

On the other side, why do we need to provide libsystemd-shared-246.so in any udev output? Reading #97051 (comment), ninja might need to intermediately compile libsystemd_static to produce libudev.so.1, but the libsystemd.a file shouldn't need to be in the udev output, should it?

@vcunat
Copy link
Member Author

vcunat commented Sep 5, 2020

This PR provides libudev.pc. There's also udev.pc and I don't see why it should be provided here, though maybe it wouldn't be hard (I haven't looked). That's why pointing udev attribute to this derivation seems confusing to me.

The *.pc files are generally quite indicative of what makes sense to be split (during runtime), and having aliases based on those seem perfectly fine to me, so that packages can express what they need even for derivations that are not split (yet)... though it's perhaps better to avoid cases where we find it very unlikely to split them in the following couple of years.

@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

We /can't/ use aliases.nix, as it'd fail grahamcofborg-eval-package-list-no-aliases - they're only meant for backwards compatibility for thing referring to it outside of nixpkgs (IMHO a questionable thing anyways, as semantics might change too).

Creating a udev = systemd; alias outside aliases.nix doesn't really provide a lot of value IMHO - we effectively don't know it's wrong, and whether packages really need systemd or udev.

Given the dependency cycle has been resolved for now with #97008, and we don't need to rush this, can we give this some more research?

I could envision udev.dev shipping both udev.pc and libudev.pc, with udev binaries in udev.bin/udev.out, and libudev in udev.lib.

@vcunat
Copy link
Member Author

vcunat commented Sep 5, 2020

I could see that... but as the derivations are written so far, to get udev.pc you basically need to build the systemd attribute, and you can't use that as a build-time dependency of lvm2 (for example).

@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

I could see that... but as the derivations are written so far, to get udev.pc you basically need to build the systemd attribute, and you can't use that as a build-time dependency of lvm2 (for example).

Yeah, as written here, the udev and systemd derivations would need to be much more separated (and only share src and patches)

@vcunat
Copy link
Member Author

vcunat commented Sep 5, 2020

we don't need to rush this

For 20.09 I think it would be preferable to have some improvement in about one week. (than the current solution with two systemds in most closures)

@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

It's a 28MB closure size increase, yes. But it's probably fine to ship 20.09 even with that.

Splitting udev and systemd is something that probably takes more time than we have to properly fix it before the 20.09 release, and I don't think the current proposed approach improves matters from a maintainability factor. IMHO, we should just go with the closure size increase for now, work on a proper fix in unstable, and if the fix is not too invasive, it can probably be backported (but I think it does require quite some changes in many packages).

@andersk
Copy link
Contributor

andersk commented Sep 5, 2020

@andersk I don't really understand your comment. Why couldn't we (re-)symlink libudev.so.1 inside the systemd derivation to the udev.lib location? Why would we need this in first place? Other applications wanting to link against libudev.so could just ask pkgconfig, and get a location from the udev.lib output back?
If we need to still provide symlinks, why would they be incompatible?

Perhaps you are reading the opposite of what I wrote? I said exactly that we can make such a symlink because the two libudev.so.1s are compatible. This is why it does makes sense to split off a libudev derivation.

This libudev.so.1 symlink would also work with a udev derivation, but other things don’t:

On the other side, why do we need to provide libsystemd-shared-246.so in any udev output? Reading #97051 (comment), ninja might need to intermediately compile libsystemd_static to produce libudev.so.1, but the libsystemd.a file shouldn't need to be in the udev output, should it?

The systemd-udevd and udevadm binaries link against libsystemd-shared-246.so—you can see this with ldd. AFAIK, the libsystemd-shared-246.so from a udev derivation would not be compatible with the libsystemd-shared-246.so from a systemd derivation. (Unless we gave it the same build inputs as systemd, but then we can’t break the cycle, which I thought was the whole point.) This is why it does not make sense to split off a udev derivation.

(Sorry if the emphasis and repetition comes across as patronizing…there are certainly things I could be wrong about here, but I want to make sure we’re communicating correctly so we can figure out where that might be.)

@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

@andersk right - splitting systemd-udevd from systemd won't probably work, and not sure how udevadm interacts with systemd (and whether it's worth digging into it).

So after a second thought, calling this other derivation libudev would make sense - but it should really be its own derivation (only sharing src and patches with the systemd expression) - and we should check all current udev=systemd buildInputs in other packages, to see if those can be replaced with libudev.

@vcunat
Copy link
Member Author

vcunat commented Sep 5, 2020

As I wrote above, it would be nice for it to be "independent" derivation, but I can't see how to do that. The configure phase isn't easy to satisfy, nor easy to cut down to just libudev. Or at least I didn't find such a way; maybe someone else will have an idea how to approach it.

@vcunat
Copy link
Member Author

vcunat commented Sep 5, 2020

🤔 this PR actually seems very close to the currently merged workaround, only with the binaries "deduplicated" (i.e. anything but libudev deleted from the first result, and libudev replaced in the second result).

gdamjan added a commit to gdamjan/tt-rss-service that referenced this pull request Sep 16, 2020
Not only does nixos not have a split systemd.lib package, it also gets
two copies of systemd in the image:
NixOS/nixpkgs#97051
NixOS/nixpkgs#98094

Let's not include it for now, the only detraction is that the
systemd/journald logger wont be available in uwsgi.
gdamjan added a commit to gdamjan/tt-rss-service that referenced this pull request Sep 16, 2020
Not only does nixos not have a split systemd.lib package, it also gets
two copies of systemd in the image:
NixOS/nixpkgs#97051
NixOS/nixpkgs#98094

Let's not include it for now, the only detraction is that the
systemd/journald logger wont be available in uwsgi.

On the good side, the image went from 50MB to 30MB now.
gdamjan added a commit to gdamjan/tt-rss-service that referenced this pull request Sep 16, 2020
Not only does nixos not have a split systemd.lib package, it also gets
two copies of systemd in the image:
NixOS/nixpkgs#97051
NixOS/nixpkgs#98094

Let's not include it for now, the only detraction is that the
systemd/journald logger wont be available in uwsgi.

On the good side, the image went from 50MB to 30MB now.

The image is built against the `my-20.09` branch of nixpkgs, that is
based on the release-20.09 branch with uwsgi fixes added.
@gdamjan
Copy link
Contributor

gdamjan commented Sep 18, 2020

The Arch package has a relatively simple approach to this, in its split package for systemd/systemd-libs.

It boils down to these two lines, that copy the libraries that are then shipped in systemd-libs package:
https://github.com/archlinux/svntogit-packages/blob/packages/systemd/trunk/PKGBUILD#L177-L179

@vcunat
Copy link
Member Author

vcunat commented Sep 18, 2020

Well, yes... other distros don't have this strict automatic detection of references (cycle between systemd and some of its libs) and they can keep all output in the shared /usr/ tree, so it's easier for them to do such things.

@flokli
Copy link
Contributor

flokli commented Sep 25, 2020

@vcunat would a systemdMinimal, as proposed in #98299 solve this sufficiently, as in, is the closure size acceptable?

Given you apparently need dbus to build systemd, which needs systemd itself, a libudev.so only wouldn't get us that far in the longer run anyways…

@arianvp
Copy link
Member

arianvp commented Sep 25, 2020

Given you apparently need dbus to build systemd

@flokli
Looking at the systemd source code, the libdbus dependency is optional and only used in the test suite. Given that we don't build the test-suite it seems we can just remove the dependency completely.

@stale
Copy link

stale bot commented Jun 4, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jun 4, 2021
@flokli
Copy link
Contributor

flokli commented Aug 4, 2021

I think the systemdMinimal approach, which we already ship for some time is sufficient. Reopen if you disagree ;-)

@flokli flokli closed this Aug 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants