日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

esp8266 SDK开发之编译流程

發(fā)布時(shí)間:2025/4/5 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 esp8266 SDK开发之编译流程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近剛完成自己8266的小項(xiàng)目,已經(jīng)發(fā)布在github上,有興趣的朋友可以看一下

github地址:esp-ujn

1. 通過(guò)MQTT協(xié)議與服務(wù)器交互

2. 內(nèi)置HTTP服務(wù)器,支持通過(guò)瀏覽器進(jìn)行參數(shù)配置

編譯流程分析


我們?cè)诰幾g8266代碼時(shí)可以使用項(xiàng)目中的gen_misc.sh(Windows下為gen_misc.bat)腳本,選擇合適的參數(shù)后就會(huì)在sdk/bin/文件夾中生成可燒錄的文件,如eagle.flash.bineagle.irom0text.bin。 但這樣存在的問(wèn)題是每次編譯時(shí)都需要選擇一遍編譯參數(shù),所以一般會(huì)使用make命令進(jìn)行編譯,如:

make COMPILE=gcc BOOT=none APP=0 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=4

這是因?yàn)?span style="margin:0px;padding:0px;">gen_misc.sh的作用僅僅是供用戶選擇編譯參數(shù),最終的編譯過(guò)程是通過(guò)make命令依據(jù)Makefile文件中定義的若干規(guī)則來(lái)進(jìn)行的。接下來(lái)通過(guò)如下幾個(gè)方面來(lái)探討整個(gè)編譯流程

  • Makefile的組織形式
  • 燒錄文件的生成過(guò)程
  • Makefile的執(zhí)行過(guò)程
  • 一、Makefile的組織形式

    SDK中Makefile文件以樹(shù)形結(jié)構(gòu)組織。總體上分為3類(lèi):主文件,項(xiàng)目配置文件,庫(kù)配置文件。

    |--sdk/ |----Makefile |----project/ |------Makefile |------user/ |--------Makefile |------json/ |--------Makefile

    如上圖所示

    • sdk/Makefile 主文件
    • sdk/project/Makefile 項(xiàng)目配置文件
    • sdk/project/json/Makefile?庫(kù)配置文件

    平常開(kāi)發(fā)過(guò)程中,一般我們只需要關(guān)注項(xiàng)目配置文件與庫(kù)配置文件即可。如有時(shí)為了程序的模塊化,需要將不同的功能模塊編譯成獨(dú)立的庫(kù)。這時(shí)需要修改項(xiàng)目配置文件,并創(chuàng)建對(duì)應(yīng)的庫(kù)配置文件。例如我們需要添加一個(gè)json庫(kù)。這時(shí)就需要:

  • sdk/project/下創(chuàng)建文件夾sdk/project/json/
  • sdl/project/user/Makefile拷貝到sdk/project/json/
  • 修改sdk/project/json/Makefile
  • 修改sdk/project/Makefile
  • 需要在兩個(gè)Makefile中做出的改動(dòng)如下:

    #sdk/project/json/Makefile GEN_LIBS = libjson.a #庫(kù)名#sdk/project/Makefile SUBDIRS = user \json #庫(kù)目錄 COMPONENTS_eagle.app.v6 = user/libuser.a \json/libjson.a #庫(kù)路徑

    二、燒錄文件的生成過(guò)程

    對(duì)于Non-FOTA模式,編譯完成后會(huì)在sdk/bin/目錄下生成eagle.flash.bineagle.irom0text.bin。顯然這兩個(gè)文件并不是編譯器的直接產(chǎn)物,一般來(lái)說(shuō)編譯器會(huì)通過(guò)我們的代碼生成一個(gè)可執(zhí)行程序。那么這兩個(gè)文件是從何而來(lái)的呢?實(shí)際上這兩個(gè)文件是編譯后生成的可執(zhí)行文件的一部分。可執(zhí)行文件被拆解成了多個(gè)部分,然后拼湊出了這兩個(gè)文件供我們燒錄。我們的代碼經(jīng)過(guò)編譯后會(huì)生成一個(gè)elf文件,它的路徑在sdk/project/.output/eagle/debug/image/eagle.app.v6.out。這個(gè)一個(gè)標(biāo)準(zhǔn)的elf文件,可以使用readelf命令查看它的一些信息。

    #readelf -h ELF 頭:Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 類(lèi)別: ELF32數(shù)據(jù): 2 補(bǔ)碼,小端序 (little endian)版本: 1 (current)OS/ABI: UNIX - System VABI 版本: 0類(lèi)型: EXEC (可執(zhí)行文件)系統(tǒng)架構(gòu): Tensilica Xtensa Processor版本: 0x1入口點(diǎn)地址: 0x40100004程序頭起點(diǎn): 52 (bytes into file)Start of section headers: 549292 (bytes into file)標(biāo)志: 0x300本頭的大小: 52 (字節(jié))程序頭大小: 32 (字節(jié))Number of program headers: 5節(jié)頭大小: 40 (字節(jié))節(jié)頭數(shù)量: 19字符串表索引節(jié)頭: 16#readelf -S 共有 19 個(gè)節(jié)頭,從偏移量 0x861ac 開(kāi)始: 節(jié)頭: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al[ 0] NULL 00000000 000000 000000 00 0 0 0[ 1] .data PROGBITS 3ffe8000 0000e0 000804 00 WA 0 0 16[ 2] .rodata PROGBITS 3ffe8810 0008f0 0015d0 00 A 0 0 16[ 3] .bss NOBITS 3ffe9de0 001ec0 006f18 00 WA 0 0 16[ 4] .irom0.text PROGBITS 40210000 0092c0 038b44 00 AX 0 0 16[ 5] .text PROGBITS 40100000 001ec0 0073fc 00 AX 0 0 4[ 6] .xtensa.info NOTE 00000000 041e04 000038 00 0 0 1[ 7] .comment PROGBITS 00000000 041e3c 001bbd 00 0 0 1[ 8] .debug_frame PROGBITS 00000000 0439fc 00211c 00 0 0 4[ 9] .debug_info PROGBITS 00000000 045b18 014bec 00 0 0 1[10] .debug_abbrev PROGBITS 00000000 05a704 003f8a 00 0 0 1

    將可執(zhí)行文件eagle.app.v6.out轉(zhuǎn)變?yōu)榭蔁浳募倪^(guò)程定義在sdk/Makefile,也就是在主文件中。大體流程如下:

    #將.text、.data、.rodata和.irom0.text節(jié)的數(shù)據(jù)轉(zhuǎn)存到文件 objcopy --only-section .text -O binary eagle.app.v6.out eagle.app.v6.text.bin objcopy --only-section .data -O binary eagle.app.v6.out eagle.app.v6.data.bin objcopy --only-section .rodata -O binary eagle.app.v6.out eagle.app.v6.rodata.bin objcopy --only-section .irom0.text -O binary eagle.app.v6.out eagle.app.v6.irom0text.bin #通過(guò)eagle.app.v6.text.bin、eagle.app.v6.data.bin和eagle.app.v6.rodata.bin生成eagle.app.flash.bin python sdk/tools/gen_appbin.py eagle.app.v6.text.bin eagle.app.v6.data.bin eagle.app.v6.rodata.bin #將最后生成的可燒錄文件放到sdk/bin/目錄下 mv eagle.app.flash.bin sdk/bin/eagle.flash.bin mv eagle.app.v6.irom0text.bin sdk/bin/eagle.irom0text.bin

    通過(guò)上邊readelf -S獲取到的節(jié)區(qū)表信息可以看到,實(shí)際在內(nèi)存中出現(xiàn)的節(jié)只有.text.data.bss.rodata.irom0.text

    .text + .data + .rodata? =>?eagle.flash.bin

    .irom0.text?=> eagle.irom0text.bin

    通過(guò)比較這幾個(gè)節(jié)的大小與燒錄文件大小的關(guān)系可以得到相同的結(jié)果(eagle.flash.bin文件中除了包含程序節(jié)數(shù)據(jù),還有少量的配置數(shù)據(jù))。.bss節(jié)雖然在內(nèi)存中出現(xiàn)但是在程序初始化時(shí)會(huì)被整個(gè)清零,所以不必出現(xiàn)在燒錄文件中。這幾個(gè)節(jié)包含的數(shù)據(jù)內(nèi)容如下:

    節(jié)名作用
    .text存放代碼
    .data存放已初始化的全局變量
    .bss存放未初始化的全局變量
    .rodata存放只讀數(shù)據(jù)
    .irom0.text存放標(biāo)注有ICACHE_FLASH_ATTR的代碼或ICACHE_RODATA_ATTR的變量

    三、Makefile的執(zhí)行過(guò)程

    在前邊已經(jīng)提到,我們寫(xiě)的代碼最終會(huì)編譯為一個(gè)elf格式的可執(zhí)行文件(eagle.app.v6.out),接下我們通過(guò)具體Makefile文件中的代碼對(duì)整個(gè)編譯的執(zhí)行過(guò)程進(jìn)行分析。之前講到sdk/Makefile為主文件,也就是所有編譯時(shí)用到的邏輯都在其中定義。我們整個(gè)的編譯流程中需要按順序產(chǎn)生如下幾類(lèi)目標(biāo):二進(jìn)制目標(biāo)文件、庫(kù)文件、elf文件、燒錄文件。那么如何通過(guò)一個(gè)主Makefile來(lái)完成這些工作呢,這里需要先看一下其余兩類(lèi)起配置作用的Makefile。這兩類(lèi)Makefile的最后都會(huì)有如下代碼:

    PDIR := ../$(PDIR) sinclude $(PDIR)Makefile

    它的作用是包含自己父文件夾中的Makefile文件,那么最后主Makefile文件中的內(nèi)容會(huì)被包含到庫(kù)配置文件與項(xiàng)目配置文件中。在項(xiàng)目配置文件中,它的作用是產(chǎn)生elf可執(zhí)行文件與燒錄文件,在庫(kù)配置文件中,它的作用是產(chǎn)生靜態(tài)鏈接庫(kù)。主Makefile中,最主要的顯式規(guī)則如下,通過(guò)這兩條規(guī)則產(chǎn)生了所有我們需要的文件。

    ...
    314
    all: .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)
    ...
    324 .subdirs: 325 @set -e; $(foreach d, $(SUBDIRS), $(MAKE) -C $(d);)

    這兩條規(guī)則的目標(biāo)都是偽目標(biāo),并不會(huì)產(chǎn)生任何文件,我們所需要的所有文件都是目標(biāo)all的依賴文件。

    $(OBJS)二進(jìn)制目標(biāo)文件
    $(OLIBS)靜態(tài)鏈接庫(kù)
    $(OIMAGES)elf可執(zhí)行文件
    $(OBINS)燒錄文件
    $(SPECIAL_MKTARGETS)一直為空

    第一個(gè)依賴文件.subdirs是一個(gè)偽目標(biāo),也就是每次編譯時(shí)都會(huì)先執(zhí)行.subdirs中定義的操作,也就是遍歷所有含Makefile文件的子文件夾,執(zhí)行make命令。通過(guò)這種方式產(chǎn)生的結(jié)果就是make工具的當(dāng)前路徑發(fā)生了改變。拿上邊列出的項(xiàng)目結(jié)構(gòu)為例,我們一次編譯過(guò)程可分為

  • 我們?cè)?span style="margin:0px;padding:0px;">sdk/project/文件夾下執(zhí)行make命令編譯源碼
  • sdk/project/Makefile包含sdk/Makefile的內(nèi)容
  • 構(gòu)建目標(biāo)all
  • 依賴文件.subdirs不存在,進(jìn)行構(gòu)建
  • 遍歷sdk/project/下所有含Makefile文件的子文件并執(zhí)行make命令
  • 這時(shí)如果執(zhí)行了sdk/project/json/Makefile,那么此時(shí)make工具的當(dāng)前路徑變?yōu)榱?span style="margin:0px;padding:0px;">sdk/project/json/。此時(shí)sdk/project/json/Makefile對(duì)上層Makefile進(jìn)行包含后再次構(gòu)建目標(biāo)all。一般來(lái)說(shuō)sdk/project/json/中不會(huì)再有包含Makefile的子文件夾,那么此時(shí)目標(biāo)all的第一個(gè)依賴項(xiàng).subdirs會(huì)立刻返回,然后再對(duì)其余的依賴項(xiàng)進(jìn)行構(gòu)建。

    還有一點(diǎn)需要說(shuō)明的是目標(biāo)all的依賴項(xiàng)并不是全都有值的,比如$(SPECIAL_MKTARGETS)的值就一直為空,表示不存在此依賴項(xiàng)。繼續(xù)拿上邊的項(xiàng)目結(jié)構(gòu)舉例:

    make當(dāng)前路徑$(OBJS)$(OLIBS)$(OIMAGES)$(OBINS)
    sdk/project/eagle.app.v6.outeagle.app.v6.bin
    sdk/project/json/json.olibjson.a

    根據(jù)make當(dāng)前路徑的不同,目標(biāo)all有不同的依賴項(xiàng),然后再根據(jù)主Makefile中定義隱式規(guī)則對(duì)依賴項(xiàng)進(jìn)行構(gòu)建,即完成了整個(gè)項(xiàng)目的構(gòu)建過(guò)程。

    ?


    有的朋友可能對(duì)Makefile的語(yǔ)法不熟悉,這里推薦一個(gè)網(wǎng)站

    https://www.gnu.org/s/make/manual/make.html

    官方的教程很詳細(xì)

    總結(jié)

    以上是生活随笔為你收集整理的esp8266 SDK开发之编译流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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