特定架构说明 —— 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,每种方法各有利弊。

seding Makefile 文件

有时候,一个简单的sed命令就可以修复它,但是,这些语句通常不易读,并且在上游更改文件时可能会失败。请确认你仅更改共享对象CFLAGS,而不更改整个包。

修补Makefile.in/configure

这更具可读性,并且更易于向上游发送。

如何解决-fPIC 问题

不要修补Makefile本身,因为它通常是由configure脚本生成的,并且可能相差很大,因此修补可能会失败。而且,这根本对上游没有帮助。

另一个不好的主意是(ab)使用 flag-o-matic.eclass 中的append-flags函数。不应将-fPIC应用于所有对象。它仅应应用于共享对象。

AMD64 上的 Multilib

当前的 AMD64 处理器能够在 64 位内核上本地运行 32 位代码。因此,你可以在 amd64 环境中运行为 x86 编译的程序。但是,需要将 32 位应用程序链接到 32 位库。混合它们将不起作用。因此,对库进行排序,通常将 32 位库分别转到/lib32/usr/lib32,将 64 位库通常转到/lib64/usr/lib64。在理想的世界中,你无需继续阅读。不幸的是,事实并非如此,因此要复杂一些。

Multilib 工具链

GCC

要生成 32 位代码,我们需要具有 multilib 功能的 GCC。在其他体系结构上,此功能通过 USE 标志multilib启用。具有 2005.0 之前版本的配置文件的 amd64 也是如此。从 2005.0 开始,你必须通过选择配置文件来选择是否需要多库支持。如果不想,请选择2005.0/no-multilib,其他所有配置文件都将multilib USE 标志屏蔽掉,你将被迫使用。使用这些配置文件,每当你在命令行中添加-m32时,GCC 都会生成 x86 代码。添加-m64或忽略任何位宽选项将默认生成 64 位代码。

glibc

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

emul-linux-x86-*软件包

如上所述,必须将 32 位应用程序链接到 32 位库。为此,我们将最常用的库组合在一起,并将其粘贴到所谓的emul-linux-x86软件包中,这些软件包位于app-emulation类中。在此处可以找到所有emul-linux-x86软件包的当前列表

这些软件包仅提供预编译的库。当前,归档文件是手动组装的,这是保持软件包尽可能整洁的主要原因。不要包括不常用的库。

注意:emul-package可能与它们的本机映像冲突,但只能在非关键位置(例如/usr/share,无论如何都与架构无关)中发生冲突。

Libdir 链接

当前,我们提供了多个配置文件,每个配置文件都有自己的 libdir 配置组合。

Profile lib32 lib lib64
2004.3 *l->emul* d64 *l->lib*
2004.3/lib64 *l->emul* *l->64* d64
>=2005.0 d32 *l->64* d64
>=2005.0/no-multilib d32 *l->64* d64
>=2005.0/no-symlink d32 d d64
>=2005.0/no-symlink/no-lib32 inexistant d32 d64

d

包含混合位对象的目录

dXX

包含 XXbit 对象的目录

l->foo

链接至 foo

为了始终获得正确的路径,应该使用multilib.eclass中的$(get_libdir)函数。在所有架构上,它将始终返回正确的目录。当然,它也处理ABI变量。

multilib-strict 函数

许多 Makefile 假定它们的库应转到/usr/lib$(prefix)/lib。如果/usr/lib不是/usr/lib64的符号链接,则此假设可能会导致严重混乱。要查找错误的软件包,我们有一个名为multilib-strict的移植功能。这将防止 emerge 将 64 位库放入除(/usr)/lib64之外的任何其他库中。

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

如何正确修复 ebuild

在大多数情况下,使用multilib.eclass中的$(get_libdir)函数即可 :

inherit multilib

src_compile() {
    econf \
        --libdir=/usr/$(get_libdir)

    emake || die
}

src_install() {
    emake DESTDIR="${D}" install || die
}

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

头文件和 Multilib

大多数 C/C++程序都需要标准的头文件,如types.h。其中一些取决于特定于架构的事实,例如types.h关于机器字的长度。为了确保我们可以同时编译 32 位和 64 位应用程序和库,我们对/usr/include/asm进行了一些特殊处理。

这是/usr/include/asm/types.h 在 AMD64 框架上的样子:

/* 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上,则可能会遇到麻烦。当然,使用搬运工具时这不是必需的。有关说明,请参见ABI 变量部分。

ABI 变量

每当 portage 在 amd64 上构建某些东西时,它都必须决定它应该是 32 位还是 64 位。如头文件和 Multilib中所述,CDEFINE中分别需要__i386____x86_64__。另外,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 不同:

Type x86 (ILP32) amd64 (LP64)
char 1 byte 1 byte
short 2 bytes 2 bytes
int 4 bytes 4 bytes
long 4 bytes 8 bytes
long long 8 bytes 8 bytes
pointer 4 bytes 8 bytes
float 4 bytes 4 bytes
double 8 bytes 8 bytes
long double 16 bytes 16 bytes

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

其它

许多上游开发人员都假定指针的长度为 4 个字节,这在程序将void*强制转换为int以及反之亦然时会引起问题。在 GCC 3.4 中,这会引起警告,编译不会中止。如果幸运的话,您的软件包可以运行,但是很可能会遇到段错误或奇怪的行为。 GCC 4.0 拒绝编译此类代码。

其他资源

results matching ""

    No results matching ""