Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I build a static-linked ELF binary from a Python project, can I run it on every Linux distribution?

I'm working on converting a Python package to a more efficient version by porting it from Python to C++ using pybind11.

The performances are really better, but now I have to distribute it.

It's an "internal product", only used by my company, so we don't have licence issues, but it can be used on a large variety of systems.

For windows users, I made a full static build for the last 4 major Python versions, and it can be used by everyone, on any windows version.

Can I do the same for Linux?

I plan to build a full statically linked .so Python extension for the last 4 majors Python version.

I have some dependencies to third party library, which I plan to also build full static, like I've done on Windows.

Will it work on Debian/CentOs/whatever, considering versions not older than 10 years (we have old systems...), or will I have to face dependencies problems (about system libs, libc or any other)?

like image 273
Aurelien Avatar asked Oct 27 '25 15:10

Aurelien


2 Answers

In Python world, for binary package, you need to build a wheel.

There's standard Python recommendations on compilation and distribution Linux binaries: PEP 599 + PEP 600, which describe which glibc versions to target and which libraries are allowed to be linked for broad compatibility.

The wheel packages have tags in them, which are used to choose between different versions/ABIs/libc implementations, if any.

There's official Docker containers for compilation: manylinux. It includes several Python versions in a single container. There are many containers based on different OS available, I recommend using manylinux_2_28 — it's based on AlmaLinux 8, which is recent on one hand, but have broad compatibility with other distros from the last 6-7 years.

Basically what you need is:

  1. From manylinux_2_28, compile wheel using Pythons from /opt/python/ (3.8 - 3.14rc3, as of writing time): /opt/python/cp311-cp311/bin/pip wheel -w wheelhouse .
  2. Run auditwheel repair --plat manylinux_2_28_x86_64 wheelhouse/*.whl to make sure that your wheel is not linked with improper libraries (see PEP 599).

That's it!

If you need to support even older OS, and your C++ code is not too fancy for the older compiler, consider using manylinux2014 — it supports everything from the last decade.

P.S. you can check glibc versions of various distros on distrowatch.

like image 83
ValdikSS Avatar answered Oct 29 '25 04:10

ValdikSS


(Note that his answer does not address Python-specific parts of the question, only linking in general. It is useful if you want to avoid the system Python installation.)

No. It might work for some distros for some years, but not reliably and not forever.

It doesn't matter that the Linux kernel allegedly doesn't break userland; the kernel is far from the only interface you rely on.

There have been several occasions where, say, something about the filesystem layout changes. When this happens, programs that have statically-linked to old versions of libc can no longer run. If you're aware of a distro shipping static binaries from 20 years ago, try downloading the old archives and see how much has broken.

Dynamically linking to libstdc++ (or libc++ if you're using that, but it's always a second-class citizen on Linux distros) and the various C libraries (there are quite a few you might be using; read the contents of <gnu/lib-names.h>), but statically linking to all other libraries, is much more likely to work. This is trivial to accomplish with appropriate linker flags, but highly dependent on your build system. The cleanest way is --push-state -Bstatic insert-non-system-libraries-here --pop-state insert-system-libraries-here, likely wrapped with -Wl.

If you need portability to distros with system libraries older than the one you're compiling on, use an $ORIGIN-relative rpath and ship the libraries (be sure to include the pointer to the source code) alongside your binary. The end-user can simply delete the libraries if their distro is new enough. If your program requires filesystem-based privileges (setuid, setcap, etc.), do not do this (but such programs are almost always shipped as part of the distro in the first place); there is much FUD about rpath on the Internet, but this is the only case where it might be dangerous.

like image 36
o11c Avatar answered Oct 29 '25 05:10

o11c