We run into the dreaded
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.18' not found
error messages a lot around here. This article is an attempt to explain what's going on with that.
The GNU C library (libc.so
) and standard C++ library (libstdc++.so
)
are dynamically loaded by most of the programs on a Unix system at
runtime.
When you're talking about binaries that have their library dependencies
"baked in," it's the job of the regular old
linker
(ld
) to resolve a program's library dependencies at compile time
(e.g., "static" dependencies). If a binary has been compiled to use
"shared objects" (external dependencies that are not baked into the
binary, but rather loaded upon execution), it's the job of the dynamic
linker
(ld.so
) to resolve those dependencies at runtime. A "shared
object" on Unix is like a
DLL
on Windows.
For example, for a binary that was compiled against a fictional shared
object /path/to/some/lib.so
, the dynamic linker will yield error
messages like
unable to load shared object /path/to/some/lib.so
when that required shared object (at the required ABI version) cannot be located in any of the following
- the system-wide linker search path, defined in
/etc/ld.so.conf
(you must be root to modify this), or - the linker runtime search path specified in
LD_LIBRARY_PATH
Mucking around with LD_LIBRARY_PATH
is frowned upon for a
variety
of
reasons, but we
still do it sometimes because it seems easier than the much preferred
alternative (appending to the binary's run-time linker path with a
compiler flag, as in:
LDFLAGS='-L/my/strange/path/lib -Wl,-rpath /my/strange/path/lib'
).[1]
It's also objectively easier to specify a "priority" for
various runtime library paths in this way. For example, many
modulefiles provided in an HPC cluster
environment will manipulate the LD_LIBRARY_PATH
in order to make the
libstdc++.so
(and other libraries) specific to one version of GCC available
with priority over other system-default libraries.
Here's a real-world example of a linker error, which you would get in
the R shell when correct libstdc++
isn't available
library(DESeq2)
The resulting error message is this:
Error in dyn.load(file, DLLpath = DLLpath, ...) :
unable to load shared object '/usr/local/R/3.2.0/lib64/R/library/Rcpp/libs/Rcpp.so':
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /usr/local/R/3.2.0/lib64/R/library/Rcpp/libs/Rcpp.so)
Error: package ‘Rcpp’ could not be loaded
The solution to this particular linker error is to module load gcc/4.8.0
(or higher) either before or after module load R
, then trying again.
The libcversions.sh
included as a part of
this gist
reports which libc
and libstdc++
ABI versions are available to running
programs. It does this by inspecting the output of ldconfig
as well as the
value of LD_LIBRARY_PATH
, which is usually modified by modulefiles (e.g.,
when you module load gcc/4.8.5
).
The authoritative reference for which GCC version goes with which ABI
(Application Binary Interface) version is the "ABI Policy and Guidelines"
section of the
official documentation
for the GNU C++ Library.[2] You
can get a rough idea which version of GCC you'll need to module load
by looking at that page and matching up the GLIBCXX
version from the
linker error you got with the GCC version that provides it.
If you have any doubts, load a GCC module that seems to be in the
neighborhood, then grep
the output of the libcversions.sh
script, above,
for the exact GLIBCXX_X.Y.Z
version number you need.
- Should I set LD_LIBRARY_PATH? (the short answer is "never")
- ABI Policy and Guidelines - GNU C++ Library documentation, gcc.gnu.org
Kevin Ernst (ernstki -at- mail.uc.edu)
This work is licensed under a Creative Commons Attribution 4.0 International License.
The associated libcversions.sh
script is provided under the MIT license.