linux编译esp8266程序,esp8266 SDK开发之编译流程

最近刚完成自己8266的小项目,已经发布在github上,有兴趣的朋友可以看一下

github地址:esp-ujn

1. 通过MQTT协议与服务器交互

2. 内置HTTP服务器,支持通过浏览器进行参数配置

编译流程分析

我们在编译8266代码时可以使用项目中的gen_misc.sh(Windows下为gen_misc.bat)脚本,选择合适的参数后就会在sdk/bin/文件夹中生成可烧录的文件,如eagle.flash.bin,eagle.irom0text.bin。 但这样存在的问题是每次编译时都需要选择一遍编译参数,所以一般会使用make命令进行编译,如:

make COMPILE=gcc BOOT=none APP= SPI_SPEED= SPI_MODE=QIO SPI_SIZE_MAP=

这是因为gen_misc.sh的作用仅仅是供用户选择编译参数,最终的编译过程是通过make命令依据Makefile文件中定义的若干规则来进行的。接下来通过如下几个方面来探讨整个编译流程

一、Makefile的组织形式

SDK中Makefile文件以树形结构组织。总体上分为3类:主文件,项目配置文件,库配置文件。

|--sdk/

|----Makefile

|----project/

|------Makefile

|------user/

|--------Makefile

|------json/

|--------Makefile

如上图所示

sdk/Makefile 主文件

sdk/project/Makefile 项目配置文件

sdk/project/json/Makefile 库配置文件

平常开发过程中,一般我们只需要关注项目配置文件与库配置文件即可。如有时为了程序的模块化,需要将不同的功能模块编译成独立的库。这时需要修改项目配置文件,并创建对应的库配置文件。例如我们需要添加一个json库。这时就需要:

在sdk/project/下创建文件夹sdk/project/json/

将sdl/project/user/Makefile拷贝到sdk/project/json/下

修改sdk/project/json/Makefile

修改sdk/project/Makefile

需要在两个Makefile中做出的改动如下:

#sdk/project/json/Makefile

GEN_LIBS = libjson.a #库名

#sdk/project/Makefile

SUBDIRS = user \

json #库目录

COMPONENTS_eagle.app.v6 = user/libuser.a \

json/libjson.a #库路径

二、烧录文件的生成过程

对于Non-FOTA模式,编译完成后会在sdk/bin/目录下生成eagle.flash.bin与eagle.irom0text.bin。显然这两个文件并不是编译器的直接产物,一般来说编译器会通过我们的代码生成一个可执行程序。那么这两个文件是从何而来的呢?实际上这两个文件是编译后生成的可执行文件的一部分。可执行文件被拆解成了多个部分,然后拼凑出了这两个文件供我们烧录。我们的代码经过编译后会生成一个elf文件,它的路径在sdk/project/.output/eagle/debug/image/eagle.app.v6.out。这个一个标准的elf文件,可以使用readelf命令查看它的一些信息。

#readelf -h

ELF 头:

Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

类别: ELF32

数据: 2 补码,小端序 (little endian)

版本: 1 (current)

OS/ABI: UNIX - System V

ABI 版本: 0

类型: EXEC (可执行文件)

系统架构: Tensilica Xtensa Processor

版本: 0x1

入口点地址: 0x40100004

程序头起点: 52 (bytes into file)

Start of section headers: 549292 (bytes into file)

标志: 0x300

本头的大小: 52 (字节)

程序头大小: 32 (字节)

Number of program headers: 5

节头大小: 40 (字节)

节头数量: 19

字符串表索引节头: 16

#readelf -S

共有 个节头,从偏移量 0x861ac 开始:

节头:

[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

将可执行文件eagle.app.v6.out转变为可烧录文件的过程定义在sdk/Makefile,也就是在主文件中。大体流程如下:

#将.text、.data、.rodata和.irom0.text节的数据转存到文件

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

#通过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

通过上边readelf -S获取到的节区表信息可以看到,实际在内存中出现的节只有.text、.data、.bss、.rodata和.irom0.text。

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

.irom0.text => eagle.irom0text.bin

通过比较这几个节的大小与烧录文件大小的关系可以得到相同的结果(eagle.flash.bin文件中除了包含程序节数据,还有少量的配置数据)。.bss节虽然在内存中出现但是在程序初始化时会被整个清零,所以不必出现在烧录文件中。这几个节包含的数据内容如下:

节名

作用

.text

存放代码

.data

存放已初始化的全局变量

.bss

存放未初始化的全局变量

.rodata

存放只读数据

.irom0.text

存放标注有ICACHE_FLASH_ATTR的代码或ICACHE_RODATA_ATTR的变量

三、Makefile的执行过程

在前边已经提到,我们写的代码最终会编译为一个elf格式的可执行文件(eagle.app.v6.out),接下我们通过具体Makefile文件中的代码对整个编译的执行过程进行分析。之前讲到sdk/Makefile为主文件,也就是所有编译时用到的逻辑都在其中定义。我们整个的编译流程中需要按顺序产生如下几类目标:二进制目标文件、库文件、elf文件、烧录文件。那么如何通过一个主Makefile来完成这些工作呢,这里需要先看一下其余两类起配置作用的Makefile。这两类Makefile的最后都会有如下代码:

PDIR := ../$(PDIR)

sinclude $(PDIR)Makefile

它的作用是包含自己父文件夹中的Makefile文件,那么最后主Makefile文件中的内容会被包含到库配置文件与项目配置文件中。在项目配置文件中,它的作用是产生elf可执行文件与烧录文件,在库配置文件中,它的作用是产生静态链接库。主Makefile中,最主要的显式规则如下,通过这两条规则产生了所有我们需要的文件。

...

314 all: .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS)

...

.subdirs:

@set -e; $(foreach d, $(SUBDIRS), $(MAKE) -C $(d);)

这两条规则的目标都是伪目标,并不会产生任何文件,我们所需要的所有文件都是目标all的依赖文件。

$(OBJS)

二进制目标文件

$(OLIBS)

静态链接库

$(OIMAGES)

elf可执行文件

$(OBINS)

烧录文件

$(SPECIAL_MKTARGETS)

一直为空

第一个依赖文件.subdirs是一个伪目标,也就是每次编译时都会先执行.subdirs中定义的操作,也就是遍历所有含Makefile文件的子文件夹,执行make命令。通过这种方式产生的结果就是make工具的当前路径发生了改变。拿上边列出的项目结构为例,我们一次编译过程可分为

我们在sdk/project/文件夹下执行make命令编译源码

sdk/project/Makefile包含sdk/Makefile的内容

构建目标all

依赖文件.subdirs不存在,进行构建

遍历sdk/project/下所有含Makefile文件的子文件并执行make命令

这时如果执行了sdk/project/json/Makefile,那么此时make工具的当前路径变为了sdk/project/json/。此时sdk/project/json/Makefile对上层Makefile进行包含后再次构建目标all。一般来说sdk/project/json/中不会再有包含Makefile的子文件夹,那么此时目标all的第一个依赖项.subdirs会立刻返回,然后再对其余的依赖项进行构建。

还有一点需要说明的是目标all的依赖项并不是全都有值的,比如$(SPECIAL_MKTARGETS)的值就一直为空,表示不存在此依赖项。继续拿上边的项目结构举例:

make当前路径

$(OBJS)

$(OLIBS)

$(OIMAGES)

$(OBINS)

sdk/project/

eagle.app.v6.out

eagle.app.v6.bin

sdk/project/json/

json.o

libjson.a

根据make当前路径的不同,目标all有不同的依赖项,然后再根据主Makefile中定义隐式规则对依赖项进行构建,即完成了整个项目的构建过程。

有的朋友可能对Makefile的语法不熟悉,这里推荐一个网站

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

官方的教程很详细

esp8266 SDK开发之环境搭建

最近在弄这个WiFi模块,发现网上SDK开发方面的资料很少,发现了一套视频教程,不过主讲人的讲课方式实在受不了.对基于SDK开发感兴趣的同学可以通过本帖在Ubuntu系统上通过Eclipes搭建开发环 ...

ESP8266 SDK开发: 测试下诱人的程序

前言 这一节测试一下诱人的程序 实现的功能,APP通过SmartConfig给Wi-Fi模块配网并绑定设备,然后通过MQTT远程控制开发板的继电器, APP显示ESP8266采集的温湿度数据. 简而言 ...

ESP8266 SDK开发: 外设篇-GPIO输出高低电平

前言 官方提供了两个函数 GPIO_OUTPUT_SET(gpio_no, bit_value) 设置GPIO2输出高电平 GPIO_OUTPUT_SET(2, 1); 设置GPIO2输出低电平 GP ...

ESP8266 SDK开发: 外设篇-GPIO输入检测

前言 官方提供了以下函数检测引脚输入状态 检测GPIO5 if( GPIO_INPUT_GET(5) == 0 ) GPIO5当前为低电平 if( GPIO_INPUT_GET(5) == 1 ) G ...

ESP8266 SDK开发: 开发环境搭建

前言 这节安装下编程软件, 可以去官网下载, https://wiki.ai-thinker.com/ai_ide_install 也可以安装我提供的(我使用的为官方以前版本) 建议安装我提供的,有问 ...

ESP8266 SDK开发: 外设篇-串口

串口分布 串口切换说明 1.默认所有的数据都使用串口0输出 官方提供了函数可以选择printf利用哪一个串口输出 配置printf使用串口1打印输出,波特率115200 (注:这样配置对于调试程序很有 ...

全志H3-NanoPi开发板SDK之三编译流程【转】

本文转载自:https://blog.csdn.net/yuesichiu/article/details/77600124 版权声明:本文为博主(宽简厚重,Yuesichiu)原创文章,未经博主允许 ...

ESP8266开发综合篇(SDK开发-视频教程总揽)

为了解决基础教程简单入门但不实用,项目方案非常实用但比较难的问题,开始推出8266开发综合篇 综合篇涉及到AT,LUA,SDK,LUA(sdk)开发,LUA和SDK开发会同步进行,后期再整理AT指令的 ...

编译流程,C开发常见文件类型名

编译流程 我们常说的编译是一个整体的概念,是指从源程序到可执行程序的整个过程,实际上,C语言编译的过程可以进一步细分为预编译->编译->汇编->链接 预编译是把include关键字所 ...

随机推荐

真机调试---打包6plus出现问题

问题: dyld: Library not loaded: @rpath/libswiftCore.dylib Referenced from: /private/var/mobile/Contain ...

c++ 程序在内存中的分布

从低地址到高地址: 1.代码区[包含常量的]:存放函数体的二进制代码 2.全局变量区[已初始化 + 未初始化]: 全局变量和静态变量的存储是放一块的,初始化的全局变量和静态变量在一块区域, 未初始化的 ...

MySQL 关闭FOREIGN_KEY_CHECKS检查

SET FOREIGN_KEY_CHECKS=0; truncate table QRTZ_BLOB_TRIGGERS; truncate table QRTZ_CALENDARS; truncate ...

plist文件的相关操作

本文概要 1.plist文件的简介 2.在Xcode中创建plist文件 3.在Xcode中将plist文件转换成数组或者字典对象 4.将数组或者字典对象转换成plist文件并且存储 详细介绍 1.p ...

GitHub新手使用教学(从安装到使用)

一.安装Git for Windows(又名msysgit)  下载地址: https://git-for-windows.github.io/  在官方下载完后,安装到Windows Explore ...

使用logdashboard进行可视化的日志追踪

本文源码在Github可以找到下载 LogDashboard 如果你还不了解LogDashboard请看这里. LogDashboard 1.1版本支持请求追踪,虽然目前版本还没有发布.不过这个功能可 ...

python 调用js代码

Python2   安装pyv8 pip install-egit://github.com/brokenseal/PyV8-OS-X#egg=pyv8 from pyv8 import PyV8 c ...

Control4系统对接arduino

https://www.chowmainsoft.com/arduino int digitalState[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; v ...

Python 基础之----网络编程

阅读目录 一 客户端/服务端架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现象 ...

Jenkins下载安装

Jenkins是什么? Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测 ...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值