Mastering C++ Dynamic Libraries: RPATH, LD_LIBRARY_PATH, and CMake
This article walks through building and deploying C++ shared libraries, demonstrates common pitfalls with missing dependencies, explains how to embed runtime library paths using RPATH, and shows modern CMake techniques for reliable linking on Linux systems.
When testing and deploying C++ shared libraries, programs often link to system‑installed libraries instead of the intended local ones, causing missing‑dependency errors after make install . A universal solution is to bind the runtime library path using RPATH .
1. Simple dynamic‑library example
Source files:
<code>// foo.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void foo();
#ifdef __cplusplus
}
#endif</code> <code>// foo.cc
#include "foo.h"
#include <stdio.h>
void foo() { printf("foo\n"); }</code>Build the library:
<code>g++ -o libfoo.so -fPIC -shared foo.cc</code>Consumer program:
<code>// main.cc
#include "foo.h"
int main(int argc, char* argv[]) {
foo();
return 0;
}</code>Compile linking to the current directory:
<code>gcc main.cc -L . -lfoo
./a.out # prints "foo"
ldd a.out | grep libfoo # shows libfoo.so loaded from ./</code>2. Library that depends on another library
Assume libbar.so depends on libfoo.so . Directory layout:
<code>.
├── include
│ └── bar.h
├── src
│ └── bar.cc
└── thirdparty
├── include
│ └── foo.h
└── lib
└── libfoo.so</code>Build libbar.so :
<code>g++ -o libbar.so -fPIC -shared src/bar.cc \
-I include/ -I thirdparty/include/ \
-L thirdparty/lib/ -lfoo</code>Running ldd libbar.so reveals that the dependency resolves to the system’s libfoo.so (e.g., /usr/lib64/libfoo.so ) instead of the intended local version, which can cause ABI mismatches.
Temporarily fixing the path with LD_LIBRARY_PATH works but is inconvenient for end users.
3. Using RPATH
Embedding the library location at link time solves the problem:
<code>g++ -o libbar.so -fPIC -shared src/bar.cc \
-I include/ -I thirdparty/include/ \
-L thirdparty/lib/ -lfoo -Wl,-rpath=thirdparty/lib/</code>Now ldd libbar.so shows the dependency resolved to thirdparty/lib/libfoo.so . The -Wl,-rpath flag sets the runtime search path, which differs from -L (compile‑time search path).
4. Modern CMake integration
A minimal CMakeLists.txt that sets RPATH:
<code>cmake_minimum_required(VERSION 2.8.12)
project(Bar CXX)
set(CMAKE_PREFIX_PATH "${PROJECT_SOURCE_DIR}/thirdparty")
find_path(FOO_INCLUDE_DIR NAMES foo.h)
find_library(FOO_LIB NAMES libfoo.so)
add_library(bar SHARED src/bar.cc)
include_directories(./include ${FOO_INCLUDE_DIR})
target_link_libraries(bar ${FOO_LIB})
# Set absolute RPATH
set(CMAKE_INSTALL_RPATH "${PROJECT_SOURCE_DIR}/thirdparty/lib")
install(TARGETS bar LIBRARY DESTINATION lib)
</code>Build steps:
<code>mkdir _builds && cd _builds
cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/..
make
make install</code>The installed libbar.so contains an RPATH pointing to the bundled libfoo.so , avoiding conflicts with system libraries.
5. Linux dynamic‑library search order
The linker searches for shared objects in the following order:
Directories specified by the binary’s RPATH.
Directories in LD_LIBRARY_PATH .
Directories in the binary’s RUNPATH.
Cache file /etc/ld.so.cache (derived from /etc/ld.so.conf and /etc/ld.so.conf.d ).
Standard system directories such as /lib and /usr/lib .
Using -z nodefaultlib disables steps 4 and 5. The difference between RPATH and RUNPATH is that RPATH is searched before LD_LIBRARY_PATH , while RUNPATH is searched after it.
6. Summary
By understanding how the Linux loader resolves shared‑library dependencies and by embedding appropriate RPATH entries (or using CMake’s CMAKE_INSTALL_RPATH ), developers can reliably ship C++ components without forcing end users to manipulate LD_LIBRARY_PATH or replace system libraries.
360 Zhihui Cloud Developer
360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.