Hacker News new | past | comments | ask | show | jobs | submit login

Well for the most part because it uses what unix offers rather than ignoring it.

The basic problem with most package managers is that they ignore the soname mechanism.

https://en.wikipedia.org/wiki/Soname

This allows multiple versions of a lib to live side by side, while giving the binaries the version(s) they want.

package managers ignore this, and instead is hung up on getting that one "true" version everywhere. This because their basic design only allow one version pr package name. Thus you can't have ABC 1.0 and 1.1 installed at the same time. Instead you have to mangle ABC into something like ABC1 to allow 1.1 to install without removing 1.0 in the process.




I wouldn't strictly blame the package managers. Last I checked, it's not straight-forward to link against any library version other than what the versionless .so symlink points to (-llibname will always use liblibname.so). The lame workaround is to move a portion of the version into the basename, and that's where you get libname2.so, so you can explicitly ask for it with -llibname2). You can specify the path of the library file to link against, but this doesn't get you the same dynamic linking semantics (and you really want to let the linker search the cache for the exact file rather than having to specify the path yourself).

It's actually pretty straight forward to build multiple packages with the same name and different versions that can be installed side-by-side: it's like a single line in an RPM spec file, as long as the files list doesn't conflict. A lot of the required effort is in building the software that uses the library. The library's header files are not often in versioned paths, so the -devel package for multiple versions has conflicts. It's easier to specify the option to configure that installs all the files with a version suffix and just be done with it. It is, unfortunately, not in the interest of the person doing the packaging to significantly diverge from how upstream suggests it be installed in their docs. That is, what should happen is entirely doable but, as part of the larger ecosystem of software and packaging and distributions, it's complicated and has little payoff.


From my experience, as long as -soname is provided to ld, the rest should sort itself.

At least it seems to work wonderfully for daily usage on Gobolinux.


I'm not sure exactly what you're referring to; the -soname ld option is used to set the value internally to a library that that library is known as when building a library, and is used as part of ld.so at runtime to find the appropriate .so file to run-time dynamically link against.

The issue I described is during build time of a program that uses a shared library. Given this list of available libraries:

    lrwxrwxrwx     21 Apr 20  2011 libevent.so.2 -> libevent.so.2.1.3
    -rwxr-xr-x 106656 Aug 20  2010 libevent.so.2.1.3
    lrwxrwxrwx     21 Jun  3  2012 libevent.so.5 -> libevent.so.5.1.3
    -rwxr-xr-x 277760 Jun  3  2012 libevent.so.5.1.3
    lrwxrwxrwx     21 Jun  3  2012 libevent.so -> libevent.so.5.1.3
there is no way to use the -levent option to gcc or ld to specify you want to link against libevent.so.2. If you just give it -levent, it will always link against libevent.so, which as these symlinks show, is pointing to libevent.so.5.1.3 (which is actually libevent-2.0) — this is documented in the ld man page under the -l option as for how "namespec" is resolved. Unfortunately, the APIs are different between 1.4 and 2.0, which is why this is necessary: not everyone who uses libevent has updated their code to use the new libevent API, yet we still want to use that software.

The "fix" is to move some kind of "logical" version number into the filename (although, which is "logical" and which is "physical" becomes ambiguous), like so:

    $ ll libevent[-.]*
    lrwxrwxrwx     21 Apr 20  2011 libevent-1.4.so.2 -> libevent-1.4.so.2.1.3
    -rwxr-xr-x 106656 Aug 20  2010 libevent-1.4.so.2.1.3
    lrwxrwxrwx     21 Jun  3  2012 libevent-2.0.so.5 -> libevent-2.0.so.5.1.3
    -rwxr-xr-x 277760 Jun  3  2012 libevent-2.0.so.5.1.3
    lrwxrwxrwx     21 Jun  3  2012 libevent.so -> libevent-2.0.so.5.1.3
so you can obtain a linkage against 2.1.3 by specifying -levent-1.4. This "encourages" one to use the 2.0 API by using libevent-2.0 if you specify a bare -levent. The -devel package with the header files will usually be for the latest version anyway, complicating the build process on a single machine with both libraries available (you'd have to build against a local/non-system-include-tree copy of 1.4's headers). I know some redhat/centos packages do do this (which is why I have both libevent-1.4 and libevent-2.0 on my system, but I don't know how those packages' specifically do this.

The other way around this is to explicitly link against the full path /usr/lib64/libevent.so.2.1.3 and not use the -l option at all for this library. This works in part because of the -soname option you pointed out. While this works, and produces the same output if one could use -l to select the correct library file, most of the build tools we have at our disposal prefer to use -l to select libraries at build time rather than full paths (because if you use -l to select a system installed library, ld does the work of searching its cache and standard paths for you; however, you can get around this with the :filename version of namespec to the -l option). This means that some programs' build processes would be different on systems that have only the old, only the new, or both libraries on the system, and a bunch of programs build processes might need to change once the new version comes out.

The problem here is that -l only lets you specify the name, not the version to link against, under the (arguably well-founded) assumption that old versions should not be used for new builds but you need to keep them around for already-built programs to link against (dynamically, at run time).


> The basic problem with most package managers is that they ignore the soname mechanism. ... This allows multiple versions of a lib to live side by side, while giving the binaries the version(s) they want.

I see you've qualified your statement with "most", so you're not in the wrong, but unless I'm mistaken both Nix[1] (and NixOS) and Guix[2] handle this problem well and do it in a way which scales infinitely.

[1] https://nixos.org/nix/

[2] https://www.gnu.org/software/guix/


> The basic problem with most package managers is that they ignore the soname mechanism.

Well, there's a million hobby project package managers, so I'm sure many of them fall in to that category. But the big ones, the ones used by the vast majority of linux users, don't have a problem with this (deb and rpm-based distros commonly version their libraries and install multiple versions side-by-side). This is a pain in the ass for the package maintainers as a lot of software developers don't think about versioning their API, but it's great for users.


Which package manager are you thinking of? The dpkg ecosystem (i.e. Debian and Ubuntu etc.) definitely uses sonames. It is true that the soname version ends up in the package name, but this happens automatically, at build time, and it's only the binary package name that carries the soname, the source package remains unchanged.


So does redhat & spinoffs.

You can install[] packages with libxyz.1.so and libxyz.2.so; you cannot install two -devel packages, because that package contains symlink libxyz.so to specific version.

Often, the system even installs such packages for you (they have compat in package filename, i.e. compat-libstdc++).

[] provided they don't contain additional files with assets, that conflict with each other. But this problem is not solved by gobo either.




Consider applying for YC's first-ever Fall batch! Applications are open till Aug 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: