阿里云IOT-C-SDK系列(3)快速体验:不使用SDK自带编译系统进行移植示例及Makefile的编写示范

阿里云IOT-C-SDK系列(1)概述:移植流程、程序框架、代码目录

阿里云IOT-C-SDK系列(2)快速体验:移植+示例C代码

    在系列(2)中详细的罗列了如何使用SDK自带的编译系统进行移植,正如前面所述,使用SDK自带的编译系统看起来简单,但是由于SDK对很多的细节进行了封装,所以对于我们深入的理解SDK反倒是不好的,所以阿里的技术支持更加推荐用户能够使用“代码抽取”功能,将抽取出的代码放到我们自己的工程项目中,我们根据自己的软硬件环境,我们自己来写Makefile编译SDK。

1、“代码抽取” 移植方式的流程及注意事项

    正如前两篇文章所述,执行代码抽取 脚本 后,会将我们需要的SDK功能对应的源码抽取出来,抽取目录里一般会有个Makefile,这个Makefile是一个比较贴心的东西,运行该Makefile会生成2个库文件:libiot_sdk.a 和 libiot_hal.a,其中:

libiot_sdk.a : SDK的核心库,是SDK的软件功能实现的库。

libiot_hal.a : SDK提供的HAL层的库,这个是 跟我们硬件环境相关的,换言之,是对应那个wrappers.c中的各种函数的编译结果。

    但是要特别注意:我们的移植工作的重点是 要 实现 wrappers.c中的所有 HAL_xxx接口函数,而抽取出的源码,默认情况下,wrappers.c中的HAL_XXX函数都是空的,只有框架,所以需要我们自己去填充。

   另外,这个自带的Makefile的使用也并不是一定最好的,因为如果我们不去实现HAL_xxx接口函数,即便我们运行Makefile,那么 生成的库也是没法使用的。所以最好是自己去写Makefile,这样虽然开始难一些,但是一旦调试完成了,不管是对于我们写Makefile的水平,还是对SDK的理解,能更加深入。所以本文采用 代码抽取 移植方式+ 自己编写Makefile来实现。流程如下:

(1)运行 make menuconfig(Windows下运行 config.bat),进行功能选择。即选择SDK中我们需要的功能,相当于裁剪SDK,该步骤会生成 make.setting 文件,里面罗列了我们选择的功能项,用于步骤(2)的输入。

(2)运行 extract.sh (Windows 下运行 extract.bat),进行代码抽取。

(3) 步骤2的抽取结果是在当前目录下创建 output 目录,里面包含2个子目录 eng 、examples,和1个Makefile,其中:

eng:抽取的功能源码。   examples:SDK自带的示例代码, Makefile:方便生成 库文件的 Makefile。

(4)将步骤3中生成的 eng 文件夹 放入到我们的工程目录下,这里examples只是编程示范,是不需要放入我们的工程文件的,Makefile文件更不需要。

(5)实现我们eng/wrappers/wrapper.c中的 所有 HAL_XXX接口函数。

(6)如果我们使用的是Keil或IAR, 那就简单了,不用我们自己来写Makefile了,用IDE自带的编译系统就好了,而Linux下是需要自己来写Makefile的,这里对于那些高手来讲就太简单了,不过我连个熟练手都算不上,只能算是入门级。 

(7)编写我们自己的业务逻辑代码,关于如何使用SDK,当然要借鉴output/examples里的 案例了。

2、wrapper.c 的实现注意事项

    wrapper.c是SDK的 代码抽取 脚本的最终输出文件,需要我们取提供文件中 罗列的各种 HAL_XXX函数,因为默认各个函数为空。这里需要特别注意的几点:

(1) 不能认为只要实现HAL_XXX函数就万事大吉了,我们在实现HAL_XXX接口函数的时候,一定记得要 添加 相关的头文件,否则我们在编译的时候,会出现各种各样的错误提示的。

(2)wrapper.c中只罗列了SDK运行所必须的 的 HAL_XXX接口 函数,所以我们才会发现,wrapper.c中的 HAL_XXX函数并 不多,这绝不代表 只有这些 HAL 函数,如果我们使用xxx_api.h 中的 其他HAL_XXX函数,我们是需要在wrapper.c中实现它的, 或者在其他地方, 总之只要是HAL_XXX函数,不管是在wrapper.c中还是其他地方出现的,都是 需要我们去实现的。举例:我们在linkkit_example_gateway.c 示例代码中,发现了 HAL_ThreadCreate 函数,很明显这是线程创建函数,我们搜寻源码,发现这个 函数 定义在 源码 wrapper/os/ubuntu/HAL_OS_linux.c中,这本身就是 SDK 给我们写好的 在ubuntu下的 接口函数,如果我们的编程环境是 linux,我们想用抽取 代码结果 wapper.c 之外的 HAL_XXX函数,记住, 一定要先实现他。

3、编译抽取出的功能源码的 Makefile 示范

   虽然抽取的功能源码并不是特别多,但是如果逐个文件去编译,然后连接,估计也得抓狂,这也不是Makefile的 特色,Makefile强大的功能,几乎只有我想不到,没有它干不成的,尤其是 传说中的那个 正规表达式,简直了,对于之前使用IDE编程的人来说,说震撼一点都不夸张。

    这里的难点是,如何一次性的对 抽取代码进行编译,参考抽取代码中 Makefile的方式,先上代码,然后再分析,核心Makefile代码如下:

CROSS = arm-linux-gnueabihf-

CC = $(CROSS)gcc

STRIP = $(CROSS)strip 

CFLAGS = -g -O2 -Wall

# Aliyun SDK compile 

# source dir
SRCDIR := eng
# all the *.c except wrappers/
IOT_SDK_SOURCE_FILES_C := $(shell find $(SRCDIR) -name "*.c" -not -path "*wrappers*")
# the dir wrappers/  *.c
IOT_SDK_WRAPPER_IMPL_S := $(shell find $(SRCDIR) -name "*.c" -path "*wrappers*")

# include all the dir path
IOT_SDK_HDRDIR := $(shell find $(SRCDIR) -type d)
# add the -I to the IOT_SDK_HDRDIR
IOT_SDK_HDRDIR := $(addprefix -I,$(IOT_SDK_HDRDIR))

#include
INC = -I./bsp -I./bsp/wraperror \
       -I./bsp/wrappthread \
       -I./bsp/event $(IOT_SDK_HDRDIR)

#lib
LIBS = -lpthread -lrt

#src
SRC = main.c  bsp/wraperror/wraperror.c \
      bsp/wrappthread/wrappthread.c \
      bsp/event/portevent.c \
      $(IOT_SDK_SOURCE_FILES_C) \
      $(IOT_SDK_WRAPPER_IMPL_S)

#target
TARGET = test

#objs
OBJS = $(SRC:.c=.o)

$(TARGET):$(OBJS)
	$(CC) -o $@ $^ $(LIBS)

.PHONY: clean

clean:
	rm -f $(OBJS)

install: $(TARGET) clean
	@echo start compile...
	@echo end.

%.o:%.c
	$(CC) $(CFLAGS) $(INC) $(LIBS) -o $@ -c $<

上面的大部分代码,我们分别用汉语来解释:

# 定义交叉编译器
CROSS = arm-linux-gnueabihf-
CC = $(CROSS)gcc
# 定义交叉编译器 编译选项
STRIP = $(CROSS)strip 
CFLAGS = -g -O2 -Wall

# 定义变量 SRCDIR,也就是eng目录
SRCDIR := eng

# 这里使用了 Makefile中嵌套 shell命令来实现 一条命令包含所有的 *.c文件
# 相当于运行了 find eng -name "*.c" -not -path "*wrappers*" ,这条命令的结果就是 查找
# eng目录(包含子目录)下所有的名字为 *.c 的文件,-not -path顾名思义,不包含 wrappers
# 这样做是为了 让我们一步步的编译的,比如我们可以先不去实现 wrapper.c 只编译其他核心代码 
IOT_SDK_SOURCE_FILES_C := $(shell find $(SRCDIR) -name "*.c" -not -path "*wrappers*")
# 套路跟上面一样,就是获取 wrappers 目录下(包含子目录)的所有 *.c 文件
IOT_SDK_WRAPPER_IMPL_S := $(shell find $(SRCDIR) -name "*.c" -path "*wrappers*")
#通过上面两条命令一搞,这两个变量就代表了 所有的 *.c 文件,太牛掰了。


# include all the dir path
# 获取eng 目录下所有的 目录,这是为了包含那些头文件的。
IOT_SDK_HDRDIR := $(shell find $(SRCDIR) -type d)
# add the -I to the IOT_SDK_HDRDIR
# addprefix 是添加 -I 到 后面的字符串,这样就能 符合make中 包含 路径的语法了。
IOT_SDK_HDRDIR := $(addprefix -I,$(IOT_SDK_HDRDIR))

#include
INC = -I./bsp -I./bsp/wraperror \
       -I./bsp/wrappthread \
       -I./bsp/event $(IOT_SDK_HDRDIR)  

#lib
# 编译 SDK,尤其是 linux环境下,需要加上 -lrt,因为HAL_XXX的 时间接口上使用了 rt库,
LIBS = -lpthread -lrt 

#src
SRC = main.c  bsp/wraperror/wraperror.c \
      bsp/wrappthread/wrappthread.c \
      bsp/event/portevent.c \
      $(IOT_SDK_SOURCE_FILES_C) \
      $(IOT_SDK_WRAPPER_IMPL_S)

#target
TARGET = test

#objs
#定义所有的 的目标 obj,这条命令的意思是 所有的 *.c 生成 对应的 *.o 文件
OBJS = $(SRC:.c=.o)


$(TARGET):$(OBJS)
	$(CC) -o $@ $^ $(LIBS)

.PHONY: clean

clean:
	rm -f $(OBJS)

install: $(TARGET) clean
	@echo start compile...
	@echo end.
#所有的 .o 文件生成规则
%.o:%.c
	$(CC) $(CFLAGS) $(INC) $(LIBS) -o $@ -c $<



发布了247 篇原创文章 · 获赞 257 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/u012351051/article/details/99339594