nesC程序可以通过make命令直接编译、连接,并下载到mote上,编译连接规则和使用的硬件平台定义在makefile文件中。下面讲解ncc是如何把Blink.nc和BlinkM.nc有效地连接起来的。 编译和连接命令如下: ncc -o build/mica2/main.exe -Os -board=micasb -target=mica2 –Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -fnesC-cfile=build/mica2/app.c 对其中命令选项的含义可以查阅ncc帮助信息。 从以上编译选项中可以看出,ncc编译的输入文件只有Blink.nc 配件文件,并没有BlinkM.nc模块文件。那么,究竟是如何把它们连接成一个可执行文件的呢? 首先需要理解:ncc是对C的扩展和修改,使其更好地适合嵌人式系统,特别是适合系统资源相当少的传感器网络系统。ncc是nesC的编译器,也是对gcc的修改和扩充。ncc先把nesC预编译成C文件,再通过交叉编译器把C文件编译成可执行文件。 典型的nesC应用程序代码由三部分组成:一套C声明和定义,一套接口集合;一套组件集合。它们与C文件的对应关系问题(如变量作用域,命令及事件与C语言中函数的对应关系等)将在下面逐一分析。 1、作用域问题 在作用域的最顶层包含三个名字空间的全局作用域,分别为C变量和标签名字空间(针对C声明和定义)。组件名字空间和接口名字空间。C声明和定义可能又有自己的作用域,比如C函数中的局部变量。注意,C本身是处于全局作用域中的,这点可以从Blink编译生成的C文件得到证实。 每个接口类型处于全局作用域中,但是接口中的命令和事件却处于该接口的作用域内。也就是说接口中的命令或者事件必须要指定接口名称才能访问,如在BlinkM中要用到接口Timer,根据第一条可知BlinkM和Timer处于同一作用范围内,所以在BlinkM中可以引用Timer。但是使用Time中的命令 start()时,就必须指明为Timer.start(),而不能直接写为start()。显然在任何组件中都可以使用C的变量和函数,这是因为C的变量和函数是处于全局域中的。这就是为什么上面提到的在模块BlinkM中使用result_t, uint32_t,char类型并没有出错。从ncc编译生成的C文件中可明显地看出这一点。下面是app.c(ncc编译产生的C文件)开头的一段代码,它们的定义是全局的。 每个组件引入了两个作用域:一个是规范域(specification),它处于全局域中;另外一个是实现域(implementation),它处于规范域内。 2、cc整合C文件、接口和组件的过程 从上面的编译信息可以看出,ncc编译的输入是一个配件文件Blink.nc(一个顶层配件文件)。ncc首先装人tos.h文件,该文件包含了基本数据类型定义和一些基本函数。然后ncc把需要的c文件、接口或者组件装人到ncc编译器中进行编译。最后装人顶层配件文件(此处为Blink. nc)。具体步骤如下: (1) (2) (3) 3、nesC语言命名到C语言命名的映射 所谓nesC语言命名到C语 |
|