一次搞定 Arm Linux 交叉編譯

2021-02-23 HackforFun
為什麼要交叉編譯

交叉編譯其實是相對於本地編譯(native build)來說的,我相信大家最開始學習 C/C++ 這些語言的時候,都是在電腦上寫程序,然後在電腦上編譯生成可執行文件,最後在電腦上運行。程序的編輯——》編譯——》運行,整個過程都是在一臺 X86 電腦上。

當我們開始接觸嵌入式開發後,事情變的不一樣了,你在電腦上寫程序,在電腦上編譯出可執行文件,最後這個可執行文件需要下載到你的開發板上運行。程序最後運行的環境變了,比如你的開發板是基於 Arm 的——程序在 X86 上編輯,編譯,最終運行在另一個和 X86 完全不同的架構的 Arm 晶片上。

之所以整個流程變成了這個樣子,這是由嵌入式系統的特性決定的:一般嵌入式系統裡面使用的晶片性能都比較弱,而且絕大部分都不能像 X86 一樣運行 Windows/Ubuntu 桌面系統,即使能運行,性能也很弱,無法給你提供一個在開發板上寫代碼、編譯代碼的環境。所以我們還是離不開 X86 電腦強大高效的桌面環境進行軟體開發。

但是這樣有一個問題,X86、Arm、MIPS、RISC-V 這些晶片,它們的指令集是由不同的組織或者公司設計的,彼此並不兼容——Arm 和 MIPS 的 CPU 無法運行以 X86 的指令集編碼的程序,反之亦然。所以我們要在 X86 的電腦上編譯出能夠在 Arm 上運行的程序,我們必須明確告訴編譯器,編譯生成的可執行文件需要以 Arm 指令集的標準編碼。為了讓這個流程變得簡單,開發者們為不同的晶片開發了不同的編譯器,比如針對 Arm 平臺的 arm-linux-gcc,針對 mips 平臺的 mips-linux-gnu-gcc,這些編譯器都是基於 GCC 針對具體的架構指令集進行對應配置,所以它們在運行的時候就就會生成和該目標平臺對應的可執行文件。

這篇文章主要講 Arm 的交叉編譯,所以這裡後面都以 Linux 開發環境下的 Arm gcc 為例。

工具鏈的種類

GCC 的命名規則為:arch [-vendor] [-os] [-(gnu)eabi]-gcc

比如 arm-linux-gnueabi-gcc , arm-none-eabi-gcc, aarch64-linux-gnu-gcc

帶 [] 的是可選部分。

arch:晶片架構,比如 32 位的 Arm 架構對應的 arch 為 arm,64 位的 Arm 架構對應的 arch 為 aarch64。

vendor :工具鏈提供商,大部分工具鏈名字裡面都沒有包含這部分。

os :編譯出來的可執行文件(目標文件)針對的作業系統,比如 Linux。

arm-none-eabi-gcc 一般適用用於 Arm Cortex-M/Cortex-R 平臺,它使用的是 newlib 庫。

arm-linux-gnueabi-gcc 和 aarch64-linux-gnu-gcc 適用於 Arm Cortex-A 系列晶片,前者針對 32 位晶片,後者針對 64 位晶片,它使用的是 glibc 庫。可以用來編譯 u-boot、linux kernel 以及應用程式。

另外需要補充一點的是,32 位的 Arm 和 64 位的 Arm,它們的指令集是不同的,所以需要使用不同的工具鏈。當然,Arm64 為了保證前向兼容,提供了一個 32 位的兼容模式,所以我們用 arm-linux-gnueabi-gcc 編譯的應用程式也是可以直接在Arm64 的系統上運行的,但是 Linux Kernel 和 U-Boot 就不行,除非你提前把 CPU 切換到 32 位模式。曾經有個項目使用了一顆四核的 Arm64 晶片,但是內存只有64M,為了節省空間,在 CPU 運行到 U-Boot 之前,我們就把它切到了 32 位模式,後面的 U-Boot、Linux Kernel,應用全部都用 32 位編譯,加上 Thumb 指令集,節省了不少空間。

工具鏈的下載安裝下載地址

現在 Arm 平臺上用的最廣泛的工具鏈是 Linaro 發布的,大家可以到 Linaro 官網下載,地址如下:

http://releases.linaro.org/components/toolchain/binaries/

同時我發現 Linaro 申明稱後續新版本的工具鏈會通過 Arm 官方發布。

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain

4.9、6.3、7.4 這些是工具鏈的版本號,理論上越新的版本,性能越好。

在一次優化 u-boot 大小的時候我發現 6.3 版本的工具鏈生成的二進位文件要比 4.9 版本生成的小几百個字節,進一步對比分析後發現是因為 6.3 版本的工具鏈把代碼中沒用到的一些字符串全部過濾掉了,雖然 4.9 的版本也有過濾,但是沒有 6.3 做的乾淨。

目前用的多的版本應該是 6.x,當然我也看到有些開發組織在使用 7.x 的工具鏈,比如 Armbian 目前在用 7.4 編譯內核。

另外目前最新版本的 U-Boot 已經強制必須使用 6.0 以上版本的 GCC 進行編譯。

這兩個網站下載可能會比較慢,可以考慮使用國內的鏡像下載:

https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/

下載

可以直接點擊下載,也可以通過命令行用 wget 命令下載:

wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz

wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz

下載了兩個,arm 針對是是 32 位的, aarch64 針對 Arm64.

安裝

解壓:

xz -d gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz

xz -d gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz

安裝到 /usr/local/toolchain/ 目錄下,當然也可以放在其他任何你喜歡的地方:

sudo mkdir -p /usr/local/toolchain

tar -xvf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar -C /usr/local/toolchain/

sudo tar -xvf gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar -C /usr/local/toolchain/

成功後執行 ls 命令,可以看到兩個 toolchain 都被安裝到 /usr/local/toolchain/ 目錄下了。

添加環境變量

只有把可執行文件對應的路徑加入到 PATH 環境變量裡,系統才可以認到這些命令。

這裡的路徑就是上面截圖中 pwd 命令顯示的路徑,可以添加到 ~/.bashrc 文件的最後:

PATH=$PATH:/usr/local/toolchain/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin:/usr/local/toolchain/gcc-linaro-6.4.

1-2017.11-x86_64_aarch64-linux-gnu/bin

注意:兩個獨立的路徑之間用 冒號 : 隔開。

執行 source~/.bashrc 命令讓配置生效,然後我們就可以在命令行裡執行這些命令了:

比如 arm-linux-gnueabihf-gcc-v 和 aarch64-linux-gnu-gcc-v 查看編譯器版本:

能看到如圖的信息,說明已經大功告成了。

編譯內核

這裡下載 imx 的官方內核:

git clone https://source.codeaurora.org/external/imx/linux-imx

切換到 4.19 版本:

git checkout -b imx_v2019.04_4.19.35_1.0.0 origin/imx_v2019.04_4.19.35_1.0.0

編譯:

make ARCH=arm imx_v7_defconfig

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

如果你電腦上其他的依賴庫都安裝的完整,就能順利編譯成功。

相關焦點

  • valgrind簡介以及在ARM上交叉編譯運行
    這裡記錄一下在ARM上的交叉編譯及使用過程中的一些問題。1、下載及編譯準備wget http://valgrind.org/downloads/valgrind-3.12.0.tar.bz2tar xvf valgrind-3.12.0.tar.bz2cd valgrind-3.12.0apt-get install automake.
  • 搭建ros交叉編譯環境(從x86到nvidia arm)
    交叉編譯環境搭建流程交叉編譯環境搭建的主要思路是利用catkin提供的rostoolchain腳本設置相應的交叉編譯工具、lib庫地址等,中間遇到問題再針對性解決。:1.ARM ubuntu環境上安裝arm-indigo版本,後面需要將這個arm版本copy到交叉編譯環境上。
  • openssl交叉編譯
    ,幾個常用的配置選項說明:–cross-compile-prefix=PREFIX指定交叉編譯工具鏈,以連接號結束,如 arm-linux-gnueabihf-–prefix=DIR指定 openssl 的安裝目錄,如果只是想生成庫文件,沒有必要執行 make install 命令,也就可以不用指定該選項–openssldir=DIR
  • 手把手教你在X86系統上交叉編譯ARM版本的ClickHouse
    手把手教你在X86系統上交叉編譯ARM版本的ClickHouse應用背景2020年10月,華為聯繫我司,希望我司可以對目前華為鯤鵬的生態做一些軟體適配類的工作,為之後其他項目使用鯤鵬伺服器做好鋪墊。X86版本的ClickHouse由於交叉編譯過程中需要將proto文件轉換為c++的源碼文件, 需要採用x86的protoc以及protoc-gen-grpc工具, 所以先編譯x86版本的ClickHouse# 編譯X86版本的ClickHousecd ClickHousemkdir buildcd buildcmake
  • Linux Kernel 和 U-Boot 編譯的那些事
    之前的文章:《一次搞定交叉編譯》 給大家講了如何安裝交叉編譯工具鏈,搭建交叉編譯環境。
  • 音視頻開發之旅(33) -交叉編譯android使用的FFmpeg(3.x和4.x)
    --cross-prefix=${CROSS_PREFIX} \ #開啟交叉編譯 --enable-crosss-compile \ #指定目標平臺為linux(android內核也是基於linux的ffmpeg早期版本目標平臺還不可以指定為android)
  • gcc、arm-linux-gcc和arm-elf-gcc的關係?
    在使用交叉編譯的情況下,這些工具將根據它編譯的目標而命名。例如,要使用交叉工具鏈為 ARM 機器編譯簡單的 Hello World 程序,你可以運行如下所示的命令:使用如下命令編譯並測試這個代碼: arm-linux-gcc -o hello hello.c。
  • FFMPEG與X264基於Android NDK的交叉編譯
    ,基於android-21,這個版本號需要和Application.mk中的一致SYSROOT=$NDK/platforms/android-21/arch-arm/# 配置用於交叉編譯的CROSS_PREFIXCROSS_PREFIX=$TOOLCHAINS/bin/arm-linux-androideabi-echo "CROSS_PREFIX=$CROSS_PREFIX"# 一些全局變量ROOT_DIR
  • Linux驅動05 | 內核編譯
    二、電腦的開發環境虛擬機:VMWare12.0以上作業系統:Ubuntu 16.04晶片源碼包:6818_kernel_wen.tar.gz,包含交叉編譯工具、kernel源碼、鏡像製作工具。三、源碼編譯過程對於源碼包的編譯,切換到root用戶進行操作。
  • 手把手教你樹莓派linux內核如何編譯
    之前我們講過樹莓派交叉編譯工具鏈的安裝和配置,今天我們就來講如何利用我們安裝好的交叉編譯器編譯樹莓派linux內核。
  • Linux下使用QEMU構建ARM運行環境
    1.下載Linux內核方法一:使用gitgit clonegit://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 方法二:直接下載3.17原始碼包wget https://www.kernel.org/pub/linux/kernel
  • gcc&arm-linux-gcc編譯過程詳解
    :1.gcc 2.指針,3.Makefile ,今天是第一部分gcc,內容同樣適用於arm-linux-gcc。老規矩,文字無法完整描述視頻內容,如果覺得這些文章對你有用,想進一步學習更深層次的乾貨,請訪問100ask.taobao.com購買arm裸機1期加強版視頻課程。
  • Cygwin下ndk standalone版本的交叉編譯環境搭建(Root研究)
    驗證Windows環境編譯Android等的環境是否搭建成功驗證NDK編譯環境是否配置成功系統用戶名與新裝的系統用戶名不一致的解決方法1) $ mkpasswd -l > /etc/passwd2) $ mkgroup  -l > /etc/group3) 再重新運行cygwin.bat4) 也可以直接修改/etc/passwd,把裡面涉及到原系統用戶名的地方都更新為現在的用戶名Cygwin下ndk standalone版本的交叉編譯環境搭建
  • SQLite3在ARM Cortex-A9開發板上的移植
    /configure --prefix=$PWD/build --host=i386-linux  說明  --prefix: 指定安裝路徑  --host:指定主機編譯環境  arm-linux是指ARM交叉編譯  i386-linux是指x86系統  CC:指定編譯器  如果--host是arm-linux
  • 【教程】arm-linux-gcc 4.3.2編譯uboot-1.1.6
    在第三期項目的視頻中,官方提供了一整套新的工具鏈,bootloader,內核和文件系統(arm-linux-gcc_4.3.2, uboot-2012.04.01
  • /arm-none-linux-gnueabi-gcc: No such file or directory
    交叉編譯工具:arm-2009q3.tar.bz2解壓 arm-2009q3.tar.bz2 tar xjvf arm-2009q3.tar.bz2 -C /home/imx6/share/問題描述運行發現: imx6@imx6-vm:~/share
  • TSN之iproute2交叉編譯
    0 開發環境1 iproute2是什麼2 為什麼要交叉編譯
  • Golang 交叉編譯如何做?
    說明我們將講解命令各個參數的作用,希望你在閱讀時,將每一項串聯起來,你會發現這就是交叉編譯相關的小知識也就是 Golang 令人心動的特性之一跨平臺編譯一、CGO_ENABLED在標準 go 命令的上下文環境中,交叉編譯意味著程序構建環境的目標計算架構的標識與程序運行環境的目標計算架構的標識不同,或者程序構建環境的目標作業系統的標識與程序運行環境的目標作業系統的標識不同小結:結合案例來說,我們是在宿主機編譯的可執行文件,而在
  • 嘗試codeblock實現Hi35xx的交叉編譯
    剛開始接觸linux下Hi35xx的交叉編譯,對於makefile的使用感覺實在太頭疼,不懂makefile語法,對Hi35xx的工程也不了解,
  • 系列篇編譯可在Android上運行的依賴庫:glib庫
    由於glib庫依賴於其他第三方庫,所以需要先將依賴的第三方庫交叉編譯到Android平臺上才能成功的編譯glib庫,系列文章中除《編譯可在Android上運行的glib庫》外的其他交叉編譯文章均是介紹如何對glib依賴庫進行交叉編譯。整理成5篇系列文章,並完整的介紹了如何編譯可在Android上運行的glib庫。