abhiTronix / raspberry-pi-cross-compilers

Latest GCC Cross Compiler & Native (ARM & ARM64) CI generated precompiled standalone toolchains for all Raspberry Pis. 🍇
https://sourceforge.net/projects/raspberry-pi-cross-compilers
GNU General Public License v3.0
594 stars 104 forks source link

libstdc++ missmatch in cross compiler #66

Closed codewithpassion closed 3 years ago

codewithpassion commented 3 years ago

Hi there,

I ran into an issue when using the GCC 10 cross compiler package for debian stretch.

./test: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.26' not found

It seems like the cross compiler brings a newer libc++ version (3.4.26) as to what is part of stretch (3.4.22).

Acording to https://packages.debian.org/stretch/armhf/libstdc++6/filelist the latest libstdc++6 package is on version .22

Is there a way to address this?

Thanks Dom

abhiTronix commented 3 years ago

@codewithpassion Thank for addressing this issue. Can you paste the exact URL of the toolchain you're using from this repository.

./test: /usr/lib/arm-linux-gnueabihf/libstdc++.so.6: version `GLIBCXX_3.4.26' not found

Also is this error showing up when you running cross-compiled binary on your raspberry pi, Or this just a runtime error when you're cross-compiling?

codewithpassion commented 3 years ago

@abhiTronix This is the toolchain: https://jaist.dl.sourceforge.net/project/raspberry-pi-cross-compilers/Raspberry%20Pi%20GCC%20Cross-Compiler%20Toolchains/Stretch/GCC%209.3.0/Raspberry%20Pi%201%2C%20Zero/cross-gcc-9.3.0-pi_0-1.tar.gz

This happened when the compiled program was run on a Pi with stretch.

I narrowed the problem down to different version of libstdc++.so. When I changed the symlink to libstdc++.so.6 to libstdc++.so.6.22

Then the resulting executable worked.


    cd cross-pi-gcc-*/arm-linux-gnueabihf/lib && \
    rm libstdc++.so libstdc++.so.6 && \
    ln -s libstdc++.so.6.22 libstdc++.so && \
    ln -s libstdc++.so.6.22 libstdc++.so.6
``
abhiTronix commented 3 years ago

This happened when the compiled program was run on a Pi with stretch.

I narrowed the problem down to different version of libstdc++.so. When I changed the symlink to libstdc++.so.6 to libstdc++.so.6.22

Then the resulting executable worked.

@codewithpassion Ok I think you forgot to set LD_LIBRARY_PATH as mentioned in Wiki docs. Can you please confirm if setting it solves the problem for you? (Make sure you do this on unaltered toolchain)

borrrden commented 3 years ago

I'm having this issue as well. I tried setting LD_LIBRARY_PATH but it did not seem to have any effect. Redoing the symlinks as @codewithpassion mentioned appears to have an effect but I haven't been able to test it yet. The effect I observed is that without changing the symlink, I get a bunch of undefined symbols in my final binary that end in @@GBLIBCXX_X.Y.Z including on that ends in GLIBCXX_3.4.26. Those are meant to be resolved later to libstdc++.

If I change the symlink to be as mentioned, those same symbols are compiled into the binary directly, probably because they are not in the shared library and get linked in statically via libstdc++_nonshared.a or something like that.

I don't know why the symlinks in the toolchain should point at anything but the exact same version that is on the actual device. It is in the toolchain, but so is libstdc++.so.6.0.28 (where did this come from?) . The latest, and final, version of stretch has this:

pi@raspberrypi:~ $ ls -l /usr/lib/arm-linux-gnueabihf/libstdc++.so.6*
lrwxrwxrwx 1 root root      19 Mar  1  2018 /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 -> libstdc++.so.6.0.22
-rw-r--r-- 1 root root 1269620 Mar  1  2018 /usr/lib/arm-linux-gnueabihf/libstdc++.so.6.0.22

However, the toolchain instead has the symlink pointing to libstdc++.so.6.0.28.

abhiTronix commented 3 years ago

I don't know why the symlinks in the toolchain should point at anything but the exact same version that is on the actual device. It is in the toolchain, but so is libstdc++.so.6.0.28 (where did this come from?)

@borrrden Nope it can't be exact. It's a short-coming of having the old version Glibc on Raspbian OS(i.e. Glibc-v2.24 on stretch), and thereby you cannot build new GCC with old Glibc or vice-versa. Therefore, If you are trying to build Glibc 2.24 with a more modern GCC, like 8.x/9.x/10.x, you are going to get a lot of build errors due to incompatibility, and my approach to tackle project this problem is to half build base GCC 6.3.0 version with old Glibc and then use it to compile the latest GCC versions. See build script for more information.

Tl'dr: This problem is analogous to fact that you can't run windows 10 on old hardware. Newer GCC requires newer glibc to compile.

If you want exact version, then just use GCC 6.3.0 base version.

borrrden commented 3 years ago

That explanation makes sense, but then how do you deal with the fact that this newer version of libstdc++ is going to have all these symbols inside of it that are not available on the actual hardware? Is the only solution to either statically link libstdc++ or ship the newer libstdc++ in your package? GCC 6.3.0 is not new enough to directly compile a large portion of the C++ we use in the library (minimum required is GCC 7).

abhiTronix commented 3 years ago

but then how do you deal with the fact that this newer version of libstdc++ is going to have all these symbols inside of it that are not available on the actual hardware?

@borrrden correct libstdc++ binary is already located inside our compressed toolchain binary, you just need to point them correctly. LD_LIBRARY_PATH patch is just for projects that doesn't care about symlinks. If you're looking for more advanced approach, see CMAKE GUIDE that take care of paths precisely. If you don't have Pi then see this guide

borrrden commented 3 years ago

Thanks for responding so quickly. I understand that the newer libstdc++ is in the toolchain, but it is not on the Pi unless I put it there. I was under the possibly mistaken understanding that I could run a binary produced by GCC 9.3.0, for example, on a stock install of raspbian 9. I have CMake set up to compile my binary and it compiles nicely, it's just when it runs on the actual device it gives the exact error that was described originally in this ticket. Technically the error comes from a shared library that I also build that the binary links with. It makes sense to me, because that newer libstdc++ is not present on the device and so the symbols that were promised by the toolchain are not there (i.e. anything marked GLIBCXX_3.4.23 or higher, I am guessing).

I've read through the CMake guide quite a few times on my journey to get this far but the part I don't get is where are those symbols supposed to come from on the device if the newer libstdc++ is not there? The toolchain will compile it without issue because it has libstdc++.so.6.0.28. That has driven my conclusion that I either need to put the library on the device and use LD_LIBRARY_PATH there or statically link the C++ std so that I don't need the shared library there at all.

So I guess all of that boils down to the question "Do I need to move that toolchain libstdc++ onto the device first in order for this to work?"

abhiTronix commented 3 years ago

I understand that the newer libstdc++ is in the toolchain, but it is not on the Pi unless I put it there. So I guess all of that boils down to the question "Do I need to move that toolchain libstdc++ onto the device first in order for this to work?"

@borrrden That's why we need sysroot/rootfs as described in CMAKE GUIDE to compile binaries within your raspberry pi os environment, that's how cross compiling works. When we're cross compiling any program with GCC, It automatically copies required target system binaries dependency inside build folder if it requires them at runtime. If something is missing it is because cross compiling toolchain is unable to see it as a target dependency and might wrongly interpreting as host system dependency.