Linux中國

32位支持:使用 GCC 交叉編譯

如果你是一個開發者,要創建二進位軟體包,像一個 RPM、DEB、Flatpak 或 Snap 軟體包,你不得不為各種不同的目標平台編譯代碼。典型的編譯目標包括 32 位和 64 位的 x86 和 ARM。你可以在不同的物理或虛擬機器上完成你的構建,但這需要你為何幾個系統。作為代替,你可以使用 GNU 編譯器集合 (GCC) 來交叉編譯,在單一的構建機器上為幾個不同的 CPU 架構產生二進位文件。

假設你有一個想要交叉編譯的簡單的擲骰子遊戲。在大多數系統上,以 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 => (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中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國