0%

Makefile使用笔记

文件名替换

1.wildcard
展开多个文件为使用空格分开的、匹配此模式的列表参数
格式
$(wildcard PATTERN...)

示例:

SRC=$(wildcard *.c)

2.patsubst
替换通配符
格式

$(patsubst %.c,%.o,$(dir))

示例:

obj := $(patsubst %.c,%.o,$(wildcard *.c))

3.替换引用
patsubst的示例等价于:

obj=$(dir:%.c=%.o)

引用替换:

$(var:a=b) 或 ${var:a=b}

含义是把变量var中的每一个值,用b替换掉a

PHONY

Makefile执行的规则是A:B,表示A依赖于B

  • 有B才能执行A对应的编译操
  • B有更新(检测文件时间),则A会执行,若B没有更新,不执行A

问题来了,clean: 不需要依赖任何对象,如何执行
PHONY定义伪目标,可以解决源文件不是最终目标直接依赖(即间接依赖)带来的不能自动检查更新规则, 示例如下

.PHONY: clean
clean:
    rm -f *.o

PHONY不仅用于clean,对于间接依赖也有用,例如A:B, B:C ,有时C为空,就需要把B定义为PHONY

OBJS = *.o
program:  $(OBJS)
        gcc *.o -o program
 
.PHONY : $(OBJS)
$(OBJS):
        make -C $(dir $@)

不过一般情况,obj依赖于%.c,总之,对于没有依赖项的对象,需要定义为PHONY

通配符

常见通配符

$@, $^, $<, $?

$@  表示目标文件
$^  表示所有的依赖文件
$<  表示第一个依赖文件
$?  表示比目标还要新的依赖文件列表

示例:
编译Test目录下的.cpp文件,输出test可执行程序
直接指定依赖文件名的makefile写法:

test: $(wildcard Test/*.cpp)
    $(CXX) $(CFLAGS) -o test $(wildcard Test/*.cpp) 

虽然wildcard实现了所有依赖的.cpp的通配,编译语句再用wildcard写一次依赖文件不优雅,而且test在依赖中已经写了,编译语句又写一遍 -o test。
编译语句使用通配, 称为通用格式:

test: $(wildcard Test/*.cpp)
    $(CXX) $(CFLAGS) -o $@ $^

多个源文件分别编译

目录下有很多源文件,每个单独编译和执行的,将每一个文件编译成可执行文件,不用单独命名如:gcc -c xxx.c -o xxx
(1)Makefile实现

SRC=$(wildcard *.c)
OBJ=$(SRC:%.c=%.o)
BIN=$(OBJ:%.o=%)
 
CC=gcc
CFLAGS=-Wall -g -c
 
all:$(BIN)

$(BIN):%:%.o
        $(CC) $^ -o $@
$(OBJ):%.o:%.c
        $(CC) $(CFLAGS) $^ -o $@

.PHONY: clean
clean:
        rm -rf $(OBJ) $(BIN)

(2)Shell实现

#! /bin/bash
for file in ./*.c
do
if [ -f $file ]
then
file=${file#./}
target=${file%.c}
gcc -o $target $file
echo $target
fi
if [ -d $file ]
then
echo $file is mu lu
fi
done

(2)Makefile编译指定目录
Makefile可以输入参数,直接在make命令的后面加上参数,如:

make BUILD_DIR=./foldername/

传入的变量将会覆盖相应Makefile中的BUILD_DIR