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 ++ :
- 产生一个32位二进制文件
- 链接到32位库,而不是默认的64位库
设置您的开发环境
要编译为32位,您需要在系统上安装32位库和标头。 如果运行纯64位系统,则没有32位库或头文件,并且需要安装基本集。 至少,您需要C和C ++库( glibc和libstdc ++ )以及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-gcc和binutils-arm-linux-gnueabi 。 这提供了(至少)构建简单C程序所需的命令和库。 另外,您需要代码使用的任何库。 您可以将头文件放在通常的位置(在大多数系统上为/ usr / include ),也可以将它们放在您选择的目录中,并使用-I选项将GCC指向它。
编译时,请勿使用标准的gcc或g ++命令。 而是使用您安装的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编译和交叉编译