基本Makefile
假设现在有3个文件,file2.h是函数声明,file2.c是函数定义,文件file1.c调用file2.c中的函数。则Makefile文件的编写如下:
helloworld:file1.o file2.o gcc file1.o file2.o -o helloworld file1.o:file1.c file2.h gcc -c file1.c -o file1.o file2.o:file2.c file2.h gcc -c file2.c -o file2.o clean: rm -rf *.o helloworld
2 自动推导
helloworld:file1.o file2.o gcc file1.o file2.o -o helloworld %.o:%.c gcc -c $< -o $@ clean: rm -rf *.o helloworld
3 变量使用
CC= gcc CFLAGS= -I/home/mymakefile/include LDFLAGS= -L/home/mymakefile/lib LIBS = -lsocket -lmath CFLAGS= -g -Wall -O2 #PATH = /path/to/bin SRCS=file1.c file2.c OBJS=file1.o file2.o TARGET=helloworld $(TARGET):$(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(TARGET) %.o:%.c $(CC) -c $< -o $@ clean: rm -rf $(OBJS) $(TARGET)
4 特殊符号使用
这里$^因为会包含依赖的文件名,如果包含的该文件存在,那么将返回其含路径的文件名
所以$(wildcard $^)就是用来过滤$^包含的所有文件并且该文件确实在本地存在.
自动化变量$?代表依赖文件列表中被改变过的所有文件。
自动化变量$^代表所有通过目录搜索得到的依赖文件的完整路径名(目录 + 一般文件名)列表。
自动化变量$@代表规则的目标。
自动化变量$<代表规则中通过目录搜索得到的依赖文件列表的第一个依赖文件。
自动化变量$(@D)
5 关键词使用
wildcard
subst
用法是$(subst FROM,TO,TEXT),即将TEXT中的东西从FROM变为TO
TARGETS = 111.cpp 222.cpp 333.cpp
OTARGETS= $(subst cpp,o,$(TARGETS))
LTARGETS= $(subst cpp,lo,$(TARGETS))
patsubst <pattern>,<replacement>,<text> )
(patsubst %.c,%.o,x.c.c bar.c)
把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”
$(wildcard PATTERN...) 。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。
可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。
filter
6 选项使用
7 进入子目录
在学习Makefile过程中,一般是Makefile文件和源码、头文件存放在同一个目录中,但对于我们实际的工作过程中,通常是分开的。分开主要有两种方式,一种是根据模块,一种是根据文件的不同。如下面两图:
对于第一种,按照文件类型进行划分代码,只需要一个Makefile文件就可以,具体的形式如下所示:
1 ########################################### 2 # Makefile 3 # By Guo Jianwei 4 # 2014-8-26 5 # EMAIL: gjianw217@163.com 6 ########################################### 7 NAME = app 8 BIN = bin/debug/$(NAME) 9 10 CC = gcc 11 CXX = g++ 12 13 LINKOPT = -O3 14 FLAGS = $(LINKOPT) 15 16 LIBS = 17 CFLAGS = $(LIBS) 18 CXXFLAGS = $(LIBS) -g 19 20 INCS = -I$(INCPATH)/common\ 21 -I$(INCPATH)/third-party 22 23 SRCPATH = src/ 24 INCPATH = include 25 26 SRCS = $(shell find $(SRCPATH) -name '*.c' -o -name '*.cpp' \ 27 -o -name '*.cc' \ 28 | grep -v 'socket') 29 30 OBJS = $(filter %.o,$(SRCS:%.c=%.c.o)) 31 OBJS += $(filter %.o,$(SRCS:%.cpp=%.cpp.o)) 32 OBJS += $(filter %.o,$(SRCS:%.cc=%.cc.o)) 33 34 .PHONY: clean print 35 36 all: print $(BIN) 37 38 print: 39 @echo "====================================================" 40 @echo " $(BIN)" 41 @echo "====================================================" 42 43 $(BIN): $(OBJS) 44 $(CXX) $(FLAGS) -o $@ $^ 45 46 %.c.o: %.c 47 $(CXX) $(CFLAGS) $(INCS) -o $@ -c $^ 48 49 %.cpp.o: %.cpp 50 $(CXX) $(CXXFLAGS) $(INCS) -o $@ -c $^ 51 52 %.cc.o: %.cc 53 $(CXX) $(CXXFLAGS) $(INCS) -o $@ -c $^ 54 55 clean: 56 rm -rf $(BIN) $(OBJS)
对于第二种,按照功能进行组织代码,在每个功能模块中,都需要包含一个Makefile文件,具体的形式如下:
1 #Makefile 2 ########################################### 3 # Makefile 4 # By Guo Jianwei 5 # 2014-8-26 6 # EMAIL: gjianw217@163.com 7 ########################################### 8 OBJ=fun1/fun1.o\ 9 fun2/fun2.o\ 10 main.o 11 DEL=fun1/fun1.h\ 12 fun2/fun2.h 13 SRC=$(patsubst %.o,%.cpp,$(OBJ)) 14 TARGET=app 15 .PHONY:all fun1 fun2 app 16 all:fun1 fun2 app 17 fun1: 18 $(MAKE) -C fun1 19 fun2: 20 $(MAKE) -C fun2 21 $(TARGET):$(OBJ) 22 g++ -o $(TARGET) $(OBJ) $(DEL) 23 %.o:%.cpp 24 g++ -c $< $(DEL) 25 clean: 26 rm $(OBJ) $(TARGET) 27 28 ########################################### 29 #Makefile fun1 30 # By Guo Jianwei 31 # 2014-8-26 32 # EMAIL: gjianw217@163.com 33 ########################################### 34 OBJ=\ 35 fun1.o 36 DEP=\ 37 fun1.h 38 SRC=\ 39 fun1.cpp 40 $(OBJ):$(SRC) 41 @echo "fun1 fun1" 42 g++ -c $< $(DEP) 43 44 ########################################### 45 #Makefile fun2 46 # By Guo Jianwei 47 # 2014-8-26 48 # EMAIL: gjianw217@163.com 49 ########################################### 50 OBJ=fun2.o 51 DEP=$(patsubst %.o,%.h,$(OBJ)) 52 SRC=$(patsubst %.o,%.cpp,$(OBJ)) 53 CXX=g++ 54 CFLAGS= -O2 -c -Wall -g 55 #$(OBJ):$(SRC) 56 # $(CXX) $(CFLAGS) $< 57 $(OBJ):%.o:%.cpp 58 $(CXX) $(CFLAGS) $< $(DEP)