makefile入门
给一个简单的makefile,下面对其进行分析
.PHONY:clean #显示指定clean为伪目标
main:main.o add.o sub.o
gcc -Wall -g main.o add.o sub.o -o main
main.o:main.o
gcc -Wall -g -c main.c -o main.o
add.o:add.h add.c
gcc -Wall -g -c add.c -o add.o
sub.o:sub.h sub.c
gcc -Wall -g -c sub.c -o sub.o
clean:
rm -f main main.o add.o sub.o
makefile的基本操作
TARGET … : DEPENDENCIES …
COMMAND
(1)目标(TARGET)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如clean,也称为伪目标。目标可以有多个
(2)依赖(DEPENDENCIES)是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。
(3)命令(COMMAND)是make执行的动作(命令是shell命令或是可在shell下执行的程序)。注意:每个命令行的起始字符必须为TAB字符!
注意:如果DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心的内容
(4)makefile自动化变量
选项名 | 作用 |
---|---|
$@ | 规则的目标文件名 |
$< | 规则的第一个依赖文件名 |
$^ | 规则的所有依赖文件列表 |
#通过自动化变量,对上面的例子进行改写
.PHONY:clean #显示指定clean为伪目标
CC = gcc
CFLAGS = -Wall -g
BIN = main
OBJECTS = main.o add.o sub.o
$(BIN):$(OBJECTS)
$(CC) $(CFLAGS) S^ -o $@
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(BIN) $(OBJECTS)
(5)makefile编译多个可执行文件
模式规则:%.o:%.c
后缀规则:.c.o:
(6)make常用内嵌函数
函数调用的基本形式:$(function arguments)
函数调用 | 含义 | 例子 |
---|---|---|
$(wildcard PATTERN) | 当前目录下匹配模式的文件 | src=$(wildcard *.c) |
$(patsubst PATTERN,REPLACEMENT,TEXT) | 模式替换函数 | $(patsubst %.c,%.o,$src) 等价于$(src:.c=.o) |
shell函数 | 执行shell命令 | $(shell ls –d */)列出当前目录下的子目录 |
#使用make常用内嵌函数编写makefile
.PHONY:clean
CC = gcc
CFLAGS = -Wall -g
BIN = main
SUBDIR = $(shell ls -d */) #当前目录中的子目录,使用shell命令,将子文件夹保存到SUBDIR这个变量中
ROOTSRC = $(wildcard *.c) #当前目录下的所有.c文件,使用make自带的函数wildcard将当前文件夹中匹配到的.c文件保存到ROOTSRC这个变量中
ROOTOBJ = $(ROOTSRC:%.c=%.o) #当前目录下的.o文件,将ROOTSRC中的.c文件名列表替换为.o文件名,并将.o文件名列表保存到ROOTOBJ这个变量中
SUBSRC = $(shell find $(SUBDIR) -name '*.c') #子目录中所有.c文件,在子文件夹中查找所有.c文件,并将文件名列表保存到SUBOBJ中
SUBOBJ = $(SUBSRC:%.c=%.o) #子目录中所有.o文件
$(BIN):$(ROOTOBJ) $(SUBOBJ)
$(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)
(7)多级目录makefile
使用父目录下的makefile文件,编译子目录中的可执行文件
文件树如下
├── makefile
├── test1
│ ├── makefile
│ ├── test1
│ ├── test1.c
│ └── test1.o
└── test2
├── makefile
├── test2
├── test2.cpp
└── test2.o
#在子目录test1和test2中生成可执行文件test1、test2
SUBDIRS = test1 test2 # 父目录下的两个子目录test1 test2
.PHONY:default all clean $(SUBDIRS)
default:all
all clean:
$(MAKE) $(SUBDIRS) TARGET=$@ #$(MAKE)表示make命令,$@表示目标all或clean
$(SUBDIRS):
$(MAKE) -C $@ $(TARGET) #-C表示进入test1或test2目录
CC = gcc
BIN = test1
OBJS = test1.o
.PHONY:all clean print
all:print $(BIN)
print:
@echo "----- make all in $(PWD) -----" #$(PWD)表示当前工作路径
$(BIN):$(OBJS)
$(CC) $(OBJS) -o $@
%.o:%.c
$(CC) -c $<
clean:
@echo "---- make clean in $(PWD) -----"
rm -f $(BIN) $(OBJS)
CXX = g++
BIN = test2
OBJS = test2.o
CPPFLAGS= -Wall -g
.PHONY: all clean print
all:print $(BIN)
print:
@echo "----- make all in $(PWD) -----" #$(PWD)表示当前工作路径
$(BIN):$(OBJS)
$(CXX) $(CPPFLAGS) $(OBJS) -o $@
%.o:%.cpp
$(CXX) -c $<
clean:
@echo "---- make clean in $(PWD) -----"
rm -f $(BIN) $(OBJS)