针对CPU Arch的交叉编译或编译原生

2w3rbyxf  于 2023-03-29  发布在  其他
关注(0)|答案(5)|浏览(163)

当编写依赖于CPU架构的软件时,例如在x86上运行的C代码或在ARM CPU上运行的C代码。通常有两种方法来编译这些代码,要么交叉编译到ARM CPU架构(例如,如果您在x86系统上开发),要么将代码复制到本地arch CPU系统并进行本地编译。
我想知道本机方法与交叉编译方法相比是否有好处?我注意到Fedora ARM团队正在使用一个缓慢/低功耗ARM设备的构建服务器集群来“本机”编译他们的Fedora ARM spin...当然,由Red Hat支持的项目可以访问一些运行x86 CPU的强大构建服务器,这些服务器可以在1/2的时间内完成工作...那么为什么他们选择?交叉编译我的软件是否遗漏了什么?

x8goxv8g

x8goxv8g1#

主要的好处是所有的./configure脚本在本地运行时不需要调整。如果你使用的是shadowrootfs,那么你仍然有运行uname的配置来检测CPU类型等。例如,请参阅this questionpkgconfig和其他工具试图简化 * 交叉构建 *,但是软件包通常会先在x86上进行 * 本机构建 *,然后在ARM上进行 * 本机构建 交叉构建 * 可能会很痛苦,因为每个软件包可能需要单独的调整。
最后,如果您正在执行profile guided optimizations并按照Joachim运行 * 测试套件 *,那么在 * 交叉构建 * 环境中几乎不可能做到这一点。

ARM上的编译速度明显快于人类包构建器,读取configure,编辑configure,重新运行配置,编译,链接周期。

这也很适合continuous integration策略。各种软件包,尤其是 libraries,可以快速构建/部署/测试。libraries 的测试可能涉及数百个依赖包。Arm *Linux发行版 * 在升级和修补基础库时通常需要对更改进行原型化,该基础库可能有数百个依赖包,至少需要重新测试。由计算机完成的缓慢循环总是比由人工干预的快速编译要好。

dvtswwa3

dvtswwa32#

不,从技术上讲,在.c -〉.o -〉a.out(或其他)的上下文中进行交叉编译不会遗漏任何内容;交叉编译器会给予你和本机编译器一样的二进制文件(尽管版本不同)
本机构建的“优势”来自编译后测试和管理复杂系统。
1)如果我能在编译后快速运行单元测试,我就能快速找到任何bug/问题,这个周期大概比交叉编译周期短;
2)如果我正在编译一些目标软件,它使用第三方库,那么在本机平台上构建,部署并使用它们来构建我的目标可能会更容易;我不想处理那些交叉编译的构建,因为其中一半的构建过程是由疯狂的猴子编写的,这使得交叉编译变得非常痛苦。
通常情况下,对于大多数事情,人们会尝试获得基本构建并在本机编译其余部分。除非我有一个生病的设置,我的交叉编译器超级快,我在那里保存的时间是值得的,以使其余的事情(如单元测试和依赖项管理)更容易。
至少我是这么想的

fivyi3re

fivyi3re3#

本机编译的唯一好处是,您不必将程序转移到目标平台,因为它已经在那里了。
然而,考虑到大多数目标平台与现代x86 PC相比性能严重不足,这并不是一个很大的好处。内存量,更快的CPU,特别是更快的磁盘使PC上的编译时间快了很多倍。以至于本机构建的优势不再是一个真正的优势。

cbeh67ev

cbeh67ev4#

这在很大程度上取决于编译器。工具链如何处理本机和交叉编译之间的差异。是否只是工具链总是认为它是作为交叉编译器构建的,但构建它的一种方法是让配置脚本自动检测主机,而不是手动操作(并自动设置前缀等)?
不要因为它是一个原生编译器就认为它真的是原生编译器。有很多例子,发行版将其原生编译器(以及内核和其他二进制文件)简化,以便该发行版可以在更广泛的系统上运行。例如,在ARMv 6系统上,您可能正在运行默认为ARMv 4的编译器。
这就引出了一个类似的问题,如果我用一个默认架构构建工具链,然后指定另一个,那么为目标架构构建工具链有什么不同吗?
理想情况下,你会希望一个主要调试的编译器/工具链会给予你相同的结果,无论你是原生的还是交叉编译的,并且独立于默认架构。现在我在一个旧的llvm上看到llvm-gcc在64位主机上运行时,交叉编译到arm会将所有int构建为64位,增加了很多代码,相同的编译器版本,32位主机上的相同源代码将给予不同的结果基本上-m32开关不适用于llvm-gcc(当时),我不知道这是否仍然是这样,因为我切换到clang时做llvm的工作,从来没有回头看llvm-gcc... llvm/例如,clang一直以来都是一个交叉编译器,链接器是唯一一个看起来特定于主机的东西,你可以使用现成的llvm,在任何主机系统上编译任何目标(当然,前提是你的构建没有禁用任何支持的目标)。

sr4lhrrt

sr4lhrrt5#

虽然许多人认为“本地编译”比“交叉编译”更有好处,或者至少没有什么区别,但事实恰恰相反。
对于那些在低层(如linux内核)工作的人来说,他们通常会遭受编译平台周围的复制,以x86和ARM为例,直接的想法是建立ARM编译库,但这是一个坏主意。
二进制有时候是不一样的,例如,

# diff hello_x86.ko hello_arm.ko
Binary files hello_x86.ko and hello_arm.ko differ
# diff hello_x86_objdump.txt hello_arm_objdump.txt
2c8
< hello_x86.ko:     file format elf64-littleaarch64
---
> hello_arm.ko:     file format elf64-littleaarch64
26,27c26,27
<    8: 91000000        add     x0, x0, #0x0
<    c: 910003fd        mov     x29, sp
---
>    8: 910003fd        mov     x29, sp
>    c: 91000000        add     x0, x0, #0x0

一般来说,较高级别的应用程序可以同时使用,较低级别(硬件相关)的工作建议使用x86 "cross compile",因为它有更好的工具链。
无论如何,compile是一个关于GCC Glibc和www.example.com的工作lib.so,如果你熟悉这些,任何一种方式都应该很容易。
PS:下面是源代码

# cat hello.c
#include <linux/module.h>      /* Needed by all modules */
#include <linux/kernel.h>      /* Needed for KERN_ALERT */
#include <linux/init.h>        /* Needed for the macros */


static int hello3_data __initdata = 3;

static int __init hello_3_init(void)
{
   printk(KERN_ALERT "Hello, world %d\n", hello3_data);
   return 0;
}

static void __exit hello_3_exit(void)
{
   printk(KERN_ALERT "Goodbye, world 3\n");
}

module_init(hello_3_init);
module_exit(hello_3_exit);

MODULE_LICENSE("GPL");

相关问题