gcc编译和交叉编译

如果您是创建二进制程序包(例如RPM,DEB,Flatpak或Snap)的开发人员,则必须为各种不同的目标平台编译代码。 典型目标包括32位和64位x86和ARM。 您可以在不同的物理或虚拟机上进行构建,但这意味着要维护多个系统。 相反,您可以使用GNU编译器集合( GCC )进行交叉编译,从而在一台构建机器上为几种不同的体系结构生成二进制文件。

假设您有一个想要交叉编译的简单掷骰子游戏。 在大多数系统上,用C编写的东西相对容易,因此为了现实起见,我增加了复杂性,我用C ++编写了这个示例,因此程序依赖于C中不存在的东西(特别是iostream )。

#include <iostream> 
     
     
#include <cstdlib> 
     
     

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 
$  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 ++ )以及32位版本的GCC库( libgcc )。 这些软件包的名称可能因发行版本而异。 在Slackware上, Alien BOB提供的multilib软件包提供了具有32位兼容性的纯64位发行版。 在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 
$  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位库相同的一组32位库,因为您的Linux发行版同时维护了这两个库。 在为完全不同的体系结构进行编译时,您可能必须寻找代码所需的库。 您所需的版本可能不在发行版本的存储库中,因为您的发行版本可能未提供目标系统的软件包,或者未在方便的位置镜像所有软件包。 如果您要编译的代码是您自己的代码,那么您可能对它的依赖项以及可能在哪里找到它们有个好主意。 如果代码是您下载的并且需要编译,则您可能不熟悉其要求。 在这种情况下,请研究正确构建代码所需的内容(它们通常列在README或INSTALL文件中,当然也包含在源代码本身中),然后收集组件。

例如,如果您需要为ARM编译C代码,则必须首先在Fedora或RHEL上安装gcc-arm-linux-gnu (32位)或gcc-aarch64-linux-gnu (64位),或arm- Ubuntu上的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 Autotools,它完成了使代码可移植的大部分工作。

翻译自: https://opensource.com/article/19/7/cross-compiling-gcc

gcc编译和交叉编译