在说Makefile 之前呢,我给大家介绍一种整理工程的好方法,这个方法会使你编写的项目结构一目了然!
在简历项目之前首先我们可以先建六个文件夹分别为: bin dist docs include lib src
bin文件夹里放我们的脚本文件,dist看名字我们也知道放垃圾文件,docs放我们的项目文档了,include放.h文件,lib放库文件,src就放我们的.c程序啦!
这方法虽然看起来没什么,但是如果真正用到开发项目的时候,你会发现它为我们节省了很多的时间来找我们需要的代码,所以,想成为高效的程序员,习惯要从开始养成哦~
大家都知道一般的程序都是由多个源文件编译链接而成的,对这么多的源文件处理就要用到Makefile来管理了!
makefile和源代码放在同一个目录下,当执行make时,编译器就会自动读取当前目录下的Makefile文件。
Makefile由一组规则组成,每条规则的格式都是:
target...:prerequisites...
command1
command2
....
例如:main:main.o add.o sub.o mul.o div.o
gcc main.o add.o sub.o mul.o div.o -o main
main是这条规则的目标target,main.o add.o sub.o mul.o div.o 是这条规则的条件。command1和command2是命令列表,这里注意了!!!!在Makefile中,命令列表中的每个命令必须以Tab开头啊!不能是空格。还有,第一条规则的目标我们称之为缺省目标,只要缺省目标更新了才算更显完成。
通常Makefile 都会有一个clean规则,用于清除编译过程中产生的二进制文件,保留源文件,正确写法类似于:
clean:
@echo"cleaning project
-rm main *.o
@echo "clean completed"
.PHONY:clean
clean 目标是一个约定俗称的名字,类似这样约定俗称的名字还有:all ,执行主要的编译工作,通常用作缺省目标。install,执行编译后的安装工作,把可执行文件、配置文件、文档等分别拷到不同的安装目录。clean,删除编译生成的二进制文件。distclean,不仅删除编译生成的二进制文件,也删除其他生成的文件。
为使Makefile写的更加简洁
这里介绍个makefile的隐式规则:如果一个目标在Makefile中的所有规则中都没有命令列表,make会尝试在内建的隐式规则数据库中查找适用的规则。(make的隐式规则可以用make -p打印出来),在隐式规则中要知道,$(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)都表示空,$@取值为规则中的目标,$<的取值为规则中的第一个条件
%.o:%.c是一种特殊的规则,称为模式规则 。
Makefile中关于变量的语法规则
用"=号"义makefile变量有利有弊,好处是我们可以把变量的值推迟到后面定义,坏处是可能写出我穷递归的定义(例如:A = $(B) B = $(A))。
用“:=”运算符在make时遇到变量定义时立即展开。例如:
x:=foo
y:=$(x)bar
all:
@echo "-$(y)-"
make后的结果y 的值是 foo bar。但是如果改成下面的例子y的值就是 bar。注意bar前面有空格
y:=$(x)bar
x:=foo
all:
@echo "-$(y)-"
注意的是:一个变量的定义从=后面的第一个非空白字符开始(从$(x)的$开始),包括后面的所有字符,直到注释或换行之前结束。“?=” 的用法直接看例子:foo ?= $(bar)的意思是,如果foo没有定义过,那么?= 相当与=,定义foo的值是$(bar),但不立即展开;如果先前已经定义了foo,则什么也不做,不会给foo重新赋值。
“+=”给变量追加值,直接看例子:object:=main.o
object += $(foo)
foo = foo.o bar.o
例子中 由于object是用 := 定义的, += 保持 := 的特性,object的值是main.o $(foo),立即展开得到main.o(这时foo还没有定义),所以main后面的空格该保留。
如果变量object没有定义过就直接赋值,那么+=相当于=。
常用的特殊变量有:
$@,表示规则中的目标。
$<,表示规则中的第一个条件。
$? ,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^ ,表示规则中的所有条件,组成一个列表,以空格分隔。
一下列举一些常用的变量
AR--静态库打包命令的名字,缺省值是ar
ARFLAGS--静态库打包命令的选项,缺省值是rv
AS--汇编器的名字,缺省值是as
ASFLAGS--汇编器的选项,没有定义
CC--C编译器的名字,缺省值是cc
CFLAGS--C编译器的选项,没有定义
CXX--C++编译器的名字,缺省值是g++
CXXFLAGS--C++编译器的选项,没有定义
CPP--C预处理器的名字,缺省值是$(CC) -E
CPPFLAGS--C预处理器的选项,没有定义
LD--链接器的名字,缺省值是ld
LDFLAGS--连接器的选项,没有定义
TARGET_ARCH--和目标平台相关的命令行选项,没有定义
OUTPUT_OPTION--输出的命令行选项,缺省值是-o$@
LINK.o--把.o文件链接在一起的命令行,缺省值是$(CC) $(LDFLAGS) $(TARGET_ARCH)
LINK.c--把.c文件链接在一起的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
LINK.cc--把.cc文件(C++源文件)链接在一起的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
COMPILE.c--编译.c文件的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
COMPILE.cc--编译.cc文件的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
RM--删除命令的名字,缺省值是rm -f
在Makefile中使用函数!!!!!!!!!!!!!!!!!!!
首先我先说下注意事项,再把makefile的函数依依列出来,供以后参考
Makefile 里的函数跟它的变量很相似——使用的时候,你用一个$符合跟开括号,函数名,空格后面跟一列由逗号分隔的参数,最后用关括号结束。
函数调用语法:$(<function>;<arguments>;)或者是${<function>;<arguments>},其中<function>是函数名,<arguments>是函数的参数,参数之间以逗号隔开,函数名与参数之间用空格分开。函数和变量的括号最好一样。
好啦,下面我们要列举函数了,用到是查方便。
1》SOURCES = $(wildcard *.c)表示,所有以.c结尾的文件的列表,然后存入变量SOURCES里
字符串处理函数
2》$(subst <from>;,<to>;,<text>;)把字符串<text>中的<from>;字符串替换成<to>;。
3》$(patsubst <pattern>;,<replacement>;,<text>;)模式字符串替换函数。示例:$(patsubst %.c,%.o,x.cc bar.c)把字串“x.cc bar.c"符合模式[%.c]的单词替换成[%.o],返回结果是”x.c.o bar.o“
4》$(strip <string>;)去空格函数。去掉<string>;字串中开头和结尾的空格符。
5》$(findstring <find>;,<in>;)查找字符串函数。在字符串<in>;.中查找<find>;字串,如果找到返回<find>如果没有找到返回空字符串。
6》$(filter <pattern...>;,<text>;)过滤函数,返回符合模式<pattern>;的字串。例子:sources:=foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
其中(filter %.c %.s,$(sources))的返回值是"foo.c bar.c baz.s"。
7》$(filter-out <pattern...>;,<text>;)反过滤函数
8》$(sort <list>;)排序函数——sort。给字符串<list>;中的单词排序(升序).备注:sort函数会去掉<list>;中相同单词。
文件名操作函数
9》$(dir <names...>;)取目录函数——dir。功能;从文件名序列<names>;中取出目录部分。目录部分是指最后一个反斜杠(”/“)之前的部分。如果没有反斜杠,那么返回”./“。例子:$(dir src/foo.c hacks)返回值是"src/ ./"。
10》$(notdir <names...>;取文件函数:从文件名序列<names>;中取出非目录部分。非目录部分是最后一个反斜杠之后的部分。例子:$(notdir src/foo.c hacks)返回值是“foo.c hacks"。
11》$(suffix <names...>;)取后缀函数suffix。从文件名序列<names>;中取出各文件名的后缀。如果文件没有后缀就返回空字串。例子:$(suffix src/foo.c src1.c hacks)返回值是”.c .c“
12》$(basename <name...>;)取前缀函数。取出各文件名的前缀部分。例子$(basename src/foo.c src1.c hacks)返回值是“src/foo src1 hacks"。
13》$(addsuffix <suffix>;,<names...>;)加后缀函数,把<suffix>加到<names>中的每个单词后面。
14》$(addprefix <prefix>;,<names...>;)加前缀函数。
15》$(join <list1>;,<list2>;)连接函数,返回连接后的函数,功能是:把<list2>;中的单词对应的加到<list1>;的单词后面。如果<list1>;的单词个数要比<list2>;的多,那么,<list1>;中的多出来的单词将保持原样。反之,<list2>中多出来的单词将被复制到<list2>;中。例子:$(join aaa bbb ,111 2222 3333)返回“aaa111 bbb2222 3333"