Solved gcc11 GLIBCXX error

jbo@

Developer
On my FreeBSD 13.0-RELEASE-p5 machine I have installed both lang/gcc10 and lang/gcc11.
I am able to successfully compile using either gcc10 or gcc11.

However, upon launching an executable built with gcc11 I am presented with this error message:
Code:
ld-elf.so.1: /usr/local/lib/gcc10/libstdc++.so.6: version GLIBCXX_3.4.29 required by /home/jbo/projects/gpds/cmake-build-debug/test/gpds-tests not found
Launching the same program/binary/executable built with gcc10 works fine.

What's the problem here? How would one fix that?
 
What's the problem here?
Look closely at the error, it seems to be depending on GCC10 libraries, instead of GCC11. I suspect something went wrong with linking and you linked to 10 libraries.
Code:
ld-elf.so.1: /usr/local/lib/gcc10/libstdc++.so.6
 
Well yeah - I should have asked more precisely: Why is the executable depending on gcc10?

This is a cmake based project. I simply set CMAKE_CXX_COMPILER to g++11 (and CMAKE_C_COMPILER to gcc11.
This works well on other platforms such as Windows, Linux & MacOS.
 
I have
pkg which pkg which /usr/local/lib/gcc10/libstdc++.so.6 0
/usr/local/lib/gcc10/libstdc++.so.6 was installed by package gcc10-10.3.0

As environment,
export CPATH=/usr/local/include
export LIBRARY_PATH=/usr/local/lib

You could try:
export CMAKE_LIBRARY_PATH=/usr/local/lib
Or
something like "LDFLAGS+= -L${XXX}/lib" ?
 
Is there a particular reason you use GCC for compiling? If not, just omit the CMAKE_C_COMPILER and CMAKE_CXX_COMPILER flags and let CMake select it automatically.
 
Is there a particular reason you use GCC for compiling? If not, just omit the CMAKE_C_COMPILER and CMAKE_CXX_COMPILER flags and let CMake select it automatically.
In this case because it's an "educational" project to explore the fancyness of C++20. Compared to gcc, clang is lacking behind so I have to stick with gcc for this one.

While I understand why this question would come up (eg. to prevent an XY problem) I'd argue that there is "something wrong" which would "require fixing" in any case. even if I can get along with just using clang or gcc10 on my system.
 
Well, what does `ldd your_application` say?

Are you setting LD_LIBRARY_PATH?

As already mentioned, does your build use the (wrong) rpath?

Check that with `objdump -x your_application | grep RUNPATH`
 
On my FreeBSD 13.0-RELEASE-p5 machine I have installed both lang/gcc10 and lang/gcc11.
I am able to successfully compile using either gcc10 or gcc11.

However, upon launching an executable built with gcc11 I am presented with this error message:
Code:
ld-elf.so.1: /usr/local/lib/gcc10/libstdc++.so.6: version GLIBCXX_3.4.29 required by /home/jbo/projects/gpds/cmake-build-debug/test/gpds-tests not found
Launching the same program/binary/executable built with gcc10 works fine.

What's the problem here? How would one fix that?
I would destroy your build directory then run your cmake again, just in case.
 
Sorry for the long silence.

I would destroy your build directory then run your cmake again, just in case.
Done this several times over. Even tried different FreeBSD 13 machines.

Check that with `objdump -x your_application | grep RUNPATH`
Doesn't output anything (also not when grepping for RPATH instead).

I can reproduce this successfully: Install lang/gcc10, lang/gcc11 and devel/cmake. Then create a directory and change into it.

Create main.cpp:
Code:
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

Create CMakeLists.txt:
Code:
cmake_minimum_required(VERSION 3.19)
project(gcc_test)

add_executable(gcc_test main.cpp)

Build:
Code:
cmake --build build

Inspect linked libstdc++:
Code:
ldd build/gcc_test
build/gcc_test:
    libstdc++.so.6 => /usr/local/lib/gcc10/libstdc++.so.6 (0x800643000)
    libm.so.5 => /lib/libm.so.5 (0x800a2a000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x800a65000)
    libc.so.7 => /lib/libc.so.7 (0x800a7f000)

So this is linking against libstdc++ of gcc10.
 
It's because rpath is not set for the linker.
You need to set(CMAKE_INSTALL_RPATH "/path/to/library/") or you could just set -Wl,-rpath=/path/to/library using:

SET(CMAKE_CXX_FLAGS "flags")
or
SET(CMAKE_EXE_LINKER_FLAGS "flags")
(I forget which one, but possibly the former always)

Or you could remove gcc11 and have no problems :)
 
jbodenmann rpath is the key here, as mentioned a few times. Binaries compiled with GCC need some runtime libs bundled with GCC (for example libstdc++.so is a part of GCC's runtime, and on a system where GCC is the system's compiler, these libs are installed in default locations and there's only one version of them).

You have to understand the main reason for existence of these GCC ports is to compile other ports that depend on GCC (running e.g. gcc11 -dumpmachine gives a hint about that ;)). The ports framework already does the necessary rpath "magic" here for any port with USE_GCC: https://cgit.freebsd.org/ports/tree/Mk/bsd.gcc.mk#n121

In a nutshell, just add -Wl,-rpath=/usr/local/lib/gcc11 to your linker invocation when compiling with gcc11.

edit: You could also go the "hacky" way and fix your binary afterwards with sysutils/patchelf:
patchelf --set-rpath /usr/local/lib/gcc11 build/gcc_test
 
In this case because it's an "educational" project to explore the fancyness of C++20. Compared to gcc, clang is lacking behind so I have to stick with gcc for this one.
As this is an "educational" project, I presume this has limited scope. That supposes that your first priority is to get both gcc10 & gcc11 examples compiled, linked & run, why not first create a separate jail for a gcc10 and gcc11 environment?
 
why not first create a separate jail for a gcc10 and gcc11 environment?
That would be a possible way. IMHO, just setting rpath correctly on your binary is the easier way, but YMMV ;)

Maybe for some more explanation: All GCC packages install GCC runtime libs below a standard path (/usr/local/lib) which is scanned by ldconfig(8), so they will be found. The problem arises when multiple versions of GCC are installed in parallel. A shared library is found by its SONAME property (use readelf -d to display it), and e.g. for GCC's C++ standard lib, this property is libstdc++.so.6 in both versions, still the version coming with gcc10 is missing some symbol versions present in the gcc11 one.

Without an explicit rpath in the binary, the dynamic linker will link the first library it can find in the standard search path with a matching SONAME, and that would be the one installed by gcc10 here. With an rpath, the dynamic linker will search it first before looking at standard paths.
 
[FONT=monospace]jbodenmann[/FONT] rpath is the key here, as mentioned a few times.
I know & I agree. I didn't mean to ignore previous posts. I'm currently just very limited on time and wanted to keep you guys posted.


Or you could remove gcc11 and have no problems
Not an option in my case :p

As expected forcing the RPATH using set(CMAKE_BUILD_RPATH /usr/local/lib/gcc11) resulted in the binary correctly linking to the gcc11 C++ runtime.
For people driving by here in the future: Don't forget to also investigate setting CMAKE_INSTALL_RPATH.
 
BTW, that's one of the problems that could be solved by buiding multiple binary packages from the same source/port (and IIRC that's not a new idea, maybe ports will get that feature some day).

If you would just put all of GCCs runtime libs in a separate package (like, e.g. gcc-runtime?) and have the GCC packages depend on it with a minimum version required, all would be fine.

The reason is: A library must change its SONAME if breaking changes are introduced. So, assuming GCC does it correctly, the libs from gcc11 would still work just fine for binaries compiled with gcc10.

This would also solve the issue of needing to have a full GCC installed in order to use any software compiled with GCC. The package with the runtime libs would be enough for that.
 
Back
Top