日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具

發(fā)布時(shí)間:2024/10/14 106 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

??最近,工作重心要從裸機(jī)開發(fā)轉(zhuǎn)移到嵌入式 Linux 系統(tǒng)開發(fā),由于之前對嵌入式 Linux 環(huán)境并不是很了解,因此,第一步就是需要了解如何搭建一個(gè)完整的嵌入式 Linux 環(huán)境。現(xiàn)在將學(xué)習(xí)心得記錄為此文。

嵌入式 Linux 環(huán)境

??嵌入式 Linux 環(huán)境與我們熟悉的 PC 環(huán)境還是有很大區(qū)別的,要搭建出一套完整的嵌入式 Linux 環(huán)境需要做的工作相當(dāng)多。下圖是我根據(jù)學(xué)習(xí)整理的一個(gè)嵌入式 Linux 環(huán)境示意圖:

  • BootLoader:通常使用的是 U-Boot,就是一個(gè)復(fù)雜點(diǎn)的裸機(jī)程序,與我們通常編寫的 ARM 裸機(jī)程序沒有本質(zhì)區(qū)別。BootLoader 需幫助內(nèi)核實(shí)現(xiàn)重定位,BootLoader 還要給內(nèi)核提供啟動參數(shù)。

    BootLoader 是無條件啟動的,從零開始啟動的。

  • Linux Kernel: 本身也是一個(gè)復(fù)雜的裸機(jī)程序。與裸機(jī)程序相比,內(nèi)核運(yùn)行起來后,在軟件上分為內(nèi)核層和應(yīng)用層,分層后兩層的權(quán)限不同,內(nèi)存訪問和設(shè)備操作的管理上更加精細(xì)(內(nèi)核可以隨便訪問各種硬件,而應(yīng)用程序只能被限制地訪問硬件和內(nèi)存地址)。

    內(nèi)核是不能開機(jī)自動完全從零開始啟動的,需要 BootLoader 幫忙。

  • 裸機(jī)程序編譯工具鏈: 這個(gè)編譯工具鏈(名字是我自己起的)編譯出特定于架構(gòu)的純裸機(jī)程序以在指定架構(gòu)上運(yùn)行。一般由內(nèi)核廠家提供,我們最為熟知的就是 ARM 提供的 GNU Arm Embedded Toolchain 中的 arm-none-eabi-*、Keil 中的 armcc、IAR。

    通常采用交叉編譯。

  • linux 程序編譯工具鏈: 這個(gè)編譯工具鏈(名字是我自己起的)用于編譯出在我們的嵌入式 Linux 環(huán)境中運(yùn)行的用戶程序。通常這個(gè)編譯工具鏈需要我們根據(jù)自己的嵌入式 Linux 環(huán)境自己編譯。如果是直接買的 SoC 或者開發(fā)套件,SoC 或者開發(fā)套件廠家會自己編譯好然后提供給客戶。

  • 通常采用交叉編譯。
  • 嵌入式 linux 編譯套件往往不是通用的!
  • linux 程序編譯工具鏈也可以編譯裸機(jī)程序,例如編譯裸機(jī) U-Boot、Linux Kernel。 但是通常不會使用 linux 程序編譯工具鏈來進(jìn)行純裸機(jī)開發(fā)。
  • 文件系統(tǒng): 其中主要就是根文件系統(tǒng)(RootFS),包括 Linux 啟動時(shí)所必須的目錄和關(guān)鍵性的文件,例如,Linux 啟動時(shí)都需要有 init 目錄下的相關(guān)文件。Linux 啟動時(shí),第一個(gè)必須掛載的是根文件系統(tǒng),若系統(tǒng)不能從指定設(shè)備上掛載根文件系統(tǒng),則系統(tǒng)會出錯(cuò)而退出啟動。成功之后可以自動或手動掛載其他的文件系統(tǒng)。

    根文件系統(tǒng)是第一個(gè)需要使用我們自己的編譯套件來編譯的程序。

  • 用戶 APP: 這個(gè)就是我們的嵌入式 Linux 中運(yùn)行的應(yīng)用程序了。肯定是需要使用我們自己制作的 linux 程序編譯工具鏈來產(chǎn)生。

??以上就是完整的嵌入式 Linux 環(huán)境各個(gè)部分的基本情況。從搭建嵌入式 Linux 環(huán)境的角度來說,我們需要自己編譯 BootLoader、Linux Kernel、文件系統(tǒng)、linux 程序編譯工具鏈 這四大部分;從使用者角度來說,通常會直接購買以上完整的嵌入式環(huán)境,然后在以上環(huán)境上開發(fā)用戶 APP,基本不會涉及以上四大部分的修改(二次開發(fā)除外)。

??在上面我們說的嵌入式環(huán)境四大部分種,最麻煩的應(yīng)該就是構(gòu)建自己的 linux 程序編譯工具鏈了。

CPU 體系架構(gòu)

??當(dāng)前全球公認(rèn)為主流的 CPU 體系架構(gòu)有 x86、PowerPC、ARM、RISC-V 和 MIPS 等。早年, x86 和 PowerPC 專注于桌面計(jì)算機(jī)、服務(wù)器等領(lǐng)域,ARM、RISC-V 和 MIPS 則在嵌入式領(lǐng)域發(fā)力。如今,x86、PowerPC 也布局了嵌入式領(lǐng)域,ARM、RISC-V 和 MIPS 也開始布局桌面計(jì)算機(jī)和服務(wù)器。

我對于這些指令集沒有深入研究,以下僅作為擴(kuò)展知識了解一下!

x86

??x86 是一個(gè)復(fù)雜指令集計(jì)算機(jī)(CISC)指令集體系結(jié)構(gòu)家族,最初是由 Intel 基于 Intel 8086 微處理器及其 8088 變體開發(fā)的。該名字就源自于 Intel 的 80x86 系列處理器。

??英特爾 8086 微處理器中的 x86 是16 位的,1985 年,英特爾發(fā)布了 32 位 80386。現(xiàn)在,我們通常使用 i386 表示 32 位 x86 架構(gòu)(有時(shí)候也直接使用 x86 表示)。 在 1999 年至 2003 年,AMD 將這種 32 位架構(gòu)擴(kuò)展到 64 位,并在早期文檔中將其稱為 x86-64,后來稱為 AMD64。英特爾很快以 IA-32e 的名義采用了 AMD 的架構(gòu)擴(kuò)展,后來使用 EM64T 的名稱,最后使用 Intel64。現(xiàn)在,我們?nèi)匀皇褂?x86-64 或 AMD64 來表示 64 位的 x86 架構(gòu)(有時(shí)候也直接使用 x64 表示)。

PowerPC

??PowerPC(Performance Optimization With Enhanced RISC – Performance Computing,有時(shí)簡稱稱 PPC)是 1991 年 Apple-IBM-Motorola聯(lián)盟( AIM)基于早期的 IBM POWER 架構(gòu)創(chuàng)建的精簡指令集計(jì)算機(jī)(RISC)指令集架構(gòu)(ISA)。從 2006 年開始被命名為 Power ISA(PowerPC ISA + PowerPC Book E),而 PowerPC 則作為某些 PowerPC 架構(gòu)的處理器的商標(biāo)而存在。基本發(fā)展過程:POWER ? PowerPC ? Power ISA。

ARM

??ARM 架構(gòu)是由 ARM 公司推出的基于精簡指令集計(jì)算機(jī)(RISC)指令集架構(gòu)(ISA)。ARM 架構(gòu)版本從 ARMv3 到 ARMv7 支持 32 位空間和 32 位算數(shù)運(yùn)算,大部分架構(gòu)的指令為定長 32 位(Thumb 指令集支持變長的指令集,提供對 32 位和 16 位指令集的支持),而 2011 年發(fā)布的 ARMv8-A 架構(gòu)添加了對 64 位空間和 64 位算術(shù)運(yùn)算的支持,同時(shí)也更新了 32 位定長指令集。

??ARM 公司除了 ARM 指令集相關(guān)產(chǎn)品,也提供了一些列的開發(fā)軟件,例如 Keil、DS-5 等。

RISC-V

??RISC-V 是一個(gè)基于精簡指令集(RISC)原則的開源的指令集架構(gòu)(ISA),其中的 V 表示第 5 代。RISC-V 于 2010 年誕生于美國加州大學(xué)伯克利分校并行計(jì)算實(shí)驗(yàn)室(Parallel Computing Laboratory) 的 David A. Patterson 教授指導(dǎo)的團(tuán)隊(duì)。

??目前,于 2015 年成立的 RISC-V 基金會(現(xiàn)在被稱為 RISC-V International)擁有,維護(hù)和發(fā)布與 RISC-V 定義相關(guān)的知識產(chǎn)權(quán)。RISC-V 官方還提供了一系列的工具,例如 RISC-V GNU Toolchain 等。指令集手冊,軟件工具等基本都托管在 Github 上。

MIPS

??MIPS(Microprocessor without Interlocked Pipeline Stages)是由美國 MIPS 計(jì)算機(jī)系統(tǒng)公司開發(fā)的一種采取精簡指令集(RISC)的指令集架構(gòu)(ISA)。早期的 MIPS 架構(gòu)只有 32 位的版本,隨后才開發(fā) 64 位的版本。在 MIPS V 之后分為了 MIPS32 和 MIPS64。

2021 年 3 月,MIPS 宣布 MIPS 架構(gòu)的開發(fā)已經(jīng)結(jié)束,因?yàn)樵摴菊谙?RISC-V 過渡。

(交叉)編譯工具鏈

??軟件程序的編譯過程由一系列的步驟完成,每一個(gè)步驟都有一個(gè)對應(yīng)的工具。這些工具緊密地工作在一起,前一個(gè)工具的輸出是后一個(gè)工具的輸入,像一根鏈條一樣,我們稱這些工具為編譯工具鏈。

??在當(dāng)前平臺(例如 x86 架構(gòu)的 PC)下,直接編譯出來程序(或者庫文件),其可以直接在當(dāng)前的平臺運(yùn)行(或使用)。這個(gè)過程就叫做本地編譯,使用的編譯工具叫做本地編譯工具鏈(簡稱編譯工具鏈)。例如 PC 上的 VC、GCC、LLVM、TCC 等。

??在當(dāng)前平臺下(例如 x86 架構(gòu)的 PC)下,直接編譯出來程序(或者庫文件),其不可以直接在當(dāng)前的平臺運(yùn)行(或使用),必須放到目標(biāo)平臺上(例如 ARM)才可以運(yùn)行(或使用),這個(gè)過程就叫做交叉編譯,使用的編譯工具叫做交叉編譯工具鏈。例如PC 中的 armcc、iar、特定架構(gòu)的 GNU、特定架構(gòu)的 LLVM 等。

這里的平臺指的是 CPU 架構(gòu)或者操作系統(tǒng)

??交叉編譯工具鏈又可以根據(jù)是否支持 Linux 系統(tǒng)分為 裸機(jī)程序交叉編譯工具鏈Linux 程序交叉編譯工具鏈 這兩大類。我們上面的舉例中,armcc、iar 都屬于裸機(jī)交叉編譯工具鏈;而特定架構(gòu)的 GNU、特定架構(gòu)的 LLVM 則根據(jù)需要可以支持 Linux 系統(tǒng),也可以不支持 Linux 系統(tǒng),因此它既有裸機(jī)程序交叉編譯工具鏈,也有 Linux 程序交叉編譯工具鏈。

  • 這里說的裸機(jī)是相對于 Linux 系統(tǒng)來說的。裸機(jī)程序交叉編譯工具鏈可以用于編譯一些嵌入式實(shí)時(shí)操作系統(tǒng),例如 FreeRTOS、RT-Thread 等。
  • 由于 ARM 的絕對市場地位,導(dǎo)致了在網(wǎng)上搜索交叉編譯工具鏈,基本都和 ARM 有關(guān)系。其中一個(gè)明顯的例子就是交叉編譯器的命名。
  • GNU 交叉編譯工具鏈

    ??我們接觸最多交叉編譯工具鏈就是特定架構(gòu)的 GNU,例如 Arm GNU Toolchain 就分為僅支持裸機(jī)的 arm-none-eabi 和 支持 linux 系統(tǒng)的 arm-none-linux 這兩大類。特定架構(gòu)的 GNU 交采編譯工具鏈也是目前我們使用最多的交叉編譯工具鏈,網(wǎng)上所說的交叉編譯工具鏈基本就是指的 GCC。

    由于 ARM 的絕對市場地位,導(dǎo)致了在網(wǎng)上搜索交叉編譯工具鏈,基本都和 ARM 有關(guān)系。其他架構(gòu),例如 MIPS、RISC-V 也有 GCC 交叉編譯工具鏈,但是由于市場占有率低我們接觸較少,網(wǎng)上資料也非常少。

    ??在我們構(gòu)建自己的 GCC (交叉)編譯工具鏈的時(shí)候,編譯(交叉)編譯工具鏈?zhǔn)褂玫钠脚_、編譯出的(交叉)編譯工具鏈運(yùn)行的平臺、使用編譯出的(交叉)編譯工具鏈編譯出的程序運(yùn)行的平臺三者可以完全不同。其中關(guān)鍵的一步是設(shè)置 configure 的參數(shù),該命令有三個(gè)參數(shù) --build、--host、--target 非常重要,下圖是 Windows 上的 MinGW 編譯器配置信息:

    • --build:這個(gè)參數(shù)指出了編譯(交叉)編譯工具鏈?zhǔn)褂玫钠脚_。如果我們不顯示指定這個(gè)參數(shù)的值,那么這個(gè)參數(shù)的值就會由 config.guess 自動識別。
    • --host:這個(gè)參數(shù)指出了編譯出的(交叉)編譯工具鏈運(yùn)行的平臺。這個(gè)參數(shù)的值一般就等于 --build 的值。
    • --target:這個(gè)參數(shù)指出了使用編譯出的(交叉)編譯工具鏈編譯出的程序運(yùn)行的平臺。這個(gè)選項(xiàng)只有在建立交叉編譯環(huán)境的時(shí)候用到,正常編譯和交叉編譯都不會用到。

    ??本地編譯工具鏈一般就是指的 --build = --host = --target 的情況,交叉編譯工具鏈一般是--build = --host ≠ --target 的情況。基本很少出現(xiàn)--build ≠ --host 的情況。

    命名規(guī)則

    ??一般來說,交叉編譯工具鏈的命名規(guī)則是:arch [-vendor] [-os] [-(gnu)abi]-*。但是,關(guān)于這個(gè)規(guī)則,我并沒有找到在哪份官方資料上有介紹,實(shí)際有些交叉編譯工具鏈也確實(shí)不符合上面的命名規(guī)則。如果有誰在官方資料上見到過此規(guī)則的詳細(xì)描述,一定要私信告訴我。

    • arch: 體系架構(gòu),如 ARM、MIPS、RISC-V
    • vendor: 工具鏈提供商,沒有 vendor 時(shí),用 none 代替。
    • os: 目標(biāo)操作系統(tǒng),沒有 os 支持時(shí),也用 none 代替,表示裸機(jī)。如果同時(shí)沒有 vendor 和 os 支持,則只用一個(gè) none 代替。例如 arm-none-eabi 中的 none 表示既沒有 vendor 也沒有 os 支持。
      • none
        • C 庫通常是 newlib
        • 提供不需要操作系統(tǒng)的 C 庫服務(wù)
        • 允許為特定硬件目標(biāo)提供基本系統(tǒng)調(diào)用
        • 可以用來構(gòu)建 Bootloader 或 Linux Kernel,不能構(gòu)建 Linux 用戶空間代碼
      • linux
        • 用于 Linux 操作系統(tǒng)的開發(fā)
        • linux 特有的 C 庫的選擇:glibc、uClibc-ng、musl
        • 支持 Linux 系統(tǒng)調(diào)用
        • 可以用來構(gòu)建 Linux 用戶空間代碼,但也可以構(gòu)建裸機(jī)代碼,如 Bootloader 或 Linux Kernel
    • abi: 應(yīng)用二進(jìn)制接口(Application Binary Interface)
      • gnu: 這個(gè)其實(shí)是早期 AArch32 架構(gòu)使用的名字,后來該名字為 gnueabi
      • gnueabi: 其實(shí)就是嵌入式應(yīng)用二進(jìn)制接口(Embedded Application Binary Interface,EABI)
      • elf: 這個(gè)通常用在 64 位裸機(jī)架構(gòu)的編譯工具鏈中

    ??由于 ARM 的絕對市場地位,導(dǎo)致了在網(wǎng)上搜索交叉編譯工具鏈,基本都和 ARM 有關(guān)系。因此,這里的命名規(guī)則更多的是指 Arm GNU Toolchain 的命名。

    組成部分

    ??GUN 交叉編譯工具鏈中有三個(gè)核心組件:Binutils、GCC、C library,如果需要支持 Linux,則還有個(gè) Linux kernel headers。在源代碼組織上他們是相互獨(dú)立的,需要單獨(dú)進(jìn)行交叉編譯。

    • Binutils:包括一些二進(jìn)文件相關(guān)的工具
      • 主要工具
        • ld 鏈接器
        • as 匯編器
      • 調(diào)試/分析工具和其他工具
        • addr2line、ar、c++filt、gold、gprof、nm、objcopy、objdump、ranlib、readelf、size、strings、strip
      • 需要針對每種 CPU 架構(gòu)進(jìn)行配置
      • 交叉編譯非常簡單,不需要特殊的依賴項(xiàng)。
    • gcc:GNU Compiler Collection
      • C、C++、Fortran、Go 等編譯器前端
      • 各種 CPU 架構(gòu)的編譯器后端
      • Provides:
        • 編譯器本身。例如 cc1 for C、cc1plus for C++

        • 編譯器調(diào)用程序。gcc、g++ 不但調(diào)用編譯器本身,也調(diào)用 binutils 中的 匯編器、連接器

          不要被 gcc 這個(gè)名字誤導(dǎo),它其實(shí)是個(gè) wrapper,會根據(jù)輸入文件調(diào)用一系列其他程序。國外資料中被稱為 compiler driver,國內(nèi)有些資料稱為 引導(dǎo)器。

        • 目標(biāo)庫:libgcc(gcc 運(yùn)行時(shí))、libstdc ++(c ++ 庫)、libgfortran(fortran運(yùn)行時(shí))

        • 標(biāo)準(zhǔn) c++ 庫的頭文件

      • 構(gòu)建 gcc 比構(gòu)建 binutils 要復(fù)雜的多
    • Linux Kernel headers:構(gòu)建需要支持 Linux 系統(tǒng)時(shí)必須提供。這些頭文件定義了用戶空間與內(nèi)核之間的接口(系統(tǒng)調(diào)用、數(shù)據(jù)結(jié)構(gòu)等)。
      • 為了構(gòu)建一個(gè) C 庫,需要 Linux 內(nèi)核頭文件中系統(tǒng)調(diào)用號的定義、各種結(jié)構(gòu)類型和定義。
      • 在內(nèi)核中,頭文件被分開:
        • 用戶空間可見的頭文件,存儲在 uapi 目錄中:include/uapi/、arch/<ARCH>/include/uapi/asm
        • 內(nèi)部的內(nèi)核頭文件
      • 在安裝過程中需要使用
        • 安裝包括一個(gè)清理過程,用于從頭文件中刪除特定于內(nèi)核的結(jié)構(gòu)體
        • 從 Linux 4.8 開始,安裝 756 個(gè)頭文件
        • 內(nèi)核到用戶空間 ABI 通常是向后兼容的。Kernel headers 的版本必須等于或者小于目標(biāo) Linux 的版本
    • C library
      • 提供 POSIX 標(biāo)準(zhǔn)函數(shù)的實(shí)現(xiàn),以及其他幾個(gè)標(biāo)準(zhǔn)和擴(kuò)展

      • 基于 Linux 系統(tǒng)調(diào)用

      • 幾個(gè)可用的實(shí)現(xiàn)

        • glibc:The GNU C Library 是 Linux C 庫的事實(shí)標(biāo)準(zhǔn),我們常見的 Linux 發(fā)行版中都使用它。支持眾多的架構(gòu)和操作系統(tǒng),但是不支持沒有 MMU 的平臺,不支持靜態(tài)鏈接。早些年由于硬件限制及 glibc 本身太大基本不能直接用于嵌入式,如今貌似也可以了。

        • uClibc-ng:以前叫 uClibc,始于 2000 年,支持非常靈活的配置。支持架構(gòu)很多(包括一些 glibc 不支持的),但是僅支持 Linux 操作系統(tǒng)。支持多種沒有 MMU 的架構(gòu),如 ARM noMMU、Blackfin 等,支持靜態(tài)鏈接。

          STM32F MCU 沒有 MMU,其嵌入式 Linux 環(huán)境中編譯工具鏈就是用的它。

        • musl:始于 2011 年,開發(fā)非常積極,最近添加了對于 noMMU 的支持。它非常小,尤其是在靜態(tài)鏈接時(shí)。兼容性好,并且嚴(yán)格遵循 C 標(biāo)準(zhǔn)。

        • bionic:安卓系統(tǒng)使用

        • 其他一些特殊用途的:newlib(用于裸機(jī))、dietlibc、klibc

        musl 的作者對于 Linux 常用的這幾個(gè)庫做了一個(gè)對比,以下是對比情況圖:

      • 在編譯和安裝之后,提供了:

        • 動態(tài)鏈接器 ld.so
        • C 庫本身 libc.so,及其配套庫:libm、librt、libpthread、libutil、libnsl、libresolv、libcrypt
        • C 庫的頭文件:stdio.h、string.h 等等。

    ??GUN 將編譯器和 C 庫分開放在兩個(gè)軟件包里,好處是比較靈活,方便在工具鏈中可以選擇不同的 C 庫。但是,也帶來了編譯器和 C 庫的循環(huán)依賴問題:編譯 C 庫需要 C 編譯器,但是 C 編譯器又依賴 C 庫。理論上編譯器是不應(yīng)該依賴 C 庫的,它應(yīng)該只負(fù)責(zé)將源代碼翻譯為匯編代碼即可,但實(shí)際上并非如此。

    ??C99 標(biāo)準(zhǔn)定義了兩種實(shí)現(xiàn):一種稱為 hosted 實(shí)現(xiàn),一種稱為 freestanding 實(shí)現(xiàn)。其中,hosted 實(shí)現(xiàn)支持完整的 C 標(biāo)準(zhǔn),包括語言標(biāo)準(zhǔn)和庫標(biāo)準(zhǔn),它用于編譯在有宿主系統(tǒng)的環(huán)境下運(yùn)行的程序。freestanding 實(shí)現(xiàn)僅支持完整的語言標(biāo)準(zhǔn),對于庫標(biāo)準(zhǔn)它只要求支持部分庫標(biāo)準(zhǔn)。

    構(gòu)建(交叉)編譯工具鏈分為好多步,而且單是編譯 gcc 就要多次。

    ABI、EABI、OABI、GNU EABI

    ??應(yīng)用二進(jìn)制接口(Application Binary Interface,ABI)定義了一個(gè)系統(tǒng)中函數(shù)的參數(shù)如何傳送、如何接受函數(shù)返回值、數(shù)據(jù)類型的大小、布局和對齊、應(yīng)用程序應(yīng)如何對操作系統(tǒng)進(jìn)行系統(tǒng)調(diào)用、對象文件,程序庫等的二進(jìn)制格式等細(xì)節(jié)。ABI 允許編譯好的目標(biāo)代碼在使用兼容 ABI 的系統(tǒng)中無需改動就能運(yùn)行。

    ??嵌入式應(yīng)用程序二進(jìn)制接口 (Embedded Application Binary Interface,EABI) 指定嵌入式軟件程序的文件格式、數(shù)據(jù)類型、寄存器用法、堆棧幀組織和函數(shù)參數(shù)傳遞的標(biāo)準(zhǔn)約定,以便與嵌入式操作系統(tǒng)一起使用。廣泛使用的 EABI 有 PowerPC、Arm EABI、MIPS EABI。

    ??在很多地方有 GNU EABI 的這樣的叫法,例如,在 ARM 提供的 GNU 工具鏈中有 arm-none-linux-gnueabi 的命名。這里的 GNU EABI 其實(shí)就是 EABI。之所以叫這個(gè)名字是因?yàn)?GNU 一貫作風(fēng)是要求帶有 GNU 字樣。例如 GNU 要求把 Linux 稱為 GNU/Linux,但是實(shí)際情況大家都直接叫 Linux。

    ??OABI (其中的 O,理解為 Old 或 Obsolete)是 ARM 系列的最開始使用的應(yīng)用程序二進(jìn)制接口。OABI 假設(shè) CPU 擁有一個(gè)浮點(diǎn)單元處理器(實(shí)際很多沒有),導(dǎo)致編譯器生成的程序總是嘗試與浮點(diǎn)單元通信以進(jìn)行浮點(diǎn)運(yùn)算,由于沒有浮點(diǎn)運(yùn)算單元,內(nèi)核出現(xiàn)異常,異常機(jī)制會自動再使用軟件模擬浮點(diǎn)進(jìn)行計(jì)算,這導(dǎo)致了一些額外開銷。

    ??EABI 被創(chuàng)造出來以解決 OABI 的這個(gè)問題。但是,EABI 沒有簡單的方法來讓二進(jìn)制發(fā)行版同時(shí)支持軟浮點(diǎn)和硬浮點(diǎn),因此,ARM 的交叉編譯器分為 ARMEL 和 ARMHF 這兩種。因此,有個(gè) arm-none-linux-gnueabihf 表示支持硬浮點(diǎn)。

    嵌入式系統(tǒng)啟動

    ??宏觀上來看,系統(tǒng)的啟動分為 Boot 執(zhí)行階段和系統(tǒng)執(zhí)行階段,Boot 階段為系統(tǒng)運(yùn)行準(zhǔn)備必要條件,然后將 CPU 的控制權(quán)交給系統(tǒng),系統(tǒng)接管 CPU ,然后做相應(yīng)初始化后開始運(yùn)行;從微觀來看,系統(tǒng)啟動從上電開始,經(jīng)過了很多階段。

    ??芯片一上電就會根據(jù)設(shè)定的啟動方式,從固定的位置開始讀取代碼并執(zhí)行。這個(gè)固定的位置根據(jù)芯片而定,例如,STM32 的 MCU 支持 RAM、Flash、BootLoader 三個(gè)位置啟動。下圖是一個(gè)典型的嵌入式 Linux 系統(tǒng)啟動流程:

    嵌入式系統(tǒng)構(gòu)建工具

    ??構(gòu)建一整套嵌入式 Linux 環(huán)境是一件很龐大的事情,我們可以選擇自己動手,根據(jù)上面嵌入式 Linux 環(huán)境,一點(diǎn)一點(diǎn)來構(gòu)建其中的各個(gè)部分。實(shí)際情況是,為了簡化搭建工作量,誕生了一些嵌入式系統(tǒng)構(gòu)建工具。這些工具通過各種自動化手段,只需要我們輸入基本命令,就可以自動構(gòu)建出以上說的完整嵌入式環(huán)境。

    Buildroot

    ??Buildroot 是 Linux 平臺上的一個(gè)用于構(gòu)建嵌入式 Linux 系統(tǒng)的框架。整個(gè) Buildroot 是由 Makefile 腳本和 Kconfig 配置文件構(gòu)成的。使用它可以和編譯 Linux 內(nèi)核一樣,通過使用 Kbuild/Kconfig 系統(tǒng)編譯出一個(gè)完整的可以直接燒寫到機(jī)器上運(yùn)行的 Linux 系統(tǒng)軟件(包含boot、kernel、rootfs 以及 rootfs 中的各種庫和應(yīng)用程序、交叉編譯工具鏈)。

    ??Buildroot 支持的架構(gòu)有 ARC、ARM、AArch64、Black?n、csky、m68k,Microblaze、MIPS(64)、NIOS II、OpenRisc、PowerPC(64)、SuperH、SPARC、x86、x86 64、Xtensa.

    Yocto

    ??Yocto 全稱是 Yocto Project(官方簡稱 YP) 是 Linux 基金會在 2010 年推出的一個(gè)開源的協(xié)作項(xiàng)目。提供模板、工具和方法以創(chuàng)建定制的 Linux 系統(tǒng)和嵌入式產(chǎn)品,而無需關(guān)心硬件體系。從歷史上看,該項(xiàng)目是從 OpenEmbedded 項(xiàng)目發(fā)展而來的。

    ??Yocto Project 這個(gè)名字(或者我們常簡稱的 Yocto)是指的這個(gè)項(xiàng)目本身或者一個(gè)組織,Poky 官方定義為 Yocto Project 的參考發(fā)行版,它才是我們真正使用的構(gòu)建系統(tǒng)工具(更確切的說這就是一個(gè)可以構(gòu)建出嵌入式 Linux 的 DEMO)。實(shí)際情況中,我們一般會對 Poky 進(jìn)行自定義(刪除 meta-poky 等,添加自己的 meta-xxx)來實(shí)現(xiàn)自己的嵌入式 Linux 系統(tǒng)構(gòu)建工具包。如下是我們在用的一個(gè)目錄結(jié)構(gòu):

    ??這里還有個(gè)問題,Yocto Project 對于 OpenEmbedded 的引用是打散重新組合的(OpenEmbedded 本身就是有多個(gè)部分組成),并不是完整的把 OpenEmbedded 拿過來。從 Yocto Project 的角度來看,Yocto Project 的結(jié)構(gòu)就是如下所示:

    OpenEmbedded

    ??OpenEmbedded (簡稱 OE)是一個(gè)構(gòu)建自動化框架和交叉編譯環(huán)境,用于為嵌入式設(shè)備創(chuàng)建 Linux 發(fā)行版。OpenEmbedded 由成立于 2003 年的 OpenEmbedded 社區(qū)開發(fā),其誕生遠(yuǎn)早于 Yocto Project。2011 年 3 月,它與 Yocto Project 合作(實(shí)際就是合并了),并開始以 OpenEmbedded-Core 項(xiàng)目作為項(xiàng)目發(fā)展的名稱(簡稱 OE-Core),之前的稱為 OpenEmbedded-Classic(簡稱 OE-Classic 或 oe-dev),OpenEmbedded 這個(gè)名字就用來代指整個(gè) OpenEmbedded 項(xiàng)目。

    ??注意,在一些老文檔中,OpenEmbedded 這個(gè)名字有可能還是指的舊的 OpenEmbedded 。例如,OpenEmbedded 的原始代碼倉庫并沒有改名為 OpenEmbedded-Classic。OpenEmbedded 項(xiàng)目的代碼倉庫見 https://git.openembedded.org/。

    ??之所以更名是因?yàn)榕c Yocto Project 合并之后的開發(fā)團(tuán)隊(duì)對 OpenEmbedded 的整個(gè)結(jié)構(gòu)進(jìn)行了比價(jià)大改進(jìn)。 OpenEmbedded-Classic 的所有自動構(gòu)建的處方(Recipes)都放在一起,隨著發(fā)展越來越難以維護(hù);而在新的 OpenEmbedded-Core,其結(jié)構(gòu)由許多 layers 組成(OpenEmbedded 維護(hù)了一個(gè)可以與 OE-Core 一起使用的層列表),讓用戶可以更容易加入定制的自動構(gòu)建處方(Recipes)。OE-Classic 不再維護(hù),也基本沒有使用了!現(xiàn)在的 OpenEmbedded 也可以理解為基于 OE-Core 的一個(gè)實(shí)現(xiàn)(BitBake + OpenEmbedded-Core)+ 一組元數(shù)據(jù))。

    ??OpenEmbedded-Core 可以獨(dú)立使用,也被集成在 Angstrom、SHR、Yocto Project 等系統(tǒng)中來使用。實(shí)際情況是,很少見單獨(dú)使用 OE-Core 的情況,OpenEmbedded 基本就成了 Yocto Project 中的一部分(其他基本死的差不多了),其文檔等全部都引用 Yocto Project 中對應(yīng)文檔。

    PTXdist

    ??PTXdist 是一個(gè)固件鏡像構(gòu)建工具,是 Pengutronix 在 2001 年開發(fā)的一個(gè)構(gòu)建系統(tǒng)。采用了 Linux 內(nèi)核中的配置系統(tǒng) Kconfig 來選擇和配置每個(gè)包,規(guī)則集合則基于 GNU Make 和 Bash。

    OpenWRT

    ??OpenWRT 是一個(gè)針對嵌入式設(shè)備的 Linux 操作系統(tǒng)。OpenWrt 不是一個(gè)單一且不可更改的固件,而是提供了具有軟件包管理功能的完全可寫的文件系統(tǒng)。

    ??OpenWRT 是一個(gè)高度模塊化、高度自動化的嵌入式Linux系統(tǒng),擁有強(qiáng)大的網(wǎng)絡(luò)組件和擴(kuò)展性,常常被用于工控設(shè)備、電話、小型機(jī)器人、智能家居、路由器以及 VOIP 設(shè)備中。

    測試環(huán)境

    ??正好手里有一塊前幾年的 STM32F769I-EVAL 的評估板,后續(xù),我就以手里的 STM32F769I-EVAL 的評估板為載體,盡量不使用已有的嵌入式構(gòu)建工具,來一步一步搭建這個(gè)嵌入式 Linux 環(huán)境。如下圖所示的這個(gè):

    ??這塊評估板的功能應(yīng)該是非常全了,價(jià)格也是不便宜。ST 官網(wǎng)對于這塊評估板的介紹參見 Evaluation board with STM32F769NI MCU。

    ??熟悉 ST 的開發(fā)板的都知道,ST 的開發(fā)板主要有 ST 官方的 Nucleo 系列、Discovery Kits 系列、Evaluation 系列以及第三方開發(fā)板這些組成。其中,ST 自家開發(fā)板中 Evaluation 系列是功能最全的,也是價(jià)格最高的。第三方開發(fā)板差異就比加大了。

    ??嵌入式環(huán)境與我們熟悉的 PC 環(huán)境還是有很大區(qū)別的。尤其是對于部分芯片,它沒有 MMU,也就不能使用虛擬內(nèi)存相關(guān)的所有技術(shù)。也就意味著,嵌入式中的地址都是實(shí)際的物理地址。

    ??其次,嵌入式環(huán)境的另一個(gè)大特點(diǎn)就是資源非常緊張,這就導(dǎo)致了我們可能需要將最終的多部分的可執(zhí)行程序放到不同的地方。舉個(gè)例子,STM32 的 MCU 中,往往不能存放 Linux Kernel,我們需要將 Linux Kernel 放到一些外部存儲器中。

    ??對于 ARM 平臺,ARM 給出了兩個(gè)概念:加載域執(zhí)行域,加載域?qū)?yīng)加載地址,執(zhí)行域?qū)?yīng)了一個(gè)執(zhí)行地址。關(guān)于 ARM 的分散加載機(jī)制,可以參見博文 ARM 之十三 armlink(Keil) 分散加載機(jī)制詳解 及 分散加載文件的編寫 即可。

    ??進(jìn)一步具體到 STM32 芯片,我們的程序是放到內(nèi)部的 FLASH 上的,FLASH 就是加載域,FLASH 上的具體地址就是加載域地址。同時(shí),ST 芯片的設(shè)計(jì)可以從 FLASH 上執(zhí)行代碼(速度相對較慢),此時(shí)的加載域與執(zhí)行域是同一個(gè);還有一種更高效的方式是將代碼放到 RAM 中執(zhí)行(存放還是在 FLASH),此時(shí) RAM 就是執(zhí)行域,程序在 RAM 中的地址就是執(zhí)行域地址。

    搭建過程

    ??工欲善其事,必先利其器。第一步就是搭建 LINUX 系統(tǒng)開發(fā)環(huán)境,為此特地在筆記本上安裝了 Ubuntu,具體使用的桌面開發(fā)環(huán)境是 Ubuntu 20.04.3 LTS。至于為啥選擇 Linux 系統(tǒng),而不是直接使用 Windows 系統(tǒng)想必大家都清楚為啥。

    ??接下來準(zhǔn)備好一個(gè)目錄,后續(xù)所有的操作均在此目錄中進(jìn)行。我的操作是新建 /home/zcshou/STM32LINUX 這個(gè)目錄,用于存放整個(gè)要為 STM32 嵌入式 Linux 環(huán)境編譯的源代碼,后續(xù)都在這個(gè)目錄中進(jìn)行。如下圖所示:

    ??最開始我想按照上面說的嵌入式環(huán)境的各個(gè)部分來分別寫幾篇博文來完整介紹整個(gè)搭建過程,然而寫著寫著內(nèi)容越來越多,最終超過了 CSDN 編輯器的限制!最終決定把內(nèi)容拆分成多篇文章。具體搭建過程就是如下幾步:

  • 編譯 U-Boot。參見博文 U-Boot 之一 零基礎(chǔ)編譯 U-Boot 過程詳解 及 編譯后的使用說明
  • 編譯 Linux Kernel。參見博文 Linux 之九 零基礎(chǔ)編譯嵌入式 Linux Kernel 過程詳解 及 編譯后的使用說明
  • 編譯交叉編譯工具鏈。參見博文 Linux 之十 編譯自己的嵌入式 Linux 交叉編譯工具鏈
  • 編譯 RootFS。參見博文 Linux 之十一 編譯嵌入式 Linux 下的 RootFS
  • 參考

  • https://codeantenna.com/a/wf8KVWOhym
  • https://www.its404.com/article/qq_44034198/110872972
  • https://sourcery.sw.siemens.com/GNUToolchain/kbentry32
  • https://sourcery.sw.siemens.com/GNUToolchain/kbentry38
  • https://www.jianshu.com/p/a7c8d99162c5
  • https://blog.csdn.net/flagyan/article/details/6166107
  • https://elinux.org/images/1/15/Anatomy_of_Cross-Compilation_Toolchains.pdf
  • https://zhuanlan.zhihu.com/p/110402378
  • https://wiki-archive.linaro.org/WorkingGroups/ToolChain/FAQ#What_is_the_differences_between_.2BIBw-arm-none-eabi-.2BIB0_and_.2BIBw-arm-linux-gnueabihf.2BIB0.3F_Can_I_use_.2BIBw-arm-linux-gnueabihf.2BIB0_tool_chain_in_bare-metal_environment.3F_How_do_you_know_which_toolchain_binary_to_use_where.3F
  • https://zhuanlan.zhihu.com/p/110402378
  • https://docs.embeddedts.com/EABI_vs_OABI
  • http://www.etalabs.net/compare_libcs.html
  • 總結(jié)

    以上是生活随笔為你收集整理的Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。