makefile使用方法
大约 5 分钟
makefile使用方法
使用方法
先建立一个名为makefile
或者是Makefile
的文件,然后在里面写入符合语法规则的编译命令,完成以后只需要在文件所在目录使用make
命令就能运行编译命令
书写规则
从第一行命令开始,先确认目标文件,根据目标文件确定所需的依赖文件,然后递归地找到依赖文件的依赖文件,直到依赖文件是没有子依赖文件
#注释 书写格式
[目标文件]:[依赖文件]
<tab>[command]
,即只有目标文件比依赖旧或者目标文件不存在,才会执行命令 原则
伪目标
以不会存在的文件名作为目标。make伪目标,命令会一直执行
make .PHONY #查看定义了哪些伪目标
make clean # 清除所有生成的目标文件和最终程序
make rebuild #重新编译
变量名
自定义变量:
变量名:=变量内容(字符串)
。$(变量名)
使用变量,实际上就是自动变量:变量内容会随着规则自动变化
变量 说明 $@ 目标文件 $< 第一个依赖文件 $^ 所有依赖文件,以空格分隔 $? 日期新于目标文件的所有相关文件列表,逗号分隔 $(@D) 目标文件的目录名部分 $(@F) 目标文件的文件名部分 预定义变量
变量名 | 功能 | 默认含义 |
---|---|---|
AR | 打包库文件 | ar |
AS | 汇编程序 | as |
CC | C编译器 | gcc |
CPP | C预编译器 | $(CC) -E |
CXX | C++编译器 | g++ |
RM | 删除 | rm –f |
ARFLAGS | 库选项 | 无 |
ASFLAGS | 汇编选项 | 无 |
CFLAGS | C编译器选项 | 无 |
CPPFLAGS | C预编译器选项 | 无 |
CXXFLAGS | C++编译器选项 | 无 |
= 和 := 的区别
使用 =
赋值的变量被称为递归展开变量。这可能导致变量的值在每次引用时都可能不同。
A = $(B)
B = Hello
all:
@echo $(A) # 输出 "Hello"
使用 :=
赋值的变量被称为直接展开变量。在赋值时就被展开,之后不会再次展开,因此变量的值在赋值后就固定不变。这也是工作当中的
A := $(B)
B = Hello
all:
@echo $(A) # 输出空行,因为A在赋值时B还未定义
通配符和模式匹配
使用bash的规则来应用通配符
clean:
rm -rf *.o
%
通配符
%表达式
可以作某个规则的目标(目标:上一个规则的依赖)CXX:=g++ out:=main objs:=main.o add.o $(out):$(objs) $(CXX) $^ -o $@ #main.o:main.c # $(CXX) -c $^ -o $@ #add.o:add.c # $(CXX) -c $^ -o $@ %.o:%.c $(CXX) -c $^ -o $@ #把main.o add.o用%.o匹配出来,再用%.c重新组合成main.c add.c
%表达式
根据变量内容生成新的内容srcs:= main.c add.c sub.c #objs:=main.o add.o sub.o objs:=$(srcs:%.c=%.o)
内置函数
# 格式
$([function] [arguments])
使用wildcard
函数可以使用通配符,找到所有满足通配符的文件名
srcfiles:=$(wildcard src/*.c)
使用subst
函数来实现文本替换
# 语法
$(subst from,to,text)
# 示例
ORIGINAL_TEXT := Hello, World!
REPLACED_TEXT := $(subst World,Makefile,$(ORIGINAL_TEXT)) #Hello, Makefile!
使用patsubst
函数来实现模式文本替换
$(patsubst pattern,replacement,text)
# 示例
SRCS := main.c util.c file.c
OBJS := $(patsubst %.c,%.o,$(SRCS))
循环
LIST:=one two three
all:
for i in $(LIST); do echo $$i; done
# 等价于
all:
for i in one two three; do echo $i; done
-f
指定makefile文件
make命令的有些时候makefile文件的名字不希望以makefile或者Makefile来命名,此时可以使用make命令的-f
参数来指定makefile文件
make -f newMake
示例
指定源文件生成一个可执行程序
# makefile目录下的指定源文件生成一个可执行程序
# 定义编译器
CC = gcc
# 定义源文件
SRCS = main.c util.c #指定源文件生成一个可执行程序
#SRCS:=$(wildcard *.c) #所有的源文件生成一个可执行程序
# 定义目标文件
OBJS = $(SRCS:.c=.o)
# 定义最终目标
TARGET = my_program
# 伪目标,当只输入make时执行
all: $(TARGET)
# 链接目标文件生成最终程序
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $(TARGET)
# 编译源文件生成目标文件
%.o: %.c
$(CC) -c $< -o $@
# Phony目标,确保clean总是被执行,即使存在名为clean的文件或目录
.PHONY: clean rebuild
# 清除所有生成的目标文件和最终程序
clean:
rm -f $(OBJS) $(TARGET)
# 重新编译
rebuild: clean all
.PHONY
增加makefile的可读性
每个源文件生成可执行程序
SRCS:=$(wildcard *.c)
TARGETS:=$(SRCS:%.c=%)
all:$(TARGETS)
for i in $^; do gcc -o $$i $$i.c;done
.PHONY:clean
clean:
rm $(TARGETS)
不使用循环
CC:=gcc
SRCS:=$(wildcard *.c)
TARGETS:=$(SRCS:%.c=%)
all:$(TARGETS)
%:%.c
$(CC) $^ -o $@
.PHONY:clean
clean:
rm $(TARGETS)
有头文件的情况
#bubbleSort.cc bubbleSort.h main.cc
#Makefile
CXX:=g++
CXXFLAGS:=-std=c++11
#deps := $(wildcard *.h)
srcs:=$(wildcard *.cc) #1.cc 2.cc 3.cc
objs:=$(patsubst %.cc,%.o,$(srcs))
exe:=main
all:$(exe)
$(exe):$(objs)
$(CXX) $^ -o $@
#%:%.cc $(deps)
$(CXX) $< -o $@
%:%.cc
$(CXX) $^ -o $@
.PHONY: clean rebuild
clean:
$(RM) $(exe) $(objs)
rebuild:clean all

Makefile missing separator. Stop.怎么解决
makefile的命令行,开头必须用tab键