您的位置:首页 > 其它

学习总结:工程管理与makefile

2018-01-15 21:35 393 查看


https://www.cnblogs.com/pz-Feng/p/8289410.html


工程管理与makefile


一、为什么需要makefile和make

一个工程中的源文件可能很多,按照类型、功能、模块分别放在若干个目录中,为了有效地管理软件工程,更高效地编译整个工程,需要用到makefile 和 make 命令工具。Linux 程序员须学会写makefile,使用GNU make 来构建和管理自己的软件工程,利用makefile 进行编译,已成为了一种在工程方面的常见编译方法。makefile 带来的好处是“自动化编译”,一旦写好,只需要一个make
命令,整个工程完全自动编译,极大提高软件开发的效率。


二、makefile 主要编写规则


2.1编写格式

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是个伪目标文件。
执行: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

生成 main.o pritnA.o printB.o main
执行:make clean

rm *.o main

删除 所有后缀为.o的文件 和 main 文件


2.2 让make 自动推导

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


2.3 使用变量

要设定一个变量,只要在一行的前端写下这个变量的名字,后面跟一个"=" 号,后面跟要是设定的这个变量的值就可.以后要引用这个变量,只写一个"$"符号,后面是在括号里的变量名即可.
在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)



2.4 使用函数 wildcard patsubst


wildcard 用法:

$(wildcard PATTERN...)


在makefile 中,它被展开为已经存在的,使用空格分开的,匹配此模式的所有文件列表.如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空
例子:

SOURCES = $(wildcard *.c *.cpp)


表示产生一个所有以.c .cpp 结尾的文件列表,然后存入变量SOURCES里


patsubst 用法:

(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)


注:以上假定所有的文件都在同一个目录下,且没有子目录


2.5 多目录下编译

在做项目时,一般文件都会分几个目录来存放:
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
若有错误不当之处,望大家指正,谢谢!

大作于细,业精于勤
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: