架构特定说明 - 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 问题
不要修补 Makefile
本身,因为它通常由 configure
脚本生成,并且可能差异很大,因此补丁可能会失败。此外,这对上游没有任何帮助。
另一个坏主意是(滥用)来自 flag-o-matic.eclass
的 append-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 链接
当前,我们提供了多个配置文件,每个配置文件都有自己的 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
变量控制。
头文件和多库
大多数 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 字节 |
如果您需要精确的空间量,请不要使用这些类型,而要使用 uXX
和 sXX
类型,它们由 types.h
提供,其中 XX 是您需要的位数。切换到在两种架构上都相同的类型并不建议,因为它不是一个干净的解决方案,并且可能会导致其他架构出现问题。