https://github.com/alibaba/AliOS-Things/wiki/Add-a-new-component-example.zh
一、添加一个组件:info_a
架构简介
|----AliOS-Things
|----example
| |----nano # example目录下的工程文件将会被编译运行,它将调用info_a组件
| | |----nano.c
| | |----nano.h
| | |----nano.mk
| |......
|----framwork
|----info_a # framwork目录下的新组件,有.mk文件
| |----info_a.c
| |----info_a.h
| |----info_a.mk
|......
nano例程是最简单的工程:它的路径在AliOS-Things\example\nano\nano.c
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <aos/aos.h>
static void app_delayed_action(void *arg)
{
printf("nano %s:%d %s\r\n", __func__, __LINE__, aos_task_name());
}
int application_start(int argc, char *argv[])
{
do
{
app_delayed_action(NULL);
aos_msleep(1000);
}while(1);
}
增加一个新模块供现有的app调用,运行查看结果。 nano是aos自带的一个最简单的app例子,它实现了最简单的延时循环打印功能,我们用它来作为例子中所用的app。 新增模块名设为 info_a,功能是打印一条特定的信息。
在framework下创建一个 info_a 目录。
1.增加新模块源文件
在 info_a 目录中创建 info_a.c :
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
void info_a_fun()
{
printf("this is in info_a\n");
}
2.增加新模块的对外头文件
在 info_a 目录中创建 info_a.h :
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef INFO_A_H
#define INFO_A_H
#ifdef __cplusplus
extern "C" {
#endif
extern void info_a_fun();
#ifdef __cplusplus
}
#endif
#endif /* INFO_A_H */
3.增加新模块的.mk文件
.mk文件是模块存在的标志。每一个模块都会有一个对应的mk文件,makefile通过搜索mk后缀的文件来查找模块。其中声明了一些针对该模块的定制化的东西。最基本的两个就是该模块所包含的源文件,头文件路径和该模块依赖的其他模块。
在info_a目录下创建 info_a.mk:
NAME := info_a
$(NAME)_SOURCES := info_a.c
GLOBAL_INCLUDES += .
4.修改 nano 源文件调用新接口
如:
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <aos/aos.h>
#include "info_a.h"
static void app_delayed_action(void *arg)
{
printf("%s:%d %s\r\n", __func__, __LINE__, aos_task_name());
info_a_fun();
}
int application_start(int argc, char *argv[])
{
do
{
app_delayed_action(NULL);
aos_msleep(10);
}while(1);
}
5. 修改 nano的 .mk 文件依赖新模块
在nano.mk中新增一行:
$(NAME)_COMPONENTS += info_a
坑一:找不到头文件
example/nano/nano.c:7:10: fatal error: info_a.h: No such file or directory
#include <info_a.h>
^~~~~~~~~~
那好,我改:
我把#include <info_a.h>
改成#include <../framework/info_a/info_a.h>
头文件,直接通过绝对目录来指定头文件的地方。嘚,没报错了,说明这是可以解决的。
不过又出现了新的问题:
out/nano@mk3060/libraries/nano.a(nano.o): In function `app_delayed_action':
D:\Output\AliOS\AliOS-Things/example/nano/nano.c:12: undefined reference to `info_a_fun'
函数info_a_fun没有找到?抱歉,头文件都没报错了,头文件里面有的函数你居然说找不到!再仔细找!
靠!!!nano.mk里面写错了!
原有的没改的,按照文档,我要在里面添加一句:$(NAME)_COMPONENTS += info_a
NAME := nano
$(NAME)_SOURCES := nano.c
GLOBAL_DEFINES += AOS_NO_WIFI CONFIG_NO_TCPIP
mesh ?= 0
ifeq ($(BENCHMARKS),1)
$(NAME)_COMPONENTS += benchmarks
GLOBAL_DEFINES += CONFIG_CMD_BENCHMARKS
endif
然后,我就改成了以下这种错误的了!
NAME := nano
$(NAME)_SOURCES := nano.c
GLOBAL_DEFINES += AOS_NO_WIFI CONFIG_NO_TCPIP
mesh ?= 0
ifeq ($(BENCHMARKS),1)
$(NAME)_COMPONENTS += benchmarks \
info_a # 注意不能在这里加啊!!
GLOBAL_DEFINES += CONFIG_CMD_BENCHMARKS
endif
正确的mk
NAME := nano
$(NAME)_SOURCES := nano.c
$(NAME)_COMPONENTS += info_a # 正确的做法是要在这添加啊!
GLOBAL_DEFINES += AOS_NO_WIFI CONFIG_NO_TCPIP
mesh ?= 0
ifeq ($(BENCHMARKS),1)
$(NAME)_COMPONENTS += benchmarks
GLOBAL_DEFINES += CONFIG_CMD_BENCHMARKS
endif
- 再编译,我的头文件还是这么写的
#include <../framework/info_a/info_a.h>
,编译通过! - 那我改改头文件
#include <info_a/info_a.h>
,编译失败! - 再改文件
#include <info_a.h>
,编译成功!
添加一个新模块的总结
1、新模块的C文件、H文件、mk文件缺一不可!
2、调用模块时,工程里面的mk文件一定要添加模块那啥!$(NAME)_COMPONENTS += info_a
3、头文件的包含方式就两种:
(1)绝对路径:#include <../framework/info_a/info_a.h>
(2)单独头文件:#include <info_a.h>
二、再添加一个组件:info_b
架构简介
|----AliOS-Things
|----example
| |----nano # example目录下的工程文件将会被编译运行,它将调用info_a、info_b组件
| | |----nano.c
| | |----nano.h
| | |----nano.mk
| |......
|----framwork
|----info_a # framwork目录下的新组件a,有.mk文件
| |----info_a.c
| |----info_a.h
| |----info_a.mk # 通过在这里面添加关系,来带出info_b组件
|----info_b # framwork目录下的新组件b,有.mk文件
| |----info_b.c
| |----info_b.h
| |----info_b.mk
|......
使用同样的方法添加一个info_b文件夹
- info_b.c
- info_b.h
- info_b.mk
info_b.c
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
void info_b_fun()
{
printf("this is in info_b\n");
}
info_b.h
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef INFO_B_H
#define INFO_B_H
#ifdef __cplusplus
extern "C" {
#endif
extern void info_b_fun();
#ifdef __cplusplus
}
#endif
#endif /* INFO_A_H */
info_b.mk
NAME := info_b
$(NAME)_SOURCES := info_b.c
GLOBAL_INCLUDES += .
好的,新组件b又做好了。
现在想让组件b“依附”在组件a上面,即,nano工程只需要#include "info_a.h"
就可以调用组件b的info_b_fun()
函数。只需要在info_a.mk里面写:
NAME := info_a
$(NAME)_SOURCES := info_a.c
$(NAME)_COMPONENTS += info_b # 添加这个依赖就可以了
GLOBAL_INCLUDES += .
如下就可以编译了
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <aos/aos.h>
#include <info_a.h> // 没有info_b.h的头文件
static void app_delayed_action(void *arg)
{
printf("nano %s:%d %s\r\n", __func__, __LINE__, aos_task_name());
info_b_fun(); // 却可以调用info_b里面的组件
}
int application_start(int argc, char *argv[])
{
do
{
app_delayed_action(NULL);
aos_msleep(1000);
}while(1);
}
三、再再添加一个组件:info_c/info_c_a
架构简介
|----AliOS-Things
|----example
| |----nano # example目录下的工程文件将会被编译运行,它将调用info_a、info_b组件
| | |----nano.c
| | |----nano.h
| | |----nano.mk
| |......
|----framwork
|----info_a # framwork目录下的新组件a,有.mk文件
| |----info_a.c
| |----info_a.h
| |----info_a.mk # 通过在这里面添加关系,来带出info_b组件
|----info_b # framwork目录下的新组件b,有.mk文件
| |----info_b.c
| |----info_b.h
| |----info_b.mk
|----info_c # 该目录中没有.mk文件,它的子目录中有.mk文件(加了一层)
| |----info_c_a
| | |----info_c_a.c
| | |----info_c_a.h
| | |----info_c_a.mk
| |----info_c_b # 更多的新组件
| |.......
|......
文件还是老三样(写法和组件a的几乎一模一样就是,名字加了"_c"):
- info_c_a.c
- info_c_a.h
- info_c_a.mk
就是组件在其他目录之下,那么在nano工程中该怎么调用呢?
首先nano.mk得这么写:
NAME := nano
$(NAME)_SOURCES := nano.c
$(NAME)_COMPONENTS += info_c/info_c_a # info_c里面没有.mk文件所以....
GLOBAL_DEFINES += AOS_NO_WIFI CONFIG_NO_TCPIP
mesh ?= 0
ifeq ($(BENCHMARKS),1)
$(NAME)_COMPONENTS += benchmarks
GLOBAL_DEFINES += CONFIG_CMD_BENCHMARKS
endif
然后,nano.c里面include头文件就可以直接使用了
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include <stdio.h>
#include <aos/aos.h>
#include <info_c_a.h> // 新组件c的头文件
static void app_delayed_action(void *arg)
{
printf("nano %s:%d %s\r\n", __func__, __LINE__, aos_task_name());
info_c_a_fun(); // 新组件c里面的函数
}
int application_start(int argc, char *argv[])
{
do
{
app_delayed_action(NULL);
aos_msleep(1000);
}while(1);
}
四、总结
把这几种类型的组件全部试用一次,就可以大致了解到AliOS-Things的文件依赖与调用,包括.mk文件的写法就没那么迷糊了,还有就是大型的C工程里面包含头文件的写法也是头痛,经过以上的实验之后,好像有那么点清楚了。