skip to Main Content

I have dependencies in my code that requires libc. When building (cargo build --release) on Ubuntu 20.04 (glibc 2.31) the resulting executable doesn’t run on CentOS 7 (glibc 2.17). It throws an error saying it requires GLIBC 2.18.

When build the same code on CentOS 7 the resulting executable runs on CentOS 7 and Ubuntu 20.04.

Is there a way to control which GLIBC version is required to build this version on Ubuntu 20.04 too?

3

Answers


  1. In general, you need to build binaries for a given OS on that OS, or at the very least build on the oldest OS you intend to support.

    glibc uses symbol versioning to preserve the behavior of older programs while adding support for new functionality. For example, a newer version of pthread_mutex_lock may support lock elision, while the old one would not. You’re seeing this error because when you link against libc, you link against the default version of the symbol if a version isn’t explicitly specified, and in at least one case, the version you linked against is from glibc 2.18. Changing this would require recompiling libstd (and the libc crate, if you’re using it) with custom changes to pick the old versioned symbols, which is a lot of work for little gain.

    If your only dependency is glibc, then it might be sufficient to just compile on CentOS 7. However, if you depend on other libraries, like OpenSSL, then those just aren’t compatible across OS versions because their SONAMEs differ, and there’s no way around that. So that’s why generally you want to build different binaries per OS.

    Login or Signup to reply.
  2. If your project does not depend on any native libraries, then probably the easiest way would be to use the x86_64-unknown-linux-musl target.

    This target statically links against MUSL Libc rather than dynamically linking against the system’s libc. As a result it produces completely static binaries which should run on a wide range of systems.

    To install this target:

    rustup target add x86_64-unknown-linux-musl
    

    To build your project using this target:

    cargo build --target x86_64-unknown-linux-musl
    

    See the edition guide for more details.

    If you are using any non-rust libraries it becomes more difficult, because they may be dynamically linked and may in turn depend on the system libc. In that case you would either need to statically link the external libraries (assuming that is even possible, and that the libraries you are using will work with MUSL libc), or make different builds for each platform you want to target.

    If you end up having to make different builds for each platform, a docker container would be the easiest way to achieve that.

    Login or Signup to reply.
  3. Try cross.

    Install it globally:

    cargo install cross

    Then build your project with it:

    cross build --target x86_64-unknown-linux-gnu --release

    cross take the same arguments as cargo but you have to specify a target explicitly. Also, the build directory is always target/{TARGET}/(debug|release), not target/(debug|release)

    cross uses docker images prebuilt for different target architectures but nothing stops you from "cross-compiling" against the host architecture. The glibc version in these docker images should be conservative enough. If it isn’t, you can always configure cross to use a custom image.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search