架构特定说明 - AMD64/EM64T

位置无关代码问题

Gentoo 策略要求所有共享对象在 CFLAGS 中使用 -fPIC 进行编译。由于这只是一个规则,您可以在某些架构上打破它。您可能永远不会注意到它。在 AMD64 上,这是必需的,如果共享对象不是使用对位置无关代码的支持构建的,构建过程将以错误消息退出,例如

foo.o: relocation R_X86_64_32 can not be used when making a shared
object; recompile with -fPIC

如何修复 -fPIC 问题

有几种方法可以强制在共享对象上使用 -fPIC,每种方法都有其优缺点。

sed Makefile

有时,简单的 sed 命令就足以解决问题,但是,这些语句通常可读性不强,并且当上游更改文件时可能会失败。请验证您是否只更改了共享对象的 CFLAGS,而不是整个软件包。

修补 Makefile.in/configure

这更易读,并且更容易发送到上游。

如何修复 -fPIC 问题

不要修补 Makefile 本身,因为它通常由 configure 脚本生成,并且可能差异很大,因此补丁可能会失败。此外,这对上游没有任何帮助。

另一个坏主意是(滥用)来自 flag-o-matic.eclassappend-flags 函数。不应对所有对象应用 -fPIC。它应该只应用于共享对象。

AMD64 上的多库

当前的 AMD64 处理器能够在 64 位内核上原生运行 32 位代码。因此,您可以在 amd64 环境中运行为 x86 编译的程序。但是,32 位应用程序需要与 32 位库链接。混合它们将不起作用。为此,库进行了排序,32 位库通常放在 /lib32/usr/lib32 中,而 64 位库通常放在 /lib64/usr/lib64 中。在理想情况下,您无需继续阅读。不幸的是,情况并非如此,因此它有点复杂。

多库工具链

GCC

要生成 32 位代码,我们需要一个支持多库的 GCC。在其他架构上,此功能使用 USE 标志 multilib 启用。对于使用之前2005.0 配置文件的 amd64 也是如此。从 2005.0 开始,您必须通过选择配置文件来选择是否要支持多库。如果您不想要它,请选择 2005.0/no-multilib,所有其他配置文件都屏蔽了 multilib USE 标志,您被迫使用它。使用这些配置文件,GCC 将在您向其命令行添加 -m32 时生成 x86 代码。添加 -m64 或省略任何位宽选项将默认生成 64 位代码。

glibc

如果您选择了多库配置文件,glibc 将构建两次,一次是 64 位,一次是 32 位。这是因为几乎每个应用程序都与 glibc 链接。要了解如何在 ebuild 中执行此操作,请阅读ABI 变量

32 位兼容性

正如您在上面所读到的,32 位应用程序必须与 32 位库链接。为此,我们已将最常见的库作为多库(通过 ABI 变量和 multilib.eclass)。

当前,我们提供了多个配置文件,每个配置文件都有自己的 libdir 配置组合。表项 x86、amd64 等表示该目录包含此 ABI 的对象;带有箭头符号的条目表示指向相应目录的符号链接。

配置文件 lib lib32 lib64 libx32
17.0 -> lib64 x86 amd64 不存在
17.0/no-multilib -> lib64 不存在 amd64 不存在
17.0/x32 -> libx32 x86 amd64 x32
17.1 x86 不存在 amd64 不存在
17.1/no-multilib n/a 不存在 amd64 不存在

要始终获得正确的路径,您应该使用 $(get_libdir),它自 EAPI 6 以来一直可用作为包管理器函数。它将始终返回正确的目录,在所有架构上。当然,它还处理 ABI 变量。

multilib-strict 特性

许多 Makefile 假设它们的库应该放在 /usr/lib$(prefix)/lib 中。如果 /usr/lib 不是指向 /usr/lib64 的符号链接,此假设会导致严重混乱。为了找到错误的软件包,我们有一个名为multilib-strict 的 Portage 特性。它将阻止 emerge 将 64 位库放入除 (/usr)/lib64 之外的任何地方。

multilib-strict 当前不检查 perl5、gcc、gcc-lib 和 eclipse-3,此行为由 make.profile 中的 MULTILIB_STRICT_EXEMPT 变量控制。

如何正确修复 ebuild

在大多数情况下,默认的 econf 行为就足够了,因为它会将正确的 --libdir 选项传递给 configure

一些软件包提供了非常糟糕的 Makefile,这些 Makefile 硬编码了 /usr/lib。这些应该使用 sed 进行编辑或修补。不要忘记让上游知道您的修改!

头文件和多库

大多数 C/C++ 程序需要标准头文件,例如 types.h。其中一些依赖于架构特定的因素,例如 types.h 中的机器字长度。为了确保我们能够编译 32 位和 64 位应用程序和库,我们对 /usr/include/asm 进行了一些特殊处理。

这是 AMD64 机器上的 /usr/include/asm/types.h 的外观

/* Common header file autogenerated by create_ml_includes in multilib.eclass */
#ifdef __i386__
#include <asm-i386/types.h>
#endif /* __i386__ */

#ifdef __x86_64__
#include <asm-x86_64/types.h>
#endif /* __x86_64__ */

如您所见,这只是一个包装器,它根据传递给 gcc 的参数 -D 来决定您需要哪个文件。如果您尝试手动编译某些内容并忘记将 -D__x86_64__ 附加到您的 CFLAGS,您可能会遇到一些麻烦。当然,在使用 Portage 时不需要这样做。有关说明,请参阅ABI 变量 部分。

ABI 变量

无论何时 Portage 在 amd64 上构建某些内容,它都必须决定它应该是 32 位还是 64 位。如头文件和多库 中所述,__i386____x86_64__ 需要分别放在 CDEFINE 中。此外,gcc 必须知道它应该生成什么代码,因此 -m32-m64 必须附加到 CFLAGS。这是通过 profile.bashrc 完成的。如果您想构建一个 32 位软件包,您只需要设置 ABI=x86

详细信息显示在 make.defaults

MULTILIB_ABIS="x86 amd64"
DEFAULT_ABI="amd64"

CFLAGS_amd64="-m64"
LDFLAGS_amd64="-m elf_x86_64"
CHOST_amd64="x86_64-pc-linux-gnu"
CDEFINE_amd64="__x86_64__"
LIBDIR_amd64="lib64"

CFLAGS_x86="-m32 -L/emul/linux/x86/lib -L/emul/linux/x86/usr/lib"
LDFLAGS_x86="-m elf_i386 -L/emul/linux/x86/lib -L/emul/linux/x86/usr/lib"
CHOST_x86="i686-pc-linux-gnu"
CDEFINE_x86="__i386__"
LIBDIR_x86="lib32"

移植说明

机器字大小

在 AMD64 上,某些类型的大小与 x86 不同

类型 x86 (ILP32) amd64 (LP64)
char 1 字节 1 字节
short 2 字节 2 字节
int 4 字节 4 字节
long 4 字节 8 字节
长整型 8 字节 8 字节
指针 4 字节 8 字节
单精度浮点数 4 字节 4 字节
双精度浮点数 8 字节 8 字节
长双精度浮点数 16 字节 16 字节

如果您需要精确的空间量,请不要使用这些类型,而要使用 uXXsXX 类型,它们由 types.h 提供,其中 XX 是您需要的位数。切换到在两种架构上都相同的类型并不建议,因为它不是一个干净的解决方案,并且可能会导致其他架构出现问题。

强制转换

许多上游开发人员假设指针的长度为 4 字节,这会导致程序从 void *int 的强制转换出现问题,反之亦然。使用 GCC 3.4 时,这会导致警告,编译不会中止。如果您幸运,您的软件包可以正常工作,但您很可能会遇到段错误或奇怪的行为。GCC 4.0 拒绝编译此类代码。