Makefile

来源:互联网 发布:郑州市网络监督局电话 编辑:程序博客网 时间:2024/06/14 07:23
前言:makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
一、gcc
1、基本命令
预处理(展开头文件) :gcc -E xxx.c -o xxx.i
编译(生成汇编代码) :gcc -S xxx.i -o xxx.s
汇编(生成目标文件) :gcc -c xxx.s -o xxx.o
链接(生成可执行文件):gcc xxx.o -o xxx
2、指定头文件目录(-I后面直接加路径)
gcc -c xxx.c -o xxx.o -I./include
3、指定宏(-D后面直接加宏)
gcc -c xxx.c -o xxx.o -DPLATEFORM_TYPE=0xF001
gcc -c xxx.c -o xxx.o -DNAME
4、release编译参数
gcc -c xxx.c -o xxx.o -Wall -Os
5、debug编译参数
gcc -c xxx.c -o xxx.o -Wall -g
6、链接成动态库
gcc -fPIC -shared -o libtest.so test.o
7、链接动态库生成可执行程序
假设要链接libtest.so
gcc main.c -o out -ltest -L.
-ltest:指定使用libtest.so库
-L.:指定libtest.so的路径
运行程序时,需要将libtest.so的路径添加到环境变量中。
8、链接静态库生成可执行程序(生成静态库请看第二条)
假设要链接libtest.a
gcc main.c -o out -ltest -L. -static
或者gcc main.c libtest.a -L. -o out
9、生成依赖关系.d文件
gcc -I./include -MM -MD -c test.c -o test.d
二、ar
1、生成成静态库
ar -rv libtest.a test.o
三、ld
ld是链接器,暂时不研究。
四、strip
strip 命令减少 XCOFF 对象文件的大小。strip 命令从 XCOFF 对象文件中有选择地除去行号信息、重定位信息、调试段、typchk 段、注释段、文件头以及所有或部分符号表。 一旦您使用该命令,则很难调试文件的符号;因此,通常应该只在已经调试和测试过的生成模块上使用 strip 命令。使用 strip 命令减少对象文件所需的存储量开销。
nm 命令查看符号信息。
例子: (假如out为未strip过的可执行程序)
ls -al out
nm out 
strip out
ls -al out
nm out
五、rm和cp
1、删除命令参数选项
rm -rf xxx
2、拷贝命令参数选项
cp -rf xxx xx
六、sed
1、简介
sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。
sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。
2、定址
定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。
地址是一个数字,则表示行号;是“$"符号,则表示最后一行。
例如:
只打印第三行:sed -n '3p' datafile
只查看文件的第100行到第200行:sed -n '100,200p' mysql_slow_query.log
地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。
例如:
删除第二到第五行:sed '2,5d' datafile
删除包含"My"的行到包含"You"的行之间的行:sed '/My/,/You/d' datafile
删除包含"My"的行到第十行的内容:sed '/My/,10d' datafile
3、命令与选项
sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。参考:http://www.cnblogs.com/edwardlost/archive/2010/09/17/1829145.html
七、patsubst、subst
1、patsubst
格式:$(patsubst <pattern>,<replacement>,<text>)
名称:模式字符串替换函数——patsubst。
功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
返回:函数返回被替换过后的字符串。
例子:$(patsubst %.c,%.o, test.c bar.c)
把字串”test.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是”test.o bar.o”
2、subst
格式:$(subst <from>,<to>,<text>)
名称:字符串替换函数——subst。
功能:把字串<text>中的<from>字符串替换成<to>。
返回:函数返回被替换过后的字符串。
例子:$(subst hello, hi, hello world !!!)
把字串“hello world !!!”中的”hello”替换成”hi”,返回结果是”hi world !!!”
八、makefile基本概念
1、make是什么
make 是一个根据指定的shell命令进行制作文件的工具.(make 就是要制作出某个或某些文件) make 有自己特定规则,可以自动识别大型项目中那些部分需要重新编译,并可以执行相对应的命令来重新编译之.
make 通常用于编译C程序,也可以编译其他语言的程序,前提是该语言的编译器使用shell命令.当然也可以用于非编译的情况.
make 的优点:简化编译命令,自动识别重新编译文件减少编译时间,便于扩展.
2、make和makefile的关系
make命令本身并不知道该如何做,需要有人告诉它如何来做。通常这些都写在一个叫做Makefile(makefile)的文件中,make命令依赖这个文件进行制作。
Makefile(makefile)文件是make命令缺省使用的文件,当然也可以用命令行参数指定其他文件。
比如:
$ make -f Rules.make
3、makefile基本规则
makefile由一些列的规则构成,每条规则如下:
target : prerequisites
[tab] recipe
target :目标,通常是输出文件名(可以是多个),也可以是某个特定操作的名字(伪目标)。
prerequisites :前提条件,通常是文件名,是用于创建目标的输入文件,可以理解为依赖关系。
recipe :动作,可以使多条命令,前面必须加tab,另外每一行对应一个动作(一条shell命令)。
例子:
makefile文件内容如下:
test : test1.o test2.o test3.o
[tab]gcc -o test test1.o test2.o test3.o
test1.o: test1.c test.h
[tab]gcc -c test1.c
test2.o: test2.c test.h
[tab]gcc -c test2.c
test3.o: test3.c
[tab]gcc -c test3.c -o test3.o
clean: 
[tab]rm -f test test1.o test2.o test3.o
注意:
(1)、依赖关系寻找测试
修改 test3.c后make
修改 test1.c后make
修改 test.h 后make
make clean 后make
(2)、执行make命令时,默认生成makefile中的第一个目标test
例子:调换规则test和test1.o后执行make
(3)、make后面可以加上目标名字,目标可以是多个。
例子:
$make test
$make test1.o test3.o
$make clean
4、makefile静态模式规则
targets : target-pattern: prereq-patterns …
[tab] recipe
targets :目标
target-pattern:目标的模式
prereq-patterns:前提条件的模式
recipe :命令
例子
objects = test1.o test2.o
all: $(objects)
$(objects): %.o: %.c
[tab]gcc -c $< -o $@
注意:$< 表示第一个前提条件 ,$@表示目标,后面会讲到。
例子相当于下面的内容
test1.o:test1.c
[tab]gcc -c $< -o $@
test2.o:test2.c
[tab]gcc -c $< -o $@
5、makefile隐含规则
target : prerequisites
没有recipe
例子:
test.o: test.c
相当于下面的内容(C语言编译规则)
test.o:test.c
[tab]gcc -c $< -o $@
例子:
test.o: test.cpp
相当于下面的内容(C++语言编译规则)
test.o:test.c
[tab]g++ -c $< -o $@
当然还有很多其他语言的隐含规则,这里就不细展开了,总之看到一个规则没有相应的动作也没有看到依赖关系,就要注意隐含规则了另外,隐含规则是和make相关的,不同版本的make是有差异的。
6、递归调用make
subsystem:
[tab]cd subdir && $(MAKE)
或者
subsystem:
[tab]$(MAKE) -C subdir
例子:
BASEDIR= .
SUBDIRS = $(BASEDIR)/test1 $(BASEDIR)/test2
all: $(SUBDIRS)
[tab]@for i in $(SUBDIRS); do make -C $$i || exit; done
[tab]#要注意上面必须是一行, 使用;分开多个命令。
九、makefile语法
1、include/-include(sinclude)
include:包含文件,如果文件不存在将会有错误提示。
-include(sinclude:GNU支持sinclude代替-include):包含文件,如果文件不存在则不会错误提示。
2、PHONY
.PHONY : clean
申明 clean是伪目标.
主要防止如果当前目录中,正好有一个文件叫做clean,执行make clean不能得到想要的动作。
3、 #
注释,和C++中的//一样
4、echo
显示。
5、@
make执行时不显示当前行
例子:
sample:
[tab]# sample
[tab]echo "sample" 
[tab]@ # sample 
[tab]@echo "sample"
$make sample
6、* (通配符, 还包括? /[…]/ ~)
例子
:clean:
[tab]rm -f *.o rm -f *.d
$make clean
7、%
%.o:%.c
表示有一系列的规则,规则的个数等于当前目录下.c文件的个数,而每个规则的目标都是以一个.c文件的文件名去掉c加上o构成,前提条件为该.c文件名。
等价于下面语句:
.c.o:
8、$@
规则中目标的名字
9、$<
规则中第一个前提条件的名字
例子:
dst/%.c:src/%.c
[tab]cp $< $@
10、$^
所有的前提条件
11、其他还有$?, $*,$(@D), $(@F),$(<D) , $(<F)...
以上这些又称为自动变量(Automatic Variables),具体代表什么就不展开了。
12、变量及赋值
VARIABLE = value:变量的值在执行时赋
VARIABLE := value:变量的值在定义时赋
VARIABLE ?= value:只有在该变量为空时才赋值
VARIABLE += value:将值追加到变量的尾端
例子:
BASEDIR = .
SUBDIRS = $(BASEDIR)/test1 $(BASEDIR)/test2
SUBDIRS += $(BASEDIR)/test3
13、export
例子
WORKDIR = .
export WORKDIR
14、条件
ifeq(arg1, arg2)/ifneq(arg1, arg2)
[tab]
else 
[tab]
endif
例子:
libs_for_gcc = …
normal_libs = …
ifeq ($(CC),gcc)
[tab]libs=$(libs_for_gcc)
else 
[tab]libs=$(normal_libs)
endif
foo: $(objects)
[tab]$(CC) -o foo $(objects) $(libs)
十、完整示例
一个test库与主函数的工程make示例。该示例中test库目录下有一个makefile,负责编译test库。根目录下有一个makefile,负责编译主函数及链接test库。test库的源文件修改头文件时不需要clean,直接make即可,因为makefile中已经添加了.d依赖文件。
(1)、文件结构如下:



Test目录下的makefile:
BASEDIR=.CPP   =   @echo " g++ $@"; g++CC    =   @echo " gcc $@"; gccLD    =   @echo " ld  $@"; ldAR    =  @echo " ar  $@"; arSTRIP =   @echo " strip $@"; stripRM    =   @rm -rfCP    =   @cp -rf#定义宏PRINT 5CFLAGS += -DPRINT=5#release编译选项CFLAGS += -Wall -Os#debug编译选项#CFLAGS += -Wall -g#指定头文件目录CFLAGS += -I$(BASEDIR)/Include#64位系统需要此参数CFLAGS += -fPIC #静态库编译参数AFLAGS = -rvSRCS = $(BASEDIR)/Src/Print1.c $(BASEDIR)/Src/Print2.cpp#字符串替换获取.o目标文件TMPOBJS = $(patsubst $(BASEDIR)/%.cpp, $(BASEDIR)/%.o, $(SRCS))OBJS = $(patsubst $(BASEDIR)/%.c, $(BASEDIR)/%.o, $(TMPOBJS))#字符串替换获取.d文件OBJD = $(patsubst $(BASEDIR)/%.o, $(BASEDIR)/%.d, $(OBJS))LIBTEST = $(BASEDIR)/Lib/libtest.aLIBTESTSO = $(BASEDIR)/Lib/libtest.soall: $(LIBTEST) $(LIBTESTSO)$(LIBTEST): $(OBJS)$(RM) $@$(AR) $(AFLAGS) $@ $^$(LIBTESTSO): $(OBJS)$(RM) $@$(CC) -fPIC -shared -o $@ $^%.o: %.c$(CC)  -c $(CFLAGS) $< -o $@%.o: %.cpp$(CPP)  -c $(CFLAGS) $< -o $@#sed的作用:给.d文件里的.o添加路径%.d: %.c$(CC) $(CFLAGS) -MM -MD -c $< -o $@@sed 's/.*\.o/$(subst /,\/,$(dir $@))&/g' $@ >$@.tmp@sed 's/ /\t/g' $@.tmp >$@@rm $@.tmp%.d: %.cpp$(CPP) $(CFLAGS) -MM -MD -c $< -o $@@sed 's/.*\.o/$(subst /,\/,$(dir $@))&/g' $@ >$@.tmp@sed 's/ /\t/g' $@.tmp >$@@rm $@.tmp#clean时不生成.d文件ifneq ($(MAKECMDGOALS), clean)-include $(OBJD)endif clean:$(RM) $(OBJS)$(RM) $(OBJD)$(RM) $(LIBTEST)$(RM) $(LIBTESTSO)
根目录下的makefile:
BASEDIR= .SUBDIRS = $(BASEDIR)/TestCPP   =   @echo " g++ $@"; g++CC    =   @echo " gcc $@"; gccLD    =   @echo " ld  $@"; ldAR    =  @echo " ar  $@"; arSTRIP =   @echo " strip $@"; stripRM    =   @rm -rfCP    =   @cp -rf#release编译选项CFLAGS += -Wall -Os#debug编译选项#CFLAGS += -Wall -g#指定头文件目录CFLAGS += -I$(BASEDIR)/Test/Include#64位系统需要此参数CFLAGS += -fPIC #静态库编译参数AFLAGS = -rvSRCS = $(BASEDIR)/Main/Main.cLIBS = $(BASEDIR)/Test/Lib/libtest.aDIST = $(BASEDIR)/out$(DIST): subdir$(CPP) $(SRCS) -o $@ $(CFLAGS) $(LIBS)$(STRIP) $@subdir: @for i in $(SUBDIRS); do make -C $$i || exit; doneclean: subdirclean$(RM) $(DIST)subdirclean:@for i in $(SUBDIRS); do make clean -C $$i || exit; done
工程下载地址:http://pan.baidu.com/s/1hsoZGFU

原创粉丝点击