Merge pull request #14620 from robsean/patch-5

Translated
This commit is contained in:
Xingyu.Wang 2019-07-17 08:38:47 +08:00 committed by GitHub
commit 2af273ebc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 188 additions and 189 deletions

View File

@ -1,189 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (32-bit life support: Cross-compiling with GCC)
[#]: via: (https://opensource.com/article/19/7/cross-compiling-gcc)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
32-bit life support: Cross-compiling with GCC
======
Use GCC to cross-compile binaries for different architectures from a
single build machine.
![Wratchet set tools][1]
If you're a developer creating binary packages, like an RPM, DEB, Flatpak, or Snap, you have to compile code for a variety of different target platforms. Typical targets include 32-bit and 64-bit x86 and ARM. You could do your builds on different physical or virtual machines, but that means maintaining several systems. Instead, you can use the GNU Compiler Collection ([GCC][2]) to cross-compile, producing binaries for several different architectures from a single build machine.
Assume you have a simple dice-rolling game that you want to cross-compile. Something written in C is relatively easy on most systems, so to add complexity for the sake of realism, I wrote this example in C++, so the program depends on something not present in C (**iostream**, specifically).
```
#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";
   }
```
Compile it on your system using the **g++** command:
```
`$ g++ dice.cpp -o dice`
```
Then run it to confirm that it works:
```
$ ./dice
Pick a number between 1 and 20:
[...]
```
You can see what kind of binary you just produced with the **file** command:
```
$ 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
```
And just as important, what libraries it links to with **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)
```
You have confirmed two things from these tests: The binary you just ran is 64-bit, and it is linked to 64-bit libraries.
That means that, in order to cross-compile for 32-bit, you must tell **g++** to:
1. Produce a 32-bit binary
2. Link to 32-bit libraries instead of the default 64-bit libraries
### Setting up your dev environment
To compile to 32-bit, you need 32-bit libraries and headers installed on your system. If you run a pure 64-bit system, then you have no 32-bit libraries or headers and need to install a base set. At the very least, you need the C and C++ libraries (**glibc** and **libstdc++**) along with 32-bit version of GCC libraries (**libgcc**). The names of these packages may vary from distribution to distribution. On Slackware, a pure 64-bit distribution with 32-bit compatibility is available from the **multilib** packages provided by [Alien BOB][3]. On Fedora, CentOS, and RHEL:
```
$ yum install libstdc++-*.i686
$ yum install glibc-*.i686
$ yum install libgcc.i686
```
Regardless of the system you're using, you also must install any 32-bit libraries your project uses. For instance, if you include **yaml-cpp** in your project, then you must install the 32-bit version of **yaml-cpp** or, on many systems, the development package for **yaml-cpp** (for instance, **yaml-cpp-devel** on Fedora) before compiling it.
Once that's taken care of, the compilation is fairly simple:
```
`$ g++ -m32 dice.cpp -o dice32 -L /usr/lib -march=i686`
```
The **-m32** flag tells GCC to compile in 32-bit mode. The **-march=i686** option further defines what kind of optimizations to use (refer to **info gcc** for a list of options). The **-L** flag sets the path to the libraries you want GCC to link to. This is usually **/usr/lib** for 32-bit, although, depending on how your system is set up, it could be **/usr/lib32** or even **/opt/usr/lib** or any place you know you keep your 32-bit libraries.
After the code compiles, see proof of your build:
```
$ file ./dice32
dice: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
dynamically linked (uses shared libs) [...]
```
And, of course, **ldd ./dice32** points to your 32-bit libraries.
### Different architectures
Compiling 32-bit on 64-bit for the same processor family allows GCC to make many assumptions about how to compile the code. If you need to compile for an entirely different processor, you must install the appropriate cross-build GCC utilities. Which utility you install depends on what you are compiling. This process is a little more complex than compiling for the same CPU family.
When you're cross-compiling for the same family, you can expect to find the same set of 32-bit libraries as 64-bit libraries, because your Linux distribution is maintaining both. When compiling for an entirely different architecture, you may have to hunt down libraries required by your code. The versions you need may not be in your distribution's repositories because your distribution may not provide packages for your target system, or it may not mirror all packages in a convenient location. If the code you're compiling is yours, then you probably have a good idea of what its dependencies are and possibly where to find them. If the code is something you have downloaded and need to compile, then you probably aren't as familiar with its requirements. In that case, investigate what the code requires to build correctly (they're usually listed in the README or INSTALL files, and certainly in the source code itself), then go gather the components.
For example, if you need to compile C code for ARM, you must first install **gcc-arm-linux-gnu** (32-bit) or **gcc-aarch64-linux-gnu** (64-bit) on Fedora or RHEL, or **arm-linux-gnueabi-gcc** and **binutils-arm-linux-gnueabi** on Ubuntu. This provides the commands and libraries you need to build (at least) a simple C program. Additionally, you need whatever libraries your code uses. You can place header files in the usual location (**/usr/include** on most systems), or you can place them in a directory of your choice and point GCC to it with the **-I** option.
When compiling, don't use the standard **gcc** or **g++** command. Instead, use the GCC utility you installed. For example:
```
$ arm-linux-gnu-g++ dice.cpp \
  -I/home/seth/src/crossbuild/arm/cpp \
  -o armdice.bin
```
Verify what you've built:
```
$ file armdice.bin
armdice.bin: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV) [...]
```
### Libraries and deliverables
This was a simple example of how to use cross-compiling. In real life, your source code may produce more than just a single binary. While you can manage this manually, there's probably no good reason to do that. In my next article, I'll demonstrate GNU Autotools, which does most of the work required to make your code portable.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/cross-compiling-gcc
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_osyearbook2016_sysadmin_cc.png?itok=Y1AHCKI4 (Wratchet set tools)
[2]: https://gcc.gnu.org/
[3]: http://www.slackware.com/~alien/multilib/

View File

@ -0,0 +1,188 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (32-bit life support: Cross-compiling with GCC)
[#]: via: (https://opensource.com/article/19/7/cross-compiling-gcc)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
32位生存支持使用 GCC 交叉编译
======
使用 GCC 从一个单个构建机器中来为不同的架构交叉编译二进制文件。
![Wratchet set tools][1]
如果你是一个开发者,创建二进制软件包,像一个 RPM, DEB, Flatpak,或 Snap 软件包你不得不来为各种不同的目标平台编译代码。典型的目标包括32位和64位的 x86 和 ARM 。你可以在不同的物理或虚拟机器上完成你的构建。作为代替,你可以使用 GNU 编译器集合 ([GCC][2]) 来交叉编译,从一个单个构建机器中为几个不同的架构产生二进制文件。
假设你有一个简单的掷骰子游戏,你想交叉编译。在大多数系统上,以 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`
```
然后,运行它来确认其工作:
```
$ ./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 =&gt; (0x00007ffe0d1dc000)
libstdc++.so.6 =&gt; /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(0x00007fce8410e000)
libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6
(0x00007fce83d4f000)
libm.so.6 =&gt; /lib/x86_64-linux-gnu/libm.so.6
(0x00007fce83a52000)
/lib64/ld-linux-x86-64.so.2 (0x00007fce84449000)
libgcc_s.so.1 =&gt; /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++ 库 (**glibc** 和 **libstdc++**) 以及GCC 库 (**libgcc**) 的32位版本。这些软件包的名称可能在每个发行版中不同。在 Slackware 系统上一个纯64位的带有32位兼容的发行版可以从 [Alien BOB][3] 提供的 **multilib** 软件包中获得。在 FedoraCentOS和 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 发行版是同时维护的。当为一个完全不同的架构编译时,你可能不得不穷追你代码需要的库。你需要的版本可能不在你的发行版的存储库中,因为你的发行版可能不为你的目标系统提供软件包,或者它不在容易到达的位置映照所有的软件包。如果你正在编译的代码是你的,那么你可能非常清楚它的依赖关系是什么,和清楚在哪里找到它们。如果代码是你下载的,并需要编译,那么你可能不熟悉它的要求。在这种情况下,研究正确编译代码需要什么 (它们通常被列在 README 或 INSTALL 文件中,当然也在源文件代码自身之中),然后收集需要的组件。
例如,如果你需要为 ARM 编译 C 代码你必需首先在Fedora 或 RHEL 上安装 **gcc-arm-linux-gnu** (32位) 或 **gcc-aarch64-linux-gnu** (64位),或者,在 Ubuntu 上安装 **arm-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 自动工具GNU 自动工具做大多数工作来使你的代码可移植。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/7/cross-compiling-gcc
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_osyearbook2016_sysadmin_cc.png?itok=Y1AHCKI4 (Wratchet set tools)
[2]: https://gcc.gnu.org/
[3]: http://www.slackware.com/~alien/multilib/