32位支持:使用 GCC 交叉编译
创始人
2024-03-02 03:12:38
0

使用 GCC 在单一的构建机器上来为不同的 CPU 架构交叉编译二进制文件。

如果你是一个开发者,要创建二进制软件包,像一个 RPM、DEB、Flatpak 或 Snap 软件包,你不得不为各种不同的目标平台编译代码。典型的编译目标包括 32 位和 64 位的 x86 和 ARM。你可以在不同的物理或虚拟机器上完成你的构建,但这需要你为何几个系统。作为代替,你可以使用 GNU 编译器集合 (GCC) 来交叉编译,在单一的构建机器上为几个不同的 CPU 架构产生二进制文件。

假设你有一个想要交叉编译的简单的掷骰子游戏。在大多数系统上,以 C 语言来编写这个相对简单,出于给添加现实的复杂性的目的,我以 C++ 语言写这个示例,所以程序依赖于一些不在 C 语言中东西 (具体来说就是 iostream)。

#include 
#include 

using namespace std;

void lose (int c); 
void win (int c); 
void draw (); 

int main() { 
  int i; 
    do { 
      cout << "Pick a number between 1 and 20: \n"; 
      cin >> i; 
      int c = rand ( ) % 21; 
      if (i > 20) lose (c); 
      else if (i < c ) lose (c); 
      else if (i > c ) win (c); 
      else draw (); 
      } 
      while (1==1); 
      }

void lose (int c ) 
  { 
    cout << "You lose! Computer rolled " << c << "\n"; 
  }

void win (int c ) 
  { 
    cout << "You win!! Computer rolled " << c << "\n"; 
   }

void draw ( ) 
   { 
     cout << "What are the chances. You tied. Try again, I dare you! \n";
   }

在你的系统上使用 g++ 命令编译它:

$ g++ dice.cpp -o dice

然后,运行它来确认其工作:

$ ./dice
Pick a number between 1 and 20:
[...]

你可以使用 file 命令来查看你刚刚生产的二进制文件的类型:

$ file ./dice
dice: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically
linked (uses shared libs), for GNU/Linux 5.1.15, not stripped

同样重要,使用 ldd 命令来查看它链接哪些库:

$ ldd dice
linux-vdso.so.1 => (0x00007ffe0d1dc000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(0x00007fce8410e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
(0x00007fce83d4f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6
(0x00007fce83a52000)
/lib64/ld-linux-x86-64.so.2 (0x00007fce84449000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1
(0x00007fce8383c000)

从这些测试中,你已经确认了两件事:你刚刚运行的二进制文件是 64 位的,并且它链接的是 64 位库。

这意味着,为实现 32 位交叉编译,你必需告诉 g++ 来:

  1. 产生一个 32 位二进制文件
  2. 链接 32 位库,而不是 64 位库

设置你的开发环境

为编译成 32 位二进制,你需要在你的系统上安装 32 位的库和头文件。如果你运行一个纯 64 位系统,那么,你没有 32 位的库或头文件,并且需要安装一个基础集合。最起码,你需要 C 和 C++ 库(glibclibstdc++)以及 GCC 库(libgcc)的 32 位版本。这些软件包的名称可能在每个发行版中不同。在 Slackware 系统上,一个纯 64 位的带有 32 位兼容的发行版,可以从 Alien BOB 提供的 multilib 软件包中获得。在 Fedora、CentOS 和 RHEL 系统上:

$ yum install libstdc++-*.i686
$ yum install glibc-*.i686
$ yum install libgcc.i686

不管你正在使用什么系统,你同样必须安装一些你工程使用的 32 位库。例如,如果你在你的工程中包含 yaml-cpp,那么,在编译工程前,你必需安装 yaml-cpp 的 32 位版本,或者,在很多系统上,安装 yaml-cpp 的开发软件包(例如,在 Fedora 系统上的 yaml-cpp-devel)。

一旦这些处理好了,编译是相当简单的:

$ g++ -m32 dice.cpp -o dice32 -L /usr/lib -march=i686

-m32 标志告诉 GCC 以 32 位模式编译。-march=i686 选项进一步定义来使用哪种最优化类型(参考 info gcc 了解选项列表)。-L 标志设置你希望 GCC 来链接的库的路径。对于 32 位来说通常是 /usr/lib,不过,这依赖于你的系统是如何设置的,它可以是 /usr/lib32,甚至 /opt/usr/lib,或者任何你知道存放你的 32 位库的地方。

在代码编译后,查看你的构建的证据:

$ file ./dice32
dice: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
dynamically linked (uses shared libs) [...]

接着,当然, ldd ./dice32 也会指向你的 32 位库。

不同的架构

在 64 位相同的处理器家族上允许 GCC 做出很多关于如何编译代码的假设来编译 32 位软件。如果你需要为完全不同的处理器编译,你必需安装适当的交叉构建实用程序。安装哪种实用程序取决于你正在编译的东西。这个过程比为相同的 CPU 家族编译更复杂一点。

当你为相同处理器家族交叉编译时,你可以期待找到与 32 位库集的相同的 64 位库集,因为你的 Linux 发行版是同时维护这二者的。当为一个完全不同的架构编译时,你可能不得不穷追你的代码所需要的库。你需要的版本可能不在你的发行版的存储库中,因为你的发行版可能不为你的目标系统提供软件包,或者它不在容易到达的位置提供所有的软件包。如果你正在编译的代码是你写的,那么你可能非常清楚它的依赖关系是什么,并清楚在哪里找到它们。如果代码是你下载的,并需要编译,那么你可能不熟悉它的要求。在这种情况下,研究正确编译代码需要什么(它们通常被列在 READMEINSTALL 文件中,当然也出现在源文件代码自身之中),然后收集需要的组件。

例如,如果你需要为 ARM 编译 C 代码,你必须首先在 Fedora 或 RHEL 上安装 gcc-arm-linux-gnu(32 位)或 gcc-aarch64-linux-gnu(64 位);或者,在 Ubuntu 上安装 arm-linux-gnueabi-gccbinutils-arm-linux-gnueabi。这提供你需要用来构建(至少)一个简单的 C 程序的命令和库。此外,你需要你的代码使用的任何库。你可以在惯常的位置(大多数系统上在 /usr/include)放置头文件,或者,你可以放置它们在一个你选择的目录,并使用 -I 选项将 GCC 指向它。

当编译时,不使用标准的 gccg++ 命令。作为代替,使用你安装的 GCC 实用程序。例如:

$ arm-linux-gnu-g++ dice.cpp \
  -I/home/seth/src/crossbuild/arm/cpp \
  -o armdice.bin

验证你构建的内容:

$ file armdice.bin
armdice.bin: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV) [...]

库和可交付结果

这是一个如何使用交叉编译的简单的示例。在真实的生活中,你的源文件代码可能产生的不止于一个二进制文件。虽然你可以手动管理,在这里手动管理可能不是好的正当理由。在我接下来的文章中,我将说明 GNU 自动工具,GNU 自动工具做了使你的代码可移植的大部分工作。


via: https://opensource.com/article/19/7/cross-compiling-gcc

作者:Seth Kenlon 选题:lujun9972 译者:robsean 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

华为仓颉编程语言首个 LT...
IT之家 7 月 1 日消息,华为仓颉编程语言首个 LTS 版本 ...
2025-07-01 21:12:49
VS2022配置工程的编译...
VS2022配置工程的编译路径(输出目录和中间目录&...
2025-06-01 19:24:39
编译原理个人作业--第二章
第二章 6 文法G6G_6G6​为 N→D∣NDN\rightar...
2025-05-31 13:52:40
Ubuntu20.4配置a...
Ubuntu20.4配置arm交叉编译环境 我是在虚拟机中配置的&...
2025-05-31 12:39:52
关于导入、编译、烧录S32...
问题来自于实践。 在学习了EB关于相关模块的配置之后,...
2025-05-31 10:37:52
【UNIX 环境编程】GC...
💭 写在前面:本文将介绍如何使用 G...
2025-05-31 02:18:08

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
2024 开年,LLUG 和你... Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...
什么是 KDE Connect... 什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...
Opera 浏览器内置的 VP... 昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...