Makefile是组织编译的命令脚本文件-构建生成可执行文件的依赖关系树.

make根据makefile的规则关系树, 构建出编译可执行程序.

1
2
3
4
# 目标: 目标依赖
#     命令
a.out: demo.c
    gcc -o $@ $<

make指令

windows 环境

运行make -v会出现:

1
2
'make' 不是内部命或外部命令, 也不是可余小宁的程序, 或批处理文件.
# 系统在环境变量中找不到 make 命令执行文件

解决方法:

  1. 找到mingw安装目录, 打开bin目录, 找到mingw32-make.exe
  2. mingw32-make.exe将该文件重命名为make.exe

编译过程

cimpiler_processer

编译过程图

Makefile

  • 变量 使用 $(val) 获取val的值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.PHONY: clean

CC=g++
BIN=exec
OBJS=AddTwoSum.o utils.o

$(BIN): $(OBJS)
	@echo "start compiling..."
	@echo $(CC)
	$(CC) -o $(BIN) $(OBJS)
	@echo "compile done"
AddTwoSum.o: AddTwoSum.cpp
	$(CC) -c -o $@ $<
utils.o: utils.cpp
	$(CC) -c -o $@ $<
clean:
	rm -f $(BIN) $(OBJS)
  • 条件复制
1
2
3
4
5
6
7
8
9
#条件赋值 ?=
#追加赋值 +=
CC = g++
CC ?= gcc
OBJS = AddTwoSum.o
OBJS += utils.o
echo:
	@echo $(CC)
	@echo $(OBJS)
  • 立即变量和延迟变量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 使用 := 赋值, 立即变量
# 使用 = 赋值, 延迟变量(关系变量)
a = 1
b = 2
val_a := $(a) # val_a=1 解析即赋值 立即解析赋值
val_b = $(b)  # val_b的值随着b的变化而变化 绑定变量关系
a = 10
# b = 20
echo:
	@echo $(val_a)
	@echo $(val_b)
  • 自动变量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 常用自动变量
# $@ 目标
# $^ 所有依赖项
# $< 目标依赖项中的第一个
# $? 所有依赖项中被修改过的
.PHONY: clean

CC=g++
BIN=exec
OBJS=AddTwoSum.o utils.o

$(BIN): $(OBJS)
	@echo "start compiling..."
	@echo $(CC)
	$(CC) -o $@ $^
	@echo "compile done"
AddTwoSum.o: AddTwoSum.cpp
	$(CC) -c -o $@ $<
utils.o: utils.cpp
	$(CC) -c -o $@ $<
clean:
	rm -f $(BIN) $(OBJS)
  • 变量替换(模式匹配)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.PHONY: echo

SRC = demo.c demo1.c
OBJ = $(SRC:.c=.o)
OBJ1 = $(SRC:%.c=%.o)

echo:
	@echo "SRC=$(SRC)"
	@echo "OBJ=$(OBJ)"
	@echo "OBJ1=$(OBJ1)"

# SRC=demo.c demo1.c
# OBJ=demo.o demo1.o
# OBJ1=demo.o demo1.o
  • 环境变量

环境变量运行时载入makefile. 如果有相同命名的变量, 系统环境变量会被覆盖.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
.PHONY: echo

CFLAGS = -g

echo:
	@echo "CFLAGS = $(CFLAGS)"
	@echo "SHELL = $(SHELL)"
	@echo "MAKE = $(MAKE)"
	@echo "HOSTNAME = $(HOSTNAME)"

# CFLAGS = -g
# SHELL = D:/sortwares/Git/usr/bin/sh.exe
# MAKE = D:/sortwares/mingw64/bin/make
# HOSTNAME = TX-PC0N4UHP

# 运行make 可以传值改变 export方式
# make HOSTNAME=CodeMax
# HOSTNAME = CodeMax
  • 条件判断
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# ifeq 判断相等
mode = debug

echo:
ifeq ($(mode),debug)
	@echo "debug mode"
else
	@echo "release mode"
endif

# ifneq
echo:
ifeq ($(mode),)
	@echo "debug mode"
else
	@echo "release mode"
endif

# ifdef
echo:
ifdef mode
	@echo "debug mode"
else
	@echo "release mode"
endif
  • 函数
  1. 自定义函数 通过call调用
  2. make内嵌函数 直接make调用
  3. 函数与参数使用空格隔开 参数之间使用,隔开
1
2
3
4
5
# 内嵌函数
SRC = $(wildcard *.cpp)

echo:
	@echo "SRC = $(SRC)"
1
2
3
4
5
6
7
8
# 自定义函数
define func
	@echo "param1 = $(0)"
	@echo "param = $(1)"
endef

echo:
	$(call func, hello world)
  • 遍历 foreach
1
$(foreach VAR, LIST, TEXT)
  1. VAR 将空格隔开的每一个选项赋值给VAR
  2. TEXT 处理VAR的脚本
  • if 函数
1
2
3
4
5
6
# $(if(condition, then[, else]))
install__path =
install_path = $(if $(install__path), $(install__path), /usr/local)

echo:
	@echo "$(install_path)"
  • call 函数
1
# $(call def_func, <parm1>, <param2>...)
  • error warning 函数
1
2
# $(error TEXT...)
# $(warning TEXT...)

example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 如果当前目录中,正好有一个文件叫做clean,那么这个命令不会执行。
# 因为Make发现clean文件已经存在,就认为没有必要重新构建了,就不会执行指定的rm命令
# 就有了下面的伪声明
.PHONY: clean

# 编译Cpp
CC = g++
# 设置编译参数设置
# -g表示编译时候加入调试信息,
# -DDEBUG表示编译debug版本
# -W -Wall表示输出所有警告
# -fPIC是生成dll时候用的
CFLAGS = -g -DDEBUG -W -Wall -fPIC
# 头文件的目录为./ 当前目录
HEADER  = -I./

ALGONAME = AddTwoSum
TOOLNAME = utils
OBJS= $(ALGONAME).o $(TOOLNAME).o

TARGET = algo

$(TARGET): $(OBJS)
	@echo "start compiling..."
	$(CC) $(CFLAGS) -o $@ $^
	@echo "compile done"
$(ALGONAME).o: $(ALGONAME).cpp
	$(CC) -c -o $@ $<
$(TOOLNAME).o: $(TOOLNAME).cpp
	$(CC) -c -o $@ $<
clean:
	rm -f $(TARGET) $(OBJS)

参考