一个工程中的源文件可能不少,按照类型、功能、模块分别放在若干个目录中,为了有效地管理软件工程,更高效地编译整个工程,须要用到makefile 和 make 命令工具。Linux 程序员须学会写makefile,使用GNU make 来构建和管理本身的软件工程,利用makefile 进行编译,已成为了一种在工程方面的常见编译方法。makefile 带来的好处是“自动化编译”,一旦写好,只须要一个make 命令,整个工程彻底自动编译,极大提升软件开发的效率。html
Target:Dependencies (tab)命令 (tab)命令
例如:前端
prinA.cpp 包含prinA.h程序员
printB.cpp 包含printB.h函数
main.cpp 包含printA.h printB.h工具
makefile:优化
main:main.o printA.o printB.o g++ -o main main.o printA.o printB.o main.o:main.cpp g++ -c main.cpp printA.o:printA.cpp g++ -c printA.cpp pritnB.o:printB.cpp g++ -c printB.cpp .PHONY : clean clean: rm *.o main
“.PHONY”表示,clean是个伪目标文件。debug
执行:makecode
g++ -c -o main.o main.cpp
g++ -c -o printA.o printA.cpp
g++ -c -o printB.o printB.cpp
g++ -o main main.o printA.o printB.ohtm
生成 main.o pritnA.o printB.o mainblog
执行:make clean
rm *.o main
删除 全部后缀为.o的文件 和 main 文件
GNU的make很强大,它能够自动推导文件以及文件依赖关系后面的命令,因而咱们就不必去在每个 .o 文件后都写上相似的命令,由于,咱们的make会自动识别,并本身推导命令。
利用make的自动推导,能够把makefile 简化
简化版makefile:
main:main.o printA.o printB.o g++ -o main main.o printA.o printB.o .PHONY : clean clean: rm *.o main
只要make 看到一个.o文件,它就会自动把其依赖项.c/.cpp 加在依赖关系中,而且推导出命令:
gcc/g++ -c -o .o .c/.cpp
执行make,即可以看到推导和编译结果:
g++ -c -o main.o main.cpp
g++ -c -o printA.o printA.cpp
g++ -c -o printB.o printB.cpp
g++ -o main main.o printA.o printB.o
要设定一个变量,只要在一行的前端写下这个变量的名字,后面跟一个"=" 号,后面跟要是设定的这个变量的值就可.之后要引用这个变量,只写一个"$"符号,后面是在括号里的变量名便可.
在makefile中使用变量:
OBJS = main.o printA.o printB.o XX = g++ CC = gcc CFLAGS = -Wall -g -O TARGET = main $(TARGET):$(OBJS) $(XX) -o $(TARGET) $(CFLAGS) $(OBJS) .PHONY :clean clean: rm $(TARGET) $(OBJS)
CFLAGS = -Wall -g -O: 配置编译器设置,并把它复制给CFLAGS变量,其中每一个部分含义为:
- -Wall :输出全部警告信息
- -O: 编译时进行优化
- -g:即是编译debug版本
亦可以使用经常使用的内部变量:
- $@:扩展成当前规则的目的文件名
- $<:扩展成依靠列表中的第一个依靠文件
- $^:扩展成整个依靠的列表
使用内部变量makefile:
OBJS = main.o printA.o printB.o XX = g++ CC = gcc CFLAGS = -Wall -g -O TARGET = main $(TARGET):$(OBJS) $(XX) -o $@ $(CFLAGS) $^ .PHONY :clean clean: rm $(TARGET) $(OBJS)
$(wildcard PATTERN...)
在makefile 中,它被展开为已经存在的,使用空格分开的,匹配此模式的全部文件列表.若是不存在任何符合此模式的文件,函数会忽略模式字符并返回空
例子:
SOURCES = $(wildcard *.c *.cpp)
表示产生一个全部以.c .cpp 结尾的文件列表,而后存入变量SOURCES里
(patsubst %.src , %.dst , $(dir))
表示用patsubst 把$(dir)中的变量符合后缀是 .src 所有替换成 .dst
例子:
$(patsubt %.c, %o,$(patsubt %.cpp, %.o $(SOURCES)))
这是一个嵌套使用,表示先把 $(SOURCES)中后缀符合为.cpp 的所有替换成.o,而后再从中把后缀符合为.c 的所有替换成 .o
总体实现把 $(SOURCES)中后缀符合为.c 和.cpp 的所有替换成.o
字符 '%' 的意思是匹配零或若干个字符
使用函数的makefile:
XX = g++ CC = gcc CFLAGS = -Wall -g -O TARGET = main SOURCES = $(wildcard *.cpp ) OBJS = $(patsubst %.cpp,%.o, $(SOURCES)) $(TARGET):$(OBJS) $(XX) -o $@ $(CFLAGS) $^ .PHONY :clean clean: rm $(TARGET) $(OBJS)
注:以上假定全部的文件都在同一个目录下,且没有子目录
在作项目时,通常文件都会分几个目录来存放:
include/ bin/ src/ obj/ lib/ tools/
笔者习惯建工程时,建立前面4个目录
mkdir include bin src obj
include/ 存放头文件
bin/ 存放可执行文件
obj/ 存放后缀为.o 的文件
src/ 存放.c 和.cpp 的源文件
多文件目录工程管理的makefile:
BIN = ./bin SRC = ./src OBJ = ./obj INCLUDE =./include SOURCES = $(wildcard $(SRC)/*.cpp ) #要加notdir,去掉选定源文件的目录,不然替换会出错 OBJS = $(patsubst %.cpp,$(OBJ)/%.o, $(notdir $(SOURCES))) TARGET = $(BIN)/main XX = g++ #-I$(INCLUDE) :$(INCLUDE)下寻找头文件 CFLAGS = -Wall -g -I$(INCLUDE) #用全部的.o文件生成目的可执行文件 $(TARGET):$(OBJS) $(XX) -o $@ $^ #生成各个.o 文件 $(OBJ)/%.o:$(SRC)/%.cpp $(XX) -c $(CFLAGS) -o $@ $< .PHONY :clean clean: rm $(TARGET) $(OBJS)
转载请注明原文出处:
http://www.cnblogs.com/pz-Feng/p/8289410.html
如有错误不当之处,望你们指正,谢谢!