【问题标题】:Cross-compile and link libstdc++ for i686-elf (using g++ on Ubuntu 16.04)为 i686-elf 交叉编译和链接 libstdc++(在 Ubuntu 16.04 上使用 g++)
【发布时间】:2017-03-15 23:52:01
【问题描述】:

相信我,我已经花了很长时间在谷歌上搜索,但没有什么结果。

我正在编写一个非常基本的操作系统作为一个有趣的项目。由于显而易见的原因,它需要编译成一个独立的形式(在我的例子中是 i686-elf)。但是我已经决定纯 C 对我来说是不够的,我很想使用 C++。所以我写了一些代码,它似乎工作了,所以我继续,尽管代码没有明显的问题,但突然间我一直收到同样的错误。

./sh/../obj/class_string.o:(.eh_frame+0x4f): undefined reference to __gxx_personality_v0' ./sh/../obj/kernel.o:(.eh_frame+0x13): undefined reference to __gxx_personality_v0' /home/natiiix/crosscompiler/out/path/bin/../lib/gcc/i686-elf/6.1.0/libgcc.a(unwind-dw2.o): In function read_encoded_value_with_base': /home/natiiix/crosscompiler/out/src/build-gcc/i686-elf/libgcc/../../../gcc-6.1.0/libgcc/unwind-pe.h:257: undefined reference to abort'

经过一番谷歌搜索后,我发现问题一定是我的 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 最接近)时,我停止收到 undefined reference to __gxx_personality_v0,但我仍然收到少数似乎是 C 函数的未定义引用。 (abort, strlen, malloc, free)

不使用模板、类析构函数和更多特定于 c++ 的东西可以避免整个问题(具有讽刺意味的是,单独的类似乎在大多数情况下都可以正常工作),但对我来说这似乎不是一个很好的解决方案.我宁愿接触这些东西。

有人可以向我解释我做错了什么吗?

【问题讨论】:

  • " 几乎不可能找到已经编译好的 libstdc++.a" 嗯,不。这很容易(对于任何给定的发行版)。但是该死的,你似乎在跳过箍来解决你不应该遇到的问题。事情通常没有那么难(除非 ylu 只是“做错了”)。
  • 错误信息显示了答案。 stackoverflow.com/questions/6045809/…
  • @jesper 怎么这么容易?如果你能找到它,请给我链接 i686-elf 的库。至少一个小时我根本找不到任何东西。
  • @sailfish009 不,它没有,它实际上什么也没说。我无法让 libstdc++ 工作,因此我无法链接它。

标签: c++ linux linker g++ libstdc++


【解决方案1】:

从您的帖子中不清楚您想要获得什么确切结果。下面有一些观察可以帮助您弄清楚您的真正问题是什么。

  1. 首先,如果您需要在(我猜的)64 位 Ubuntu 主机上编译 32 位代码,则不需要交叉工具链,只需使用 -m32 编译即可。
  2. 如果您希望代码针对特定 CPU 变体优化,只需使用适当的 -march=-mcpu=-mtune= 选项即可。
  3. 如果您需要将您的 32 位程序与 C++ 库静态链接,那么在 Ubuntu 上您只需要安装软件包 libstdc++-6-dev:i386。运行sudo apt-get install libstdc++-6-dev:i386,它还将安装所有必要的依赖项。然后用gcc -m32 -static编译你的程序。
  4. 如果您需要为特定 CPU 使用标准库优化,而不是通用 i386,那么您需要手动构建它们。这不仅适用于 libstdc++,也适用于 libc(IIRC,Ubuntu 16.04 仍然使用通用 -march=i386 选项来构建 libc,Ubuntu 16.10 使用 -march=i686)。
  5. 您从链接输出中获得了未定义的引用,因为您使用的是-nostdlib-lstdc++,而不是-lclibstdc++ 使用标准 C 库中的函数,所以你需要它。
  6. 当您开发操作系统内核并需要独立环境时,我想您确实不需要标准库。在这种情况下,请参阅 C++ 标准第 17.6.1.3 节,以查找可以在应用程序中使用的标准头文件。你必须在你的编译器命令行上使用-lsupc++ -lgcc,如果你使用异常处理,你还需要-lgcc_ehlibgcc_eh.a__gxx_personality_v0的来源)。请勿在独立环境中使用 -lstdc++

希望这能有所帮助,祝你好运!

【讨论】:

  • 我不仅不需要这些库,我什至不想要它们中的任何一个。我只想支持 c++ 功能,例如关键字 new / delete、对象析构函数 ~class() 等。无论如何,我不知道如何使用标准 g++ 使其工作。它总是链接到他们的 x86_64-linux 版本。 g++ -m32 -static -march=i386 -T ${BASH_SOURCE%/*}/../src/linker.ld -o ${BASH_SOURCE%/*}/../bin/kokos.bin -nostdlib -ffreestanding -O2 ${BASH_SOURCE%/*}/../obj/*.o -lgcc -lc -lgcc_eh 仍然会产生由缺少 C 库引起的错误。我不能自己实现这些功能并使用它们吗?
猜你喜欢
  • 2019-07-18
  • 2014-07-20
  • 2011-06-08
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多