第5篇,关于编译的法则:Makefile和makerules

tinyos当中,如果对应的application文件夹下面只有*.nc文件是没有办法完成编译的,我们还需要相应的makefile文件。

Makefile文件是编译的时候,指定ncc编译器去编译哪个程序(COMPONENT),并使用什么样的方式(由makerules所指定)去编译。

 

通常,一个标准的Makefile的内容为:

COMPONENT={application name}

include ../Makerules

 

vvfangblog当中所说的不同(可能是版本不同的原因),根据我的经验,实际上tinyos在编译每个app的时候,是会运行app里的makefile定义的include ../Makerules, 不信你把那条语句删掉试试,出现如下提示:

Make: *** No rule to make target  ‘pc’ .Stop

 

tinyos程序的文件位置:

那么下一个问题就可以解决。例如不想把自己的app放到官方指定的位置: /opt/tinyos-1.x/apps,比如,我就把我自己编写和修改的程序放到如下文件夹: /opt/tinyos-1.x/apps/myworks 和官方给的例子程序区别开。程序放到这个文件夹下还是不可以直接编译的,我们需要把/opt/tinyos-1.x/apps 下面Makerules文件也复制到/opt/tinyos-1.x/apps/myworks下,编译就没有任何问题。

 

结论如下:

1.  tinyos中,一次典型的编译需要如下文件在一个文件夹中:

 moudule file

 顶级configuration file

 makefile

 以及其他文件

系统已有的文件是不需要专门放到这个文件夹下面,tinyos的编译器会自己去找到相应的系统调用。

  makefile中有:

 COMPONENT={application name}

include ../Makerules

 

COMPONENT必须和应用程序的名字一致,不需要和文件夹名字一致。

 

  

2. 自己编写的应用程序,不必非要放在apps文件夹下面,但是程序文件夹的上层(外层)必须有makerules文件,才可以成功编译。


观察到在/opt/tinyos-1.x/apps也有makefile,打开看到是对应该目录下所有的例子程序的make法则。那么你可以在/opt/tinyos-1.x/apps下,直接敲入

make pc

那么它对应的功能自然就是:编译所有例子程序!!!

 

不知道为什么,我这里在编译到HighFrequencySampling的时候出错,具体原因没时间仔细看,哪位同学有解决方案,请告知,谢谢!

 

附录:关于Make Makefile

 

无论是在Linux 还是在Unix 环境中,make 都是一个非常重要的编译命令。不管是自己

进行项目开发还是安装应用软件,我们都经常要用到make make install。利用make 工具,

我们可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的

应用程序,使用make makefile 工具就可以简洁明快地理顺各个源文件之间纷繁复杂的相

互关系。而且如此多的源文件,如果每次都要键入gcc 命令进行编译的话,那对程序员来说

简直就是一场灾难。而make 工具则可自动完成编译工作,并且可以只对程序员在上次编译

后修改过的部分进行编译。因此,有效的利用make makefile 工具可以大大提高项目开发

的效率。

 

1 Makefile 文件

Make 工具最主要也是最基本的功能就是通过makefile 文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如

何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。makefile

件是许多编译器――包括 Windows NT 下的编译器――维护编译信息的常用方法,只是在

集成开发环境中,用户通过友好的界面修改 makefile 文件而已。

UNIX 系统中,习惯使用 Makefile 作为 makfile 文件。如果要使用其他文件作为

makefile,则可利用类似下面的 make 命令选项指定 makefile 文件:

$ make -f Makefile.debug

例如,一个名为prog 的程序由三个C 源文件filea.cfileb.c filec.c 以及库文件LS

译生成,这三个文件还分别包含自己的头文件a.h b.h c.h。通常情况下,C 编译器将会

输出三个目标文件filea.ofileb.o filec.o。假设filea.c fileb.c 都要声明用到一个名为defs

的文件,但filec.c 不用。即在filea.c fileb.c 里都有这样的声明:

#include "defs"

那么下面的文档就描述了这些文件之间的相互联系:

---------------------------------------------------------

#It is a example for describing makefile

prog : filea.o fileb.o filec.o

cc filea.o fileb.o filec.o -LS -o prog

filea.o : filea.c a.h defs

cc -c filea.c

fileb.o : fileb.c b.h defs

cc -c fileb.c

filec.o : filec.c c.h

cc -c filec.c

----------------------------------------------------------

这个描述文档就是一个简单的makefile 文件。

从上面的例子注意到,第一个字符为 # 的行为注释行。第一个非注释行指定prog 由三

个目标文件filea.ofileb.o filec.o 链接生成。第三行描述了如何从prog 所依赖的文件建立

可执行文件。接下来的468 行分别指定三个目标文件,以及它们所依赖的.c .h 文件以

defs 文件。而579 行则指定了如何从目标所依赖的文件建立目标。

filea.c a.h 文件在编译之后又被修改,则 make 工具可自动重新编译filea.o,如果

在前后两次编译之间,filea.C a.h 均没有被修改,而且 test.o 还存在的话,就没有必要

重新编译。这种依赖关系在多源文件的程序编译中尤其重要。通过这种依赖关系的定义,

make 工具可避免许多不必要的编译工作。当然,利用 Shell 脚本也可以达到自动编译的效

果,但是,Shell 脚本将全部编译任何源文件,包括哪些不必要重新编译的源文件,而 make

工具则可根据目标上一次编译的时间和目标所依赖的源文件的更新时间而自动判断应当编

译哪个源文件。

Makefile 文件作为一种描述文档一般需要包含以下内容:

◆ 宏定义

◆ 源文件之间的相互依赖关系

◆ 可执行的命令

Makefile 中允许使用简单的宏指代源文件及其相关编译信息,在Linux 中也称宏为变量。在

用宏时只需在变量前加$符号,但值得注意的是,如果变量名的长度超过一个字符,在引用

就必须加圆括号()。

下面都是有效的宏引用:

$(CFLAGS)

$2

$Z

$(Z)

其中最后两个引用是完全一致的。

需要注意的是一些宏的预定义变量,在Unix 系统中,$*$@$?$<四个特殊宏的值

在执行命令的过程中会发生相应的变化,而在GNU make 中则定义了更多的预定义变量。

宏定义的使用可以使我们脱离那些冗长乏味的编译选项,为编写makefile 文件带来很大

的方便。

---------------------------------------------------------

# Define a macro for the object files

OBJECTS= filea.o fileb.o filec.o

# Define a macro for the library file

LIBES= -LS

# use macros rewrite makefile

prog: $(OBJECTS)

cc $(OBJECTS) $(LIBES) -o prog

……

---------------------------------------------------------

此时如果执行不带参数的make 命令,将连接三个目标文件和库文件LS;但是如果在

make 命令后带有新的宏定义:

make "LIBES= -LL -LS"

则命令行后面的宏定义将覆盖makefile 文件中的宏定义。若LL 也是库文件,此时make

令将连接三个目标文件以及两个库文件LS LL

Unix 系统中没有对常量NULL 作出明确的定义,因此我们要定义NULL 字符串时要

使用下述宏定义:

STRINGNAME=NULL

2 Make 命令

make 命令后不仅可以出现宏定义,还可以跟其他命令行参数,这些参数指定了需要

编译的目标文件。其标准形式为:

target1 [target2 …]:[:][dependent1 …][;commands][#…]

[(tab) commands][#…]

方括号中间的部分表示可选项。Targets dependents 当中可以包含字符、数字、句点

"/"符号。除了引用,commands 中不能含有"#",也不允许换行。

在通常的情况下命令行参数中只含有一个":",此时command 序列通常和makefile 文件

中某些定义文件间依赖关系的描述行有关。如果与目标相关连的那些描述行指定了相关的

command 序列,那么就执行这些相关的command 命令,即使在分号和(tab)后面的aommand

字段甚至有可能是NULL。如果那些与目标相关连的行没有指定command,那么将调用系

统默认的目标文件生成规则。

如果命令行参数中含有两个冒号"::",则此时的command 序列也许会和makefile 中所有

描述文件依赖关系的行有关。此时将执行那些与目标相关连的描述行所指向的相关命令。同

时还将执行build-in 规则。

如果在执行command 命令时返回了一个非"0"的出错信号,例如makefile 文件中出现了

错误的目标文件名或者出现了以连字符打头的命令字符串,make 操作一般会就此终止,但

如果make 后带有"-i"参数,则make 将忽略此类出错信号。

Make 命本身可带有四种参数:标志、宏定义、描述文件名和目标文件名。其标准形式

为:

Make [flags] [macro definitions] [targets]

Unix 系统下标志位flags 选项及其含义为:

-f file 指定 file 文件为描述文件,如果file 参数为"-"符,那么描述文件指向标准输入。

如果没有"-f"参数,则系统将默认当前目录下名为makefile 或者名为Makefile 的文件为描述

文件。在Linux 中, GNU make 工具在当前工作目录中按照GNUmakefilemakefileMakefile

的顺序搜索 makefile 文件。

-i 忽略命令执行返回的出错信息。

-s 沉默模式,在执行之前不输出相应的命令行信息。

-r 禁止使用build-in 规则。

-n 非执行模式,输出所有执行命令,但并不执行。

-t 更新目标文件。

-q make 操作将根据目标文件是否已经更新返回"0"或非"0"的状态信息。

-p 输出所有宏定义和目标文件描述。

-d Debug 模式,输出有关文件和检测时间的详细信息。

Linux make 标志位的常用选项与Unix 系统中稍有不同,下面我们只列出了不同部分:

-c dir 在读取 makefile 之前改变到指定的目录dir

-I dir 当包含其他 makefile 文件时,利用该选项指定搜索目录。

-h help 文挡,显示所有的make 选项。

-w 在处理 makefile 之前和之后,都显示工作目录。

通过命令行参数中的target ,可指定make 要编译的目标,并且允许同时定义编译多个

目标,操作时按照从左向右的顺序依次编译target 选项中指定的目标文件。如果命令行中没

有指定目标,则系统默认target 指向描述文件中第一个目标文件。

通常,makefile 中还定义有 clean 目标,可用来清除编译过程中的中间文件,例如:

clean:

rm -f *.o

运行 make clean 时,将执行 rm -f *.o 命令,最终删除所有编译过程中产生的所有中间

文件。

3 隐含规则

make 工具中包含有一些内置的或隐含的规则,这些规则定义了如何从不同的依赖文

件建立特定类型的目标。Unix 系统通常支持一种基于文件扩展名即文件名后缀的隐含规则。

这种后缀规则定义了如何将一个具有特定文件名后缀的文件(例如.c 文件),转换成为具有

另一种文件名后缀的文件(例如.o 文件):

.c:.o

$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

系统中默认的常用文件扩展名及其含义为:

print: $(FILES)

pr $? | $P

touch print

test:

make -dp | grep -v TIME>1zap

/usr/bin/make -dp | grep -v TIME>2zap

diff 1zap 2zap

rm 1zap 2zap

lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c

$(LINT) dosys.c donamc.c file.c main.c misc.c version.c /

gram.c

rm gram.c

arch:

ar uv /sys/source/s2/make.a $(FILES)

----------------------------------------------------------

通常在描述文件中应象上面一样定义要求输出将要执行的命令。在执行了make 命令之

后,输出结果为:

$ make

cc -c version.c

cc -c main.c

cc -c donamc.c

cc -c misc.c

cc -c file.c

cc -c dosys.c

yacc gram.y

mv y.tab.c gram.c

cc -c gram.c

cc version.o main.o donamc.o misc.o file.o dosys.o gram.o /

-LS -o make

13188+3348+3044=19580b=046174b

最后的数字信息是执行"@size make"命令的输出结果。之所以只有输出结果而没有相应

的命令行,是因为"@size make"命令以"@"起始,这个符号禁止打印输出它所在的命令行。

描述文件中的最后几条命令行在维护编译信息方面非常有用。其中"print"命令行的作用

是打印输出在执行过上次"make print"命令后所有改动过的文件名称。系统使用一个名为

print 0 字节文件来确定执行print 命令的具体时间,而宏$?则指向那些在print 文件改动过

之后进行修改的文件的文件名。如果想要指定执行print 命令后,将输出结果送入某个指定

的文件,那么就可修改P 的宏定义:

make print "P= cat>zap"

大多数自由软件提供的是源代码,而不是现成的可执行文件,这就要求用户根据自己系

统的实际情况和自身的需要来配置、编译源程序后,软件才能使用。

 

你可能感兴趣的:(unix,command,application,工具,makefile,编译器)