makefile

转自:https://blog.csdn.net/runfarther/article/details/50036115

https://www.cnblogs.com/Shirlies/p/4282182.html

https://www.cnblogs.com/pied/archive/2012/11/02/2751476.html

Makefile

我们用gcc编译程序时,可能会用到“-I”(大写i),“-L”(大写l),“-l”(小写l)等参数,下面做个记录:
例:
gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld
上面这句表示在编译hello.c时:

-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include

-L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找的顺序是:/home/hello/lib-->/lib-->/usr/lib-->/usr/local/lib

 -lworld表示在上面的lib的路径中寻找libworld.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libworld.a静态库文件)

 

make中规定每一Shell命令之前的开头必须使用<tab>字符。

https://blog.csdn.net/shallnet/article/details/37657597

 

添加.PHONY:clean 

如果没有,则如果目录下clean文件冲突,无法执行make clean 

PHONY是一个伪目标,可以防止在Makefile中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,另一种是提交执行makefile时的效率。

更多关于.PHONY的知识请看http://www.cnblogs.com/chenyadong/archive/2011/11/19/2255279.html

 

Makefile示例:

对上面的代码,在不用Makefile时,我们可以直接用命令行来编译,得到我们的可执行程序main.out:

[plain] view plain copy

1. g++ -c main.c   

2. g++ -c line1.c   

3. g++ -c line2.c   

4. g++ -o main.out main.o line1.o line2.o  

为了编译工作更加方便,我们通常会编写Makefile来完成编译,我们先看一个用于编译和链接上面代码的例子:

[plain] view plain copy

1. main.out:main.o line1.o line2.o  

2.     g++ -o main.out main.o line1.o line2.o  

3. main.o:main.c line1.h line2.h  

4.     g++ -c main.c  

5. line1.o:line1.c line1.h  

6.     g++ -c line1.c  

7. line2.o:line2.c line2.h  

8.     g++ -c line2.c  

从例子可以看出,Makefile一般的格式是:

[html] view plain copy

1. target:components   

2.     rule  

第一行表示的是依赖关系,第二行是规则,特别要注意,rule这行必须是TAB键开头。

比如说我们上面的那个Makefile文件的前面二行:

[plain] view plain copy

1. main.out:main.o line1.o line2.o  

2.     g++ -o main.out main.o line1.o line2.o  

表示我们的目标(target)main.out的依赖对象(components)是main.o line1.o line2.o,当依赖的对象在被修改的话,就要去执行规则一行所指定的命令g++ -o main.out main.o line1.o line2.o。注意规则这行是以一个TAB键开头。

接下来我来介绍下Makefile中的四个有用的特殊符号意义和使用,他们分别是@、$@、$^、$<

一、@

这个符串通常用在“规则”行中,表示不显示命令本身,而只显示它的结果,例如Makefile中的内容为:

[plain] view plain copy

1. DIR_OBJ=./obj  

2. CMD_MKOBJDIR=if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi  

3.   

4. mkobjdir:  

5.     @${CMD_MKOBJDIR}  

命令行执行如下:

[html] view plain copy

1. make mkobjdir  

此时不会显示在命令行不会显示出if [ -d ${DIR_OBJ} ]; then exit 0; else mkdir ${DIR_OBJ}; fi,但如果规则行的TAB后没有以@开头,则会显示,不信可以试试。

二、$@、$^、$<

这三个分别表示:

$@          --代表目标文件(target)

$^            --代表所有的依赖文件(components)

$<           --代表第一个依赖文件(components中最左边的那个)。

好了,知道了他们的意义后,如果使用上面三个变量,那么简化的Makefile文件为:

[plain] view plain copy

1. main.out:main.o line1.o line2.o  

2.     g++ -o $@ $^  

3. main.o:main.c line1.h line2.h  

4.     g++ -c $<  

5. line1.o:line1.c line1.h  

6.     g++ -c $<  

7. line2.o:line2.c line2.h  

8.     g++ -c $<  

当然,还可以进一步简化,有兴趣可以再去研究下,这里就不展示了。

------------------递归编译所有C文件------------

多文件目录下makefile文件递归执行编译所有c文件

首先说说本次嵌套执行makefile文件的目的:只需make根目录下的makefile文件,即可编译所有c文件,包括子目录下的。

意义:自动化编译行为,以后编译自己的c文件时可把这些makefile文件直接复制到相应目录即可方便编译出所有文件。这些makefile文件是通用的,只需根据自己的工程情况改动少许内容即可。下面会说。

总体思路是:把目标文件放在debug文件夹下的obj目录下,把最终的二进制文件放在debug文件夹下的bin目录下;如何递归编译所有除了debug目录下的makefile文件呢:获得当前目录下的所有子目录,执行子目录下的makefile文件;获取当前目录下的所有c文件,编译c文件并放到指定的目标文件夹下。最后再执行debug目录下的makefile文件生成bin文件。

注意:除了debug文件夹比较特殊外,其他的子目录下都需要有Makefile文件,而且这些Makefile是相同的,除了根目录下的makefile文件有些不同外。即除了bin和obj目录以外的其他目录都需要Makefile文件,即使目录下没有c文件或者其他目录。

过程:首先在根目录下新建一个debug文件夹,debug文件夹下有bin目录和obj目录和一个Makefile文件,结构如下图。(这个debug文件里的makefile文件需要最后执行)(tree工具需要自己安装的,ubuntu下直接输入sudo apt-get install tree即可,但有时可能需要先sudo apt-get update才行)

 

整个目录结果如下图:

 

然后在根目录下新建Makefile文件,根目录下也可能会有c文件,故也需处理根目录下的c文件,内容如下:

 

#设置编译器

CC=gcc

#debug文件夹里的makefile文件需要最后执行,所以这里需要执行的子目录要排除debug文件夹,这里使用awk排除了debug文件夹,读取剩下的文件夹

SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "debug") print $$9}')

#无需下一行的注释代码,因为我们已经知道debug里的makefile是最后执行的,所以最后直接去debug目录下执行指定的makefile文件就行,具体下面有注释

#DEBUG=$(shell ls -l | grep ^d | awk '{if($$9 == "debug") print $$9}')

#记住当前工程的根目录路径

ROOT_DIR=$(shell pwd)

#最终bin文件的名字,可以更改为自己需要的

BIN=myapp

#目标文件所在的目录

OBJS_DIR=debug/obj

#bin文件所在的目录

BIN_DIR=debug/bin

#获取当前目录下的c文件集,放在变量CUR_SOURCE

CUR_SOURCE=${wildcard *.c}

#将对应的c文件名转为o文件后放在下面的CUR_OBJS变量中

CUR_OBJS=${patsubst %.c, %.o, $(CUR_SOURCE)}

#将以下变量导出到子shell中,本次相当于导出到子目录下的makefile

export CC BIN OBJS_DIR BIN_DIR ROOT_DIR

#注意这里的顺序,需要先执行SUBDIRS最后才能是DEBUG

all:$(SUBDIRS) $(CUR_OBJS) DEBUG

#递归执行子目录下的makefile文件,这是递归执行的关键

$(SUBDIRS):ECHO

    make -C $@

DEBUG:ECHO

    #直接去debug目录下执行makefile文件

    make -C debug

ECHO:

    @echo $(SUBDIRS)

#c文件编译为o文件,并放在指定放置目标文件的目录中即OBJS_DIR

$(CUR_OBJS):%.o:%.c

    $(CC) -c $^ -o $(ROOT_DIR)/$(OBJS_DIR)/$@

CLEAN:

    @rm $(OBJS_DIR)/*.o

    @rm -rf $(BIN_DIR)/*

 

上面的注释很详细了,具体的命令如果不清楚,自己可以google一下,譬如:wildcard patsubst awk等

读者可以根据自己的需要更改自己的debug目录和目标文件目录和bin文件目录

其他子目录下的Makefile文件的内容如下:

 

 1 #子目录的Makefile直接读取其子目录就行 2 SUBDIRS=$(shell ls -l | grep ^d | awk '{print $$9}') 3 #以下同根目录下的makefile的相同代码的解释 4 CUR_SOURCE=${wildcard *.c} 5 CUR_OBJS=${patsubst %.c, %.o, $(CUR_SOURCE)} 6 all:$(SUBDIRS) $(CUR_OBJS) 7 $(SUBDIRS):ECHO 8     make -C $@ 9 $(CUR_OBJS):%.o:%.c10     $(CC) -c $^ -o $(ROOT_DIR)/$(OBJS_DIR)/$@11 ECHO:12     @echo $(SUBDIRS)

 

debug目录下的Makefile文件如下:

1 OBJS=*.o2 ODIR=obj3 $(ROOT_DIR)/$(BIN_DIR)/$(BIN):$(ODIR)/$(OBJS)4     $(CC) -o $@ $^

最后只需在根目录下,我的是我的根目录makefile目录下,执行make命令即可:

 

结果目录结果为:

 

然后执行". debug/bin/myapp"即可;最后可以执行make CLEAN清楚掉所有的目标文件和bin文件。

参考资料为:http://blog.csdn.net/zplove003/article/details/7066595

关于makefile文件的编写,见一下链接:跟我一起写makefilehttp://wiki.ubuntu.org.cn/index.php?title=%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile&variant=zh-cn

---------------------makefile宏及例子-------------------

notdir,wildcard和patsubst是makefile中几个有用的函数,以前没留意过makefile中函数的用法,今天稍微看看~

 

1、makefile里的函数

makefile里的函数使用,和取变量的值类似,是以一个‘$’开始,然后是一个括号里面是函数名和需要的参数列表,多个变量用逗号隔开,像这样

return = $(functionname  arg1,arg2,arg3...)。

可能这里的'$'更像是从某个地址取值类似的操作。

 

2、 wildcard

使用:SRC = $(wildcard *.c ./foo/*.c) 

搜索当前目录及./foo/下所有以.c结尾的文件,生成一个以空格间隔的文件名列表,并赋值给SRC.当前目录文件只有文件名,子目录下的文件名包含路径信息,比如./foor/bar.c。

 

3、notdir

使用:SRC = $(notdir wildcard)

去除所有的目录信息,SRC里的文件名列表将只有文件名。

 

4、patsubst

使用:OBJ = $(patsubst %.c %.o $(SRC)) 

patsubst是patten substitude的缩写,匹配替代的意思。这句是在SRC中找到所有.c 结尾的文件,然后把所有的.c换成.o。

 

传说中的万能makefile

 

########################################################### 
#Genericmakefile 
# 
#byGeorgeFoot 
#email:george.foot@merton.ox.ac.uk 
# 
#Copyright(c)1997GeorgeFoot 
#Allrightsreserved. 
# 保留所有版權  
# 
#Nowarranty,noliability; 
#youusethisatyourownrisk. 
# 沒保險,不負責  
# 你要用這個,你自己擔風險  
# 
#Youarefreetomodifyand 
#distributethiswithoutgiving 
#credittotheoriginalauthor. 
# 你可以隨便更改和散發這個文件  
# 而不需要給原作者什榮譽。  
# (你好意思?)  
# 
###################################### 

###Customising 

#Adjustthefollowingifnecessary;EXECUTABLEisthetarget 
#executable'sfilename,andLIBSisalistoflibrariestolinkin 
#(e.g.alleg,stdcx,iostr,etc).Youcanoverridetheseonmake's 
#commandlineofcourse,ifyouprefertodoitthatway. 
# 
# 如果需要,調整下面的東西。 EXECUTABLE 是目標的可執行文件名, LIBS 
# 是一個需要連接的程序包列表(例如 alleg,stdcx,iostr 等等)。當然你 
# 可以在 make 的命令行覆蓋它們,你願意就沒問題。 
# 

EXECUTABLE:=mushroom.exe 
LIBS:=alleg 

#Nowalteranyimplicitrules'variablesifyoulike,e.g.: 

# 現在來改變任何你想改動的隱含規則中的變量,例如 

CFLAGS:=-g-Wall-O3-m486 
CXXFLAGS:=$(CFLAGS) 

#Thenextbitcheckstoseewhetherrmisinyourdjgppbin 
#directory;ifnotitusesdelinstead,butthiscancause(harmless) 
#`Filenotfound'errormessages.IfyouarenotusingDOSatall, 
#setthevariabletosomethingwhichwillunquestioninglyremove 
#files. 

# 下面先檢查你的 djgpp 命令目錄下有沒有 rm 命令,如果沒有,我們使用 
#del 命令來代替,但有可能給我們 'Filenotfound' 這個錯誤信息,這沒 
# 什大礙。如果你不是用 DOS ,把它設定成一個刪文件而不廢話的命令。 
# (其實這一步在 UNIX 類的系統上是多余的,只是方便 DOS 用戶。 UNIX 
# 用戶可以刪除這5行命令。) 

ifneq($(wildcard$(DJDIR)/bin/rm.exe),) 
RM-F:=rm-f 
else 
RM-F:=del 
endif 

#Youshouldn'tneedtochangeanythingbelowthispoint. 

# 從這裡開始,你應該不需要改動任何東西。(我是不太相信,太NB了!) 

SOURCE:=$(wildcard*.c)$(wildcard*.cc) 
OBJS:=$(patsubst%.c,%.o,$(patsubst%.cc,%.o,$(SOURCE))) 
DEPS:=$(patsubst%.o,%.d,$(OBJS)) 
MISSING_DEPS:=$(filter-out$(wildcard$(DEPS)),$(DEPS)) 
MISSING_DEPS_SOURCES:=$(wildcard$(patsubst%.d,%.c,$(MISSING_DEPS))
$(patsubst%.d,%.cc,$(MISSING_DEPS))) 
CPPFLAGS+=-MD 

.PHONY:everythingdepsobjscleanverycleanrebuild 

everything:$(EXECUTABLE) 

deps:$(DEPS) 

objs:$(OBJS) 

clean
@$(RM-F)*.o 
@$(RM-F)*.d 

veryclean:clean 
@$(RM-F)$(EXECUTABLE) 

rebuild:verycleaneverything 

ifneq($(MISSING_DEPS),) 
$(MISSING_DEPS)
@$(RM-F)$(patsubst%.d,%.o,$@) 
endif 

-include$(DEPS) 

$(EXECUTABLE):$(OBJS) 
gcc-o$(EXECUTABLE)$(OBJS)$(addprefix-l,$(LIBS)) 
###

 

——————

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值