LV01-01-AliOSThings-09-源码与编译-03-源码编译工具Makefile

本文主要是源码与编译——源码编译工具Makefile的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu22.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
点击查看本文参考资料
分类 网址 说明
官方网站 阿里云 阿里云官网主页
阿里生活物联平台 生活物联网平台(飞燕平台)主页
AliGenie 天猫精灵开放平台AliGenie主页
阿里物联网平台 阿里物联网平台主页
Bluetooth 技术网站 蓝牙协议规范什么的可以来这里找
Telink Telink | Chips for a Smarter IoT (telink-semi.com)
Telink中文官网
开发手册 AliOS Things开发指南 AliOS Things开发指南,这里是最新版本,可以直接从官网找到
AliOS Things开发指南 AliOS Things应用开发指南,这里应该是3.3版本的完整开发文档
AliOS Things开发指南(3.0) AliOS Things应用开发指南,这里应该是3.0版本的完整开发文档
生活物联网平台开发文档 生活物联网平台(飞燕平台)开发文档
《设备端开发指南》
Wi-Fi IoT品类定义与功能开发 天猫精灵IoT开放平台——Wi-Fi IoT品类定义与功能开发
硬件平台 mk3080 WiFi开发板 WiFi开发板使用指南-阿里云开发者社区
esp8266开发板 一个教程:ESP8266-NodeMCU开发板详解-太极创客 (taichi-maker.com)
TLSR8258 Datasheet Datasheet for Telink BLE + IEEE802.15.4 MultiStandard Wireless SoC TLSR8258
参考资料 AliOS Things 3.0 应用开发指南 这个只是一篇参考文章,里面是一些环境搭建相关的,可以参考
IP知识百科 - 华为 (huawei.com) IP的一些相关知识点
点击查看相关文件下载
分类 网址 说明
蓝牙规范相关文档 Core Specification 5.2 核心规格 5.2,该规范定义了创建可互操作的Bluetooth 设备所需的技术。
《Core_v5.2.pdf》
Mesh Model(v1.1) 本Bluetooth 规范定义了模型(以及它们所需的状态和消息),这些模型用于在mesh 网络中的节点上执行基本功能,超出了Bluetooth Mesh 配置文件 规范中定义的基础模型。
本规范包括定义跨设备类型标准功能的通用模型,以及支持关键mesh 场景的模型,如照明控制、传感器、时间和场景。
《MshMDL_v1.1.pdf》
Mesh Profile(v1.0.1) 该Bluetooth 规范定义了基本要求,以实现可互操作的mesh 网络解决方案,用于Bluetooth 低能量无线技术。
《MshPRFv1.0.1.pdf》
Mesh Device Properties 本规范包含Bluetooth Mesh 配置文件 和Bluetooth Mesh 模型规范所要求的设备属性的定义。
但是跟之前的有些区别,我主要看的之前的版本:《MMeshDeviceProperties_v1.2.pdf》
GATT Specification Supplement GATT Specification Supplement | Bluetooth® Technology Website。
好像可以在线看:《GATT Specification Supplement》
Assigned Numbers GATT的一些类型定义可以在这里找。
AliOS Things alios-things/AliOS-Things Gitee上的AliOSThings SDK源码仓库
alibaba/AliOS-Things GitHub上的AliOSThings SDK源码仓库
天猫精灵蓝牙Mesh协议栈 alibaba-archive/genie-bt-mesh-stack GitHub上的天猫精灵蓝牙Mesh协议栈源码仓库。
之前是在alibaba/genie-bt-mesh-stack这个仓库。
写笔记的时候最新提交为faf523618a6a2560090fc423222b9db80984bb7a
蓝牙Mesh设备开发指南 阿里云生活服务平台开发手册——蓝牙设备开发一节中的内容

前面有详细学习过makefile语法,这里简单复习一下吧。

一、Makefile简介

1. make简介

可以直接搜一下就行。

2. 学习资料

官网在写这篇笔记的时候进不去,先不写吧,而且很容易搜到的。还有一个中文手册,在这里:GNU Make 使用手册(中译版) (elecfans.com)

image-20200716154757423

二、Makefile运行过程

我们有如下源码文件:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char **argv)
{
if (argc >= 2)
printf("Hello, %s!\n", argv[1]);
else
printf("Hello, world!\n");
return 0;
}

我们创建Makefile文件如下:

1
2
3
4
hello: hello.c
gcc -o hello hello.c
clean:
rm -f hello

Makefile的执行过程如下:

image-20200701130749022

三、基本语法

1. Makefile规则

1
2
目标(target): 依赖(prerequiries)
<tab>命令(command)

目标(target)通常是要生成的文件的名称,可以是可执行文件或OBJ文件,也可以是一个执行的动作名称,诸如clean

2. 两个重要概念

依赖关系:依赖关系定义了如果你要建立一个目标,有什么是必须做的。

时间先后:根据文件的时间,make程序判断那些东西发生了变化,然后根据前面定义的依赖关系把依赖于这些文件的目标重新建立一遍

3. makefile 变量赋值

变量的定义语法形式如下:

1
2
3
4
5
6
7
immediate = deferred
immediate ?= deferred
immediate := immediate
immediate += deferred or immediate
define immediate
deferred
endef

在GNU make中对变量的赋值有两种方式:延时变量、立即变量。区别在于它们的定义方式和扩展时的方式不同,前者在这个变量使用时才扩展开,意即当真正使用时这个变量的值才确定;后者在定义时它的值就已经确定了。使用=?=定义或使用define指令定义的变量是延时变量;使用:=定义的变量是立即变量。需要注意的一点是,?=仅仅在变量还没有定义的情况下有效,即?=被用来定义第一次出现的延时变量。

对于附加操作符+=,右边变量如果在前面使用(:=)定义为立即变量则它也是立即变量,否则均为延时变量。

4. makefile函数

4.1 foreach

$(foreach var,list,text)简单地说,就是 for each var in list, change it to text。对list中的每一个元素,取出来赋给var,然后把var改为text所描述的形式。例如:

1
2
objs := a.o b.o
dep_files := $(foreach f, $(objs), .$(f).d) #最终 dep_files := .a.o.d .b.o.d

4.2 wildcard

$(wildcard pattern):pattern所列出的文件是否存在,把存在的文件都列出来。例如:

1
src_files := $( wildcard  *.c) # 最终 src_files中列出了当前目录下的所有.c文件

5. 自动变量

1
2
%.o : %.c
gcc -MD -c $< -o $@

$@$^$<称为自动变量。$@表示规则的目标文件名;$^表示所有依赖的名字,名字之间用空格隔开;$<表示第一个依赖的文件名。%是通配符,它和一个字符串中任意个数的字符相匹配。

6. 伪目标

我们的Makefile中有这样的目标:

1
2
clean:
rm -f *.o

如果当前目录下恰好有名为“clean”的文件,那么执行“make clean”时它就不会执行那些删除命令。这时我们需要把“clean”这个目标,设置为“假想目标”,这样可以确保执行“make clean”时那些删除命令肯定可以得到执行。可以使用下面的语句把“clean”设置为假想目标:

1
.PHONY : clean

四、make命令

执行make命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生成第一个目标。

1. -f选项

我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,例如下面的命令将会使用 Makefile.build 文件来编译工程:

1
make -f Makefile.build 

2. -C选项

我们可以使用“-C”选项指定目录,切换到其他目录里去

1
make -C a/ -f Makefile.build 

3.生成执行目标

我们可以指定目标,不再默认生成第一个目标

1
make -C a/ -f Makefile.build target_name

五、使用实例

1. 测试文件源码

1.1 main.c

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

extern void sub_fun(void);

int main(int argc, char* argv[])
{
printf("Main fun!\n");
sub_fun();
return 0;
}

1.2 sub.c

1
2
3
4
5
6
7
#include <stdio.h>
#include "sub.h"

void sub_fun(void)
{
printf("Sub fun, A= %d!\n", A);
}

1.3 sub.h

1
2
#define A  2
void sub_fun(void);

1.4 Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
objs := main.o sub.o

test : $(objs)
gcc -o test $^


dep_files := $(wildcard *.d)

# 把依赖文件包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif

%.o : %.c
gcc -MD -c $< -o $@
clean:
rm *.d *.o test -f

2. 测试现象

我们直接用上面的makefile文件,执行make,会有以下打印信息:

image-20231126161943316

当我们没有文件更新的时候,再次执行会提示我们的可执行文件是最新的,我们执行可执行文件会有如下打印:

image-20231126162026386

然后我们修改sub.h中的宏为3,然后重新编译执行,会发现,打印结果为3,说明仅更新头文件时,最终目标也会更新:

image-20231126162145756

现在我们去掉Makefile中gcc命令后面的MD选项(注意,这里要先删掉之前的.d文件,因为之前生成过,不删除的话,会影响测试结果),之后重新执行一遍make生成一下可执行文件,然后修改宏为4,再编译执行:

image-20231126163130922

会发现,只更新了头文件后,最终可执行文件并不会被更新,这就是-MD选项的意义啦。