How to static link Linux software that uses ./configure?

Learn how to static link linux software that uses ./configure? with practical examples, diagrams, and best practices. Covers linux, gcc, configure development techniques with visual explanations.

Static Linking Linux Software with ./configure

Hero image for How to static link Linux software that uses ./configure?

Learn how to successfully static link applications on Linux, especially those using the common ./configure && make && make install build system, to create self-contained executables.

Static linking is a powerful technique that bundles all necessary libraries directly into an executable, creating a self-contained binary that doesn't rely on external shared libraries at runtime. This can be incredibly useful for deployment to environments with minimal or inconsistent library versions, or for creating portable tools. However, achieving a fully static build, especially for software that uses the common GNU Autotools build system (./configure, make, make install), can be challenging. This article will guide you through the process, highlighting common pitfalls and solutions.

Understanding Static vs. Dynamic Linking

Before diving into the how-to, it's crucial to understand the fundamental difference between static and dynamic linking. Most Linux software uses dynamic linking by default, where executables link against shared libraries (e.g., .so files) at runtime. This saves disk space and memory, as multiple programs can share the same library. Static linking, on the other hand, embeds a copy of all required library code directly into the executable. While this results in larger binaries, it eliminates runtime dependencies on external libraries.

Hero image for How to static link Linux software that uses ./configure?

Comparison of Dynamic vs. Static Linking

Prerequisites for Static Linking

To successfully static link, you'll need the static versions of all libraries your software depends on. These are typically identified by a .a extension (e.g., libz.a instead of libz.so). On most Linux distributions, these are provided in development packages, often suffixed with -dev or -static. For example, to get the static version of zlib, you might install zlib1g-dev or zlib-static depending on your distribution.

sudo apt-get install build-essential
sudo apt-get install zlib1g-dev libssl-dev libcurl4-openssl-dev # Example for Debian/Ubuntu
sudo yum install zlib-static openssl-static libcurl-static # Example for CentOS/RHEL

Installing common static library development packages

Configuring for Static Linking with ./configure

The ./configure script is designed to detect your system's capabilities and available libraries. To instruct it to prefer static libraries, you typically use the --enable-static and --disable-shared flags. Additionally, you might need to pass specific compiler and linker flags via environment variables like CFLAGS, LDFLAGS, and LIBS.

./configure --enable-static --disable-shared

# More robust approach, forcing GCC to prefer static libraries
# LDFLAGS="-static" ./configure --enable-static --disable-shared

# Even more specific, if you know the exact libraries
# LDFLAGS="-static -L/path/to/static/libs" LIBS="-lstaticlib1 -lstaticlib2" CFLAGS="-static" ./configure --enable-static --disable-shared

Common ./configure options for static linking

Dealing with glibc and ldd

The GNU C Library (glibc) is a core component of most Linux systems and is almost always dynamically linked. Static linking glibc is generally discouraged and often leads to issues, as it can break compatibility with other system components and make the resulting binary less portable across different Linux distributions or kernel versions. If your goal is maximum portability, consider using musl-libc instead of glibc for a truly static build, or target a specific older glibc version.

ldd your_executable

Use ldd to check dynamic library dependencies

After running ldd on a supposedly static executable, if you still see not a dynamic executable or no output, it's a good sign. If you see libc.so.6 or other shared libraries, your build is not fully static. For glibc, you will almost always see it listed unless you've specifically built against musl-libc or similar alternatives.

Troubleshooting Common Static Linking Issues

Static linking can be finicky. Here are some common issues and their solutions:

1. Missing Static Libraries

Ensure you have installed the -dev or -static packages for all dependencies. The linker will complain about undefined references if it can't find the static versions.

2. Order of Libraries

The order of libraries passed to the linker (-l flags) matters. Dependencies should generally be listed after the libraries that depend on them. For example, if libfoo depends on libbar, you'd link with -lfoo -lbar.

3. Forcing Static Linkage

Sometimes, even with --enable-static, the build system might still prefer shared libraries. Explicitly setting LDFLAGS="-static" and CFLAGS="-static" during ./configure or make can help force the issue. Be aware that this might cause issues if some libraries must be dynamic.

4. Position-Independent Code (PIC)

Static libraries often need to be compiled with Position-Independent Code (PIC) if they are to be linked into shared libraries (which is not your goal here) or if the main executable is itself PIC. If you're getting errors related to PIC, try adding -fPIC to CFLAGS when compiling the libraries themselves, or ensure your static libraries are built without PIC if they are only for static executables.

5. OmniOS and Solaris-like Systems

On systems like OmniOS (a Solaris derivative), static linking can be even more challenging due to differences in the linker and library conventions. You might need to explicitly specify LIBS and LDFLAGS with the full paths to static libraries, and potentially use gcc -static directly if the build system allows. The ldd command on these systems might also behave differently.