Tebako

Tebako 0.8.7 improves package portability on Linux distributions

Author’s picture Maxim Samsonov on 02 Sep 2024

Introduction

We are excited to announce significant enhancements in Tebako v0.8.7 that improve package portability across different Linux distributions.

This update introduces forward compatibility for Linux distributions that depend on the GNU C Library (glibc), offering greater flexibility in deploying your packaged applications on a wider range of platforms.

Package portability

What is portability?

In software development, portability refers to the ability of a software application or package to run on different computing environments without requiring significant modifications. This can include different operating systems, hardware architectures, or versions of system libraries.

Tebako package portability

Package portability has always been a key focus for Tebako. Tebako packages are designed to be "forward portable" across different operating systems and architectures. This means that a package created on a specific platform can be executed on a newer version of the same platform, allowing for easy distribution and deployment.

Tebako now provides the following benefits relating to package portability:

  • Broad compatibility: Packages created with Tebako v0.8.7 are now compatible with a wider range of operating systems and Linux distributions.

  • Forward portability: Packages can run on newer versions of the same platform they were built on.

    • For glibc systems, Tebako provides the --patchelf option which allows packages built on glibc-based systems to run on Linux distributions with glibc 2.31 and above. For example, a Tebako executable package built on Ubuntu 20.04 with the --patchelf option can be executed on Rocky Linux 9.

    • Packages built for the musl implementation of the C standard library (such as Alpine Linux) are forward portable. For instance, a Tebako executable package built on Alpine 3.17 can be executed on Alpine 3.19.

    • macOS packages are forward portable across different macOS versions. For example, a Tebako executable package built on macOS 12 (Monterey) can be executed on macOS 14 (Sonoma), but not vice versa.

  • Cross-architecture support: macOS packages built on x86_64 can run on Apple M (ARM, aarch64) systems.

C standard libraries and package portability

Understanding C standard libraries is crucial for grasping the importance of Tebako’s improvements in package portability. Tebako virtualizes above the system libraries layer, providing a consistent environment for your application to run in. This approach ensures that your application runs smoothly across different platforms, regardless of the system libraries installed on the target system.

The C standard library is a critical component of the system libraries layer, and different Linux distributions use different implementations and versions of the C standard library. For example:

  • Ubuntu and Fedora use the GNU C Library (glibc)

  • Alpine Linux uses the musl C library (musl)

These differences can lead to compatibility issues when deploying applications across different distributions. Tebako addresses these challenges by providing a consistent runtime environment for your application, regardless of the underlying system libraries.

The GNU C library

glibc (GNU C Library) is the most widely-used implementation of the C standard library for Linux systems. It provides core functionality for C programs, including system calls, string manipulation, mathematical computations, and more. glibc is developed as part of the GNU Project and is the default C library for most Linux distributions.

Key characteristics of glibc:

  • Extensive feature set

  • Optimized for performance

  • Complex codebase

  • Uses symbol versioning for backward compatibility

The musl C library

musl is an alternative implementation of the C standard library, designed to be lightweight, fast, and simple. musl is commonly used in embedded systems and distributions focused on minimalism, such as Alpine Linux.

Key characteristics of musl:

  • Smaller codebase

  • Emphasis on correctness and simplicity

  • Static linking friendly

  • Does not use symbol versioning

glibc vs musl: Forward portability differences

General

The approach to forward portability differs significantly between glibc and musl.

glibc forward portability

glibc uses a mechanism called symbol versioning to maintain backward compatibility while allowing the library to evolve. Each symbol (function or variable) in glibc is assigned a version, and multiple versions of the same symbol can coexist within the library.

This approach has advantages and challenges:

  • Advantage: Older binaries can run on systems with newer glibc versions only when the older glibc exist, guaranteeing identical behavior for the binary.

  • Challenge: Binaries compiled against a glibc version may not run on systems without that particular glibc version.

When a program is compiled, it is linked against specific versions of glibc symbols. If this program is then run on a system with a newer glibc version, it may fail to load because the required symbol versions are not present.

Running a Tebako-built package on a system with a newer glibc version will result in an error like this:

$ ./executable
./executable: /lib64/libpthread.so.0: version `glibc_PRIVATE' not found (required by ./executable)

Prior to version 0.8.7, Tebako-built packages need to be recompiled for systems with newer glibc versions.

musl forward portability

musl takes a different approach to forward portability:

This approach results in:

  • Advantage: Simpler forward portability, as binaries are less likely to depend on specific symbol versions.

  • Challenge: May require recompilation for optimal performance on newer systems.

In summary, while glibc offers better backward compatibility, musl provides simpler forward portability. Tebako’s improvements address these differences to enhance package portability across various Linux distributions.

Using --patchelf for glibc forward portability

Background

Around 3 weeks ago, Laurent Martin requested Rocky Linux 9 support in Issue #190. This request was a catalyst for the development of the --patchelf option in Tebako.

The solution

Originally suggested by Michał Matyas, it is apparently possible to achieve forward compatibility on glibc-based systems by stripping symbol version information.

Tebako 0.8.7 now provides the --patchelf option, which allows packages built with "older" glibc (pre 3.24) to work on newer gnu-linux versions. This option modifies symbol version information in the binary after compilation as described in Issue #196.

Benefits

Using --patchelf gives you:

  • Increased compatibility: Binaries can run on systems with newer glibc versions than the one they were compiled against.

  • No source code changes: This solution works without requiring changes to the original source code or recompilation.

  • Flexibility: Developers can compile on newer systems while still targeting older environments.

Usage

The --patchelf option can be applied when creating the Tebako package using the tebako press command:

tebako-build --patchelf ...other options...

This instructs Tebako to apply the necessary modifications to the resulting binary for improved glibc compatibility.

Caveats

Support for glibc forward portable packages is subject to the following caveats:

  1. The --patchelf option is currently experimental.

  2. The --patchelf option is only available for the GNU toolchain, not yet for clang/llvm.

  3. The package is built against the installed OpenSSL version on the system (e.g., 1.1.1), which needs to be present at the target system. If the target system has a different version of OpenSSL, the package will not work.

Support for glibc-dependent Linux distributions

The following table lists the versions of glibc Linux distributions supported by Tebako packages through --patchelf:

Table 1. Minimum versions of glibc Linux distributions that support Tebako packages with forward portability
Distribution Minimal supported version glibc version

Ubuntu

20.04 (Focal Fossa)

glibc 2.31

Debian

11 (Bullseye)

glibc 2.31

Rocky Linux

9

glibc 2.34

Fedora

33

glibc 2.32

CentOS

9

glibc 2.34

Red Hat Enterprise Linux (RHEL)

9

glibc 2.34

Oracle Linux

9

glibc 2.34

Note
See the GitHub repository for the latest information on supported distributions and versions.

Usage of the Tebako Docker containers for packaging is encouraged since it eliminates the effort needed for toolchain setup and configuration.

Best practices for forward compatibility

To ensure the best forward compatibility for your Tebako packages, consider the following best practices:

Define the target environments: Identify the target OSes, architectures, Linux distributions and versions that your application will run on. This helps you determine the compatibility requirements for your Tebako packages.

For glibc systems, use the --patchelf option: When building packages for glibc-based systems, apply the --patchelf option to improve compatibility with newer glibc versions.

Test on target systems: Verify that your Tebako packages run correctly on the target systems before deployment. This helps identify any compatibility issues early on.

Conclusion

Tebako 0.8.7 introduces significant improvements in package portability, particularly for Linux systems depending on glibc and musl. The new --patchelf option allows for greater flexibility in deployments, enabling packages created on Ubuntu 20 to run seamlessly on Linux GNU distributions with glibc version 2.31 and above.

These enhancements have been rigorously tested across multiple distributions, including Ubuntu, Rocky Linux, Fedora, and CentOS, ensuring reliability and performance. They reinforce Tebako’s core benefits of simplified deployment, enhanced security, and consistent application performance across diverse environments.

Looking ahead, we’re committed to further improving Tebako’s portability and usability. We encourage users to explore these new features and provide feedback, as your input is crucial in shaping Tebako’s future development.

To help you get started, we have sample workflows and sample code provided at Tebako Samples.

About Tebako

Tebako is a specialized tool designed to streamline the deployment of application executables using interpreted languages, such as Ruby, with enhanced security and portability. It packages applications along with their dependencies into a single, self-contained executable, eliminating the need for external dependencies.

This approach helps mitigate deployment issues related to environment differences and dependency management, making it easier to ensure that your application runs smoothly wherever it is deployed.

Tebako offers several key features:

  • Simplified deployment: Tebako simplifies the deployment process by packaging your Ruby application and its dependencies into a single executable. This eliminates the need to install and configure dependencies on the target system, reducing the chances of compatibility issues.

  • Enhanced security: By bundling your application and its dependencies into a self-contained executable, Tebako helps protect your code from unauthorized access and tampering. It ensures that your application runs in a controlled environment, reducing the risk of security vulnerabilities.

  • Portability: Tebako enables you to create executable packages that can run on different operating systems, including Ubuntu, Alpine, macOS, and Windows. This allows you to deploy your application consistently across various environments, without worrying about platform-specific dependencies.

Contact information

Contact us if you encounter any problems with Tebako, at our GitHub issues page.

The team is always on the watch for making things easier for Tebako users.

Press on with Tebako!