请相信我,我已经花了很多时间在谷歌上搜索,但没有得到太多结果。
我正在编写一个非常基本的操作系统作为一个有趣的项目。出于明显的原因,它需要编译成独立的形式(在我的例子中是 i686-elf)。然而,我认为纯 C 对我来说还不够,我更愿意使用 C++。所以我写了一些代码,它似乎可以工作,所以我继续,尽管代码没有明显问题,但突然间我不断收到同样的错误。
./sh/../obj/class_string.o:(.eh_frame+0x4f): 未定义对 __gxx_personality_v0 的引用
./sh/../obj/kernel.o:(.eh_frame+0x13): 未定义对 __gxx_personality_v0 的引用
/home/natiiix/crosscompiler/out/path/bin/../lib/gcc/i686-elf/6.1.0/libgcc.a(unwind-dw2.o): 在函数 read_encoded_value_with_base':
/home/natiiix/crosscompiler/out/src/build-gcc/i686-elf/libgcc/../../../gcc-6.1.0/libgcc/unwind-pe.h:257: 未定义的中止引用'
经过一些谷歌搜索后,我发现问题一定是我的 g++ 交叉编译器缺少 c++ 库,事实证明这是真的。它确实只包含 libgcc 和 libgcov。所以我想我会以某种方式得到它们,但事实证明这是一项非常困难的任务。几乎不可能找到已编译的 libstdc++.a。所以我不得不自己编译它,因为我对 makefile 不是特别熟悉,所以肯定不容易弄清楚。
最后我找到了一个 bash 脚本,它在某种程度上允许我做我需要的事情。它下载 gcc 6.1.0、binutils、配置两者并运行 make、make install。如果它真的有效,那就太好了。至少据我所知,编译器本身就像一个魅力,但无论我做什么,库都不会工作,至少我怀疑,出于某种原因,它是为不同的目标平台构建的。看来 libstdc++ 根本无法为 i686-elf 或类似的东西构建。
gccbuild.sh:
#!/bin/bash
set -e
if [ "$#" -ne 1 ]; then
echo "Supply one parameter: the target to use!!"
exit 1
fi
sudo apt install libgmp3-dev libmpfr-dev libisl-dev libcloog-isl-dev libmpc-dev texinfo -y
cd "$(dirname "$0")"
rm -rfv out/
mkdir out/
cd out/
rm -rfv path/
mkdir path/
rm -rfv src/
mkdir src/
cd src/
wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.26.tar.gz
wget ftp://ftp.gnu.org/gnu/gcc/gcc-6.1.0/gcc-6.1.0.tar.gz
tar -xvzf binutils-2.26.tar.gz
tar -xvzf gcc-6.1.0.tar.gz
export PREFIX="$(pwd)/../path/"
export TARGET=$1
export PATH="$PREFIX/bin:$PATH"
rm -rfv build-binutils/
mkdir build-binutils/
cd build-binutils/
../binutils-2.26/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-werror
make
make install
cd ..
rm -rfv build-gcc/
mkdir build-gcc/
cd build-gcc/
../gcc-6.1.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
../gcc-6.1.0/libstdc++-v3/configure --host=$TARGET --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --disable-libstdcxx-threads
make
make install
我的编译/链接脚本(以便您可以看到 g++ 参数):
${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -c ${BASH_SOURCE%/*}/../src/*.cpp --std=c++11 -ffreestanding -O2 -Wall -Wextra
echo moving object files from active directory to obj/
mv *.o ${BASH_SOURCE%/*}/../obj/
${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -T ${BASH_SOURCE%/*}/../src/linker.ld -o ${BASH_SOURCE%/*}/../bin/kokos.bin -ffreestanding -O2 -nostdlib ${BASH_SOURCE%/*}/../obj/*.o -lgcc -lstdc++ -lsupc++
当我尝试链接这些库(libstdc++ 和 libsupc++ 的版本似乎是 elf32-i386,它们与 i686-elf 一样接近)时,我不再得到 对 __gxx_personality_v0 的 undefined reference
,但我仍然得到一些 undefined reference ,这些引用似乎是 C 函数。 (中止、strlen、malloc、释放)
整个问题可以通过不使用模板、类析构函数和一些更特定于 c++ 的东西来避免(具有讽刺意味的是,类本身在大多数情况下似乎工作得很好),但对我来说这似乎不是一个很好的解决方案.我宁愿接触到这些东西。
有人可以向我解释我做错了什么吗?
最佳答案
从您的帖子中不清楚您想要获得的确切结果。以下是一些可以帮助您找出真正问题所在的观察结果。
- 首先,如果您需要在您的(我猜)64 位 Ubuntu 主机上编译 32 位代码,您不需要交叉工具链,只需使用
-m32
编译即可。 - 如果您希望您的代码针对特定 CPU 变体进行优化,只需使用适当的
-march=
、-mcpu=
和-mtune=
选项。 - 如果您需要将您的 32 位程序与 C++ 库静态链接,那么在 Ubuntu 上您只需安装一个软件包 libstdc++-6-dev:i386。运行
sudo apt-get install libstdc++-6-dev:i386
,它还会安装所有必要的依赖项。然后用gcc -m32 -static
编译你的程序。 - 如果您需要为特定 CPU 使用优化标准库,而不是为通用 i386 使用标准库,那么您需要手动构建它们。这不仅适用于 libstdc++,也适用于 libc(IIRC,Ubuntu 16.04 仍然使用通用的
-march=i386
选项来构建 libc,Ubuntu 16.10 使用-march=i686
). - 您从链接输出中获得了 undefined reference ,因为您使用的是
-nostdlib
和-lstdc++
而不是-lc
。libstdc++
使用了标准 C 库中的函数,所以你需要它。 - 当您开发操作系统内核并需要独立环境时,我想您确实不需要标准库。在这种情况下,请参阅 C++ 标准第 17.6.1.3 条,以查找您可以在应用程序中使用的标准头文件。您必须在编译器命令行上使用
-lsupc++ -lgcc
,如果您使用异常处理(和libgcc_eh.a
,则还需要-lgcc_eh
是__gxx_personality_v0
的来源)。不要在独立环境中使用-lstdc++
!
希望这对您有所帮助,祝您好运!
关于c++ - 为 i686-elf 交叉编译和链接 libstdc++(在 Ubuntu 16.04 上使用 g++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42822885/