1. 没有makefile的日子

1.1 手动编译

1.2 文件编译依赖树 

2. 快速体验makefile

3. makefile 变量

4.  makefile条件编译

5. makefile函数

6. 参考资料 

<1>. 没有makefile的日子 

1.1 程序是如何编译的?

如果存在这么一个工程目录结构:

.
|-- foo.c
|-- foo.h
|-- main.c

如果想要编译上面的工程,在没有使用makefile的情况下,可能需要使用如下的编译命令:

xuqiang@ubuntu:~/makefile/program$ cc -c foo.c foo.h # 编译foo.o
xuqiang@ubuntu:~/makefile/program$ cc -c main.c foo.h # 编译main.o
xuqiang@ubuntu:~/makefile/program$ cc foo.o main.o -o nomakefile # 生成工程,需要依赖foo.o和main.o
xuqiang@ubuntu:~/makefile/program$ ls
foo.c  foo.h  foo.h.gch  foo.o  main.c  main.o  makefile  nomakefile

通过上面的命令生成nomakefile工程编译完成的文件。那么可能比较懒的程序员就在想这个很类似于一个批处理的过程,那么能不能将整个过程编写成脚本的形式,减少命令的输入,makefile就是用来将手动编译自动化的一个工具。 

1.2 文件编译依赖树

 查看上面的手动编译流程的话,为了生成nomakefile文件,需要存在foo.o文件和main.o文件,如果想要生成foo.o文件,需要编译foo.c,为了生成main.o,那么需要编译main.c文件,如此即生成一个所谓的文件编译依赖树:

 

通过手动编译文件的话,显然是将文件全部重新编译,在makefile中如果说依赖的文件没有更新的话,那么目标文件是不会重新编译的。 

<2>. 快速体验makefile 

还是上面例子如果使用makefile来管理,事情会变得如此简单,首先编写makefile文件:

 # makefile comment

OBJECTS=foo.o main.o
hellomakefile:${OBJECTS}
        cc ${OBJECTS} -o hellomakefile
foo.o:foo.c foo.h
        cc -c foo.c
        @echo "compile foo.c foo.h"
main.o:main.c foo.h
        cc -c main.c
clean:
        rm *.o
完成之后目录:

 .

|-- foo.c
|-- foo.h
|-- main.c
`-- makefile
在该目录下执行make命令,make将在当前目录中查找名为makefile或者是Makefile的文件,如果使用的不是这两个名字的话,需要使用make -f your-make-file-name,解析该文件,并生成二进制文件hellomakefile。

查看上面的makefile,可以看出:

1. makefile中可以使用#添加行注释

2.  makefile文件笼统的将是一个个规则的集合,每个规则是由目标开始,然后是该目标依赖的文件,下一行以tab键开始,然后是生成目标所需的命令。

目标:依赖文件,以空格隔开

生成目标文件的命令

3.  makefile在执行默认会将第一个目标做为最终目标,在这个文件就是hellomakefile,make在执行时将自动生成“最终目标”所依赖的文件,也就是main.o和foo.o文件。

4. makefile中可以定义变量(或者称之为宏),在程序的其他部分中使用,这里也就是变量(宏) OBJECTS。

5. makefile中可以使用内建函数,例如上面中的@echo函数。 

<3>. makefile变量 

makefile中用户可以自定义变量,例如:OBJECTS=foo.o main.o,那么在下面的makefile中可以使用${OBJECTS}代替该变量定义的值(foo.o,main.o)。另外可以使用默认变量:

$@:表明的是目标文件名,例如在foo.o:foo.c foo.h中$@表示的就是foo.o

$<:表明的是目标所依赖的文件的第一个文件,例如在 foo.o:foo.c foo.h表明的是就是foo.c文件。

$?:表明的是所有比目标文件更新的文件的集合,其中使用空格个风格。对于  foo.o:foo.c foo.h,如果更新了foo.c文件,那么重新make时,将$?将显示foo.c。这里需要注意的是如果更新了foo.h文件,那么$?将显示foo.c和foo.h文件,主要原因是在foo.c文件中包含了foo.h文件。 

<4>. 条件编译 

makefile中可以使用类似于编程语言中的跳转命令,如果满足一定的条件,将执行一定的动作。常见的条件编译指令:

 ifeq(arg1, arg2) .. endif:如果arg1和arg2相等的话,将执行该区域中的内容。 

ifeq(arg1, arg2) .. endif:如果arg1和arg2不相等的话,将执行该区域内的内容。

 ifdef ARG .. endif:判定ARG变量是否已经定义

ifndef ARG .. endif:和ifdef相反

上面的语句可以和else一起来使用:

 ifneq ("same", "diff")

        @echo "same != diff"
else                        
        @echo "same == diff"
endif          

<5>. makefile函数 

makefile中可以使用内建函数,makefile中的内建函数大多是和字符串相关和目录相关函数。makefile中函数使用$(function-name function-arg),例如$(strip($(STR))),makefile中内建函数大多是和字符串相关的函数,常用函数:strip,finstring等,这些函数和高级语言中的string类的方法是极为类似的,具体可以参考[这里]。

<6>. 参考资料 

gun make

 

作者: qiang.xu 发表于 2011-05-06 19:27 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架