Makefile

1 三要素:

  • 依赖:判断依赖是否存在,若存在则判断跟目标的时间戳关系
  • 目标:判断目标是否存在,若存在则退出;否则执行动作
  • 动作:shell语句,行首为Tab
 image:a.o b.o c.o
         gcc a.o b.o c.o -o image
 
 a.o:a.c
         gcc a.c -o a.o -c
 b.o:b.c
         gcc b.c -o b.o -c
 c.o:c.c
         gcc c.c -o c.o -c

运行结果:

make
gcc a.c -o a.o -c
gcc b.c -o b.o -c
gcc c.c -o c.o -c
gcc a.o b.o c.o -o image

@:不打印命令本身

  1 image:a.o b.o c.o
  2         gcc a.o b.o c.o -o image
  3 
  4 a.o:a.c
  5         @gcc a.c -o a.o -c
  6 b.o:b.c
  7         @gcc b.c -o b.o -c
  8 c.o:c.c
  9         @gcc c.c -o c.o -c
//输出:
gcc a.o b.o c.o -o image

2 变量

  • 格式:$(变量名)
  • 变量和函数的展开实在make读取Makefile时进行。
  • 变量名大小写敏感,建议一般变量使用小写方式,参数列表采用大写方式

2.1 自定义变量&系统预定义变量

OBJ = a.o b.o c.o

image:a.o b.o c.o
    $(CC) $(OBJ) -o image

a.o:a.c
    @$(CC) a.c -o a.o -c
b.o:b.c
    @$(CC) b.c -o b.o -c
c.o:c.c
    @$(CC) c.c -o c.o -c

$(CC)默认为:CC

//输出
cc a.o b.o c.o -o image

在不同平台重新给预定义变量赋值一次即可,如在ARM平台重新赋值,此时代表交叉编译工具链

OBJ = a.o b.o c.o
CC = arm-Linux-gun-gcc

image:a.o b.o c.o
    $(CC) $(OBJ) -o image

2.2 Makefile预定义变量

  • RM:删除命令,默认为:rm -f
  • CC:c编译程序,默认为:cc
  • CPP:c程序的预处理器,默认为:-E
  • CXX:c++编译程序,默认为:g++
  • AS:汇编程序,默认为:as
  • AR:函数库打包程序,可创建静态库 .a文档,默认为:ar
  • ARFLAGS:执行AR命令的命令行参数,默认为:rv
  • CFLAGS:CC编译器的命令行参数
  • CXXFLAGS:g++编译器的命令行参数
  • ASFLAGS:汇编器AS的命令行参数

2.3 自动化变量

  • @:所在规则的目标的完整名称
    @D:目标文件的目录部分
    @F:目标文件的文件名
OBJ = a.o b.o c.o

output/image:a.o b.o c.o
    echo $(@) $(@D) $(@F)

//输出
output/image output image
  • <:所在规则的依赖列表的第一个文件的完整名称
    <D:第一个依赖文件的目录部分
    <F:第一个依赖文件的文件名
output/image:a.o b.o c.o
    echo $(<) $(<D) $(<F)

//输出
a.o . a.o
  • ^:所在规则的依赖列表,去除重复的依赖文件
    ^D:所有依赖列表的目录部分
    ^F:所有依赖列表的文件名部分

  • +:所在规则的依赖列表,同一文件可重复
    +D:所有依赖列表的目录部分
    +F:所有依赖列表的文件名部分

  • ?:被更新的依赖文件列表,用空格隔开
    ?F:被更新的依赖文件的目录部分
    ?D:被更新的依赖文件的文件名部分

  • *:在模式规则和静态规则中,代表茎

  • %:代表所在规则的静态库文件的一个成员名

用自动化变量代表依赖库和目标

OBJ = a.o b.o c.o

output/image:$(OBJ)
    $(CC) $(^) -o $(@) 

a.o:a.c
    @$(CC) $(^) -o $(@) 
b.o:b.c
    @$(CC) $(^) -o $(@) 
c.o:c.c
    @$(CC) $(^) -o $(@) 

2.4 变量的定义

  • 递归定义

A = Here is $(B)
B = China
在整个文件搜索变量B

  • 直接定义

B = China
A := Here is $(B)
在语句之前搜索变量B,若搜不到则返回空

  • 条件定义

A = apple
A ?= banana
如果A已定义则不做操作;
如果A没有定义,则定义为“banana”。

  • 多行命令定义

define commands
    echo "ok!"
    echo "done!"
enddef
  • 追加变量

A = apple
A += tree
变量A的值为:apple tree

  • 替换变量的值

A = a.c b.c c.c
B = $(A:%.c=%.o)
变量B的值为,将变量A中所有以".c"结尾的单词替换为 “.o”结尾
内嵌函数patsubst也可实现该功能:
B = $(patsubst %.c, %.o, $(A))

  • override变量

在执行make命令时,可以携带一个变量的定义。
如果这个变量跟Makefile中的变量重名,则覆盖Makefile中变量的定义。
如果Makefile中无此变量,则追加该变量的定义。

override CFLAGS += -Wall
OBJ = a.o b.o c.o
image:$(OBJ)
    $(CC) $(^) -o $(@) $(CFLAGS)

a.o:a.c
    @$(CC) $(^) -o $(@) -c 
b.o:b.c
    @$(CC) $(^) -o $(@) -c 
c.o:c.c
    @$(CC) $(^) -o $(@) -c 
//输出
//make
cc a.o b.o c.o -o image -Wall
//make CFLAGS="-g"
cc a.o b.o c.o -o image -g -Wall
  • 传递变量

将变量传递给子Makefile

//cat Makefile 
export A = apple
B = banana

all:
    echo "$A"
    echo "$B"
    $(MAKE) -C src/  #调用 src/目录下的Makefile

子Makefile:

//cat src/Makefile 
image:
    echo "src/: $A"
    echo "src/: $B"

输出:

echo "apple"
apple
echo "banana"
banana
make -C src/ 
make[1]: Entering directory '...projectA/src'
echo "src/: apple"
src/: apple
echo "src/: "
src/: 
make[1]: Leaving directory '...projectA/src'
  • 默认传递的变量:

SHELL
MAKEFLAGS
MAKEFILES
执行make前就已存在的环境变量

对于默认传递的变量可以用unexport阻止传递给子Makefile

  • VPATH

VPATH = 路径1:路径2
VPATH = 路径1 路径2
指定文件搜索时,除当前路径之外的备用路径,以空格或者冒号隔开

VPATH = src1:src2

小写的指示符:vpath 可以为不同类型的文件指定不同的路径

vpath %.c = src1:src2
vpath %.h = include/

VPATH是一个变量,而vpath是一个指示符。

  • MAKE

调用子Makefile:

$(MAKE) -C subdir/
  • MAKEFLAGS

执行make时的命令行参数,这个变量默认传递给子Makefile。

3 规则

3.1 隐式规则

make可以自动找到依赖文件所需要的源程序文件,并自动编译。
但是只能自动找到与目标同名的依赖文件。

OBJ = a.o b.o c.o

image:$(OBJ)
    $(CC) $(^) -o $(@) 

//输出
cc    -c -o a.o a.c
cc    -c -o b.o b.c
cc    -c -o c.o c.c
cc a.o b.o c.o -o image

若存在文件clean.c

OBJ = a.o b.o c.o 

image:$(OBJ)
    $(CC) $(^) -o $(@) 

clean:

//make clean
cc     clean.c   -o clean

为区分动作的代号和要生成的文件,用指示符 .PHONY 来定义伪目标,即不运用隐式规则。

OBJ = a.o b.o c.o 

image:$(OBJ)
    $(CC) $(^) -o $(@) 

clean:

.PHONY: clean


//make clean
make: Nothing to be done for 'clean'.

3.2 静态规则

编译.o文件时,需要加特定的编译选项。

OBJ = a.o b.o c.o 

image:$(OBJ)
    $(CC) $(^) -o $(@) 

$(OBJ):%.o:%.c
    $(CC) $(^) -o $(@) -Wall -c 
     
clean:
    $(RM) $(OBJ)

.PHONY: clean

//make
cc a.c -o a.o -Wall -c 
cc b.c -o b.o -Wall -c 
cc c.c -o c.o -Wall -c 
cc a.o b.o c.o -o image 

$(OBJ):%o:%.c
在(a.o、b.o、c.o)中匹配“.o”为后缀的文件,冒号后面的内容是目标对应的依赖。

3.3 多目标规则

  • 可描述文件的依赖关系
    如:OBJS中的.o文件都依赖于head.h文件,而又各自依赖其他的头文件
OBJS = a.o b.o c.o
a.o:a.h
b.o:b.h B.h
c.o:c.h
$(OBJS):head.h
  • 有多个具有类似构建命令的目标(也可用静态规则)
SRC = a.c b.c x.c y.c
OBJS = $(SRC:.c=.o)

image:$(OBJS)
  $(CC) $(OBJS) -o image

$(OBJS):$(SRC)
  $(CC) $(subst .o,.c,$@) -o $@ -c

以a.o为例,多目标规则将构建如下对a.o的规则:

a.o:a.c b.c x.c y.c
  $(CC) a.c -o a.o -c

意味着所有的目标依赖相同的文件

3.4 双冒号规则

用于同一个文件作为多个规则的目标。
在Makefile中,一个目标可以出现在多个规则中,但是这些规则必须是同一种规则,要么都是双冒号规则,要么都是普通规则。
普通规则会将所有依赖合并到一个目标文件。
双冒号规则的作用:

  • 当依赖列表为空,即使目标文件已存在,规则中的shell命令无条件执行
  • 根据依赖文件修改的情况,执行对应的命令
image::a.c
  $(CC) a.c -o $@ -L. -lx

image::b.c
  $(CC) b.c -o $@ -L. -ly

同一个目标出现在多个双冒号规则中,执行顺序按照书写顺序执行;
当a.c更新时,按照a.c文件重建目标image;
当b.c更新时,按照b.c文件重建目标image。

4 条件判断

OBJ = a.o b.o x.o y.o

#判断变量TOOLCHAIN是否有定义
ifdef TOOLCHAIN
  CC= $(TOOLCHAIN)
else
  CC = gcc
endif

image:$(OBJ)
#判断CC的值是否等于gcc,ifeq与后面的括号之间有空格
ifeq ($(CC), gcc)
  $(CC) $(OBJ) -o image -lgcc
else
  $(CC) $(OBJ) -o image
endif
...

执行:
make TOOLCHAIN=arm-none-linux-gnueabi-gcc

5 函数

函数格式:
$(function arg1,arg2,arg3,...)

5.1 wildcard

找到参数匹配的文件名

SRC=$(wildcard *.c)  #找到所有.c文件

5.2 文本处理函数

5.2.1 subst FROM,TO,TEXT

将字符串TEXT中的字符FROM替换为TO

5.2.2 patsubst PATTERN,REPLACEMENT,TEXT

按照PATTERN搜索TEXT中所有以空格隔开的单词,并将它们替换为REPLACEMENT
A = $(patsubst %.c,%.o,a.c b.c)
A的值为:a.o b.o

5.2.3 strip STRING

去掉字符串中开头和结尾的多余的空白符(空格、制表符),并将其中连续的多个空白符合并为一个。

5.2.4 findstring FIND,STRING

在字符串STRING中查找FIND子串
找到返回FIND,否则返回空

5.2.5 filter PATTERN,TEXT

过滤TEXT中不符合给定模式PATTERN的单词

A = a.c b.o c.s d.txt
B = $(filter %.c %.o,$(A))

B的值为:a.c b.o

5.2.6 filter-out PATTERN,TEXT

过滤TEXT中符合PATTERN模式的单词,与filter相反

5.2.7 sort LIST

将字符串LIST中的单词按字母升序的顺序排序,去掉重复的单词

5.2.8 word N,TEXT

取TEXT中的第N个单词,N必须为正整数

5.2.9 wordlist START,END,TEXT

取TEXT中介于START和END之间的子串;
START,END均为正整数
START大于TEXT中的单词总数或者START大于END时返回空

5.2.10 words TEXT

计算TEXT中的单词数

5.2.11 firstword TEXT

取字符串TEXT中的第一个单词;
相当于$(word 1 TEXT)

5.3 文件名的处理函数

5.3.1 dir NAMES

取文件列表NAMES中的每一个路径的目录部分

5.3.2 notdir NAMES

取文件列表NAMES中的每一个路径的文件名部分

5.3.3 suffix NAMES

取文件列表NAMES中的每一个路径文件的后缀部分;
指最后一个"."及后面的子串

5.3.4 basename NAMES

取文件列表NAMES中的每一个路径文件的前缀部分;
指最后一个"."前面的子串

5.3.5 addsuffix SUFFIX,NAMES

为文件列表NAMES中每一个路径的文件名添加后缀SUFFIX

5.3.6 addprefix PREFIX,NAMES

为文件列表NAMES中每一个路径的文件名添加前缀PREFFIX

5.3.7 wildcard PATTERN

获取满足匹配模式PATTERN的文件名

5.3.8 foreach VAR,LIST,TEXT

将LIST中以空格分割的单词依次取出赋值给VAR,然后执行TEXT表达式,重复直到LIST的最后一个单词

DIR = dir1 dir2
FILES = $(foreach dir,$(DIR),$(wildcard $(dir)/*))
all:
  echo $(FILES)

依次执行:
$(wildcard dir1/*)
$(wildcard dir2/*)

5.3.9 if CONDITION,THEN-PART[,ELSE-PART]

5.3.10 call VAR,ARGS,...

将ARGS一一替换VAR中的(1)、(2)...

A = hello, $(1) $(2)
B = $(call A )

5.3.11 origin VAR

查看参数VAR的出处

5.3.12 Shell COMMANDS

执行COMMANDS命令

6 实例

参考:
https://blog.csdn.net/xukai871105/article/details/37083675

6.1 单文件编译

#可执行文件
TARGET = test
#c文件
SRCS = main.c
#依赖目标
OBJS = $(SRCS:.c=.o) 

#指令编译器和选项
CC=gcc
CFLAGS = -Wall

$(TARGET):$(OBJS)
# @echo TARGET:$@
# @echo OBJECTS:$^
    $(CC) -o $@ $^

clean:
    $(RM) $(TARGET) $(OBJS) 

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

//执行:
make
gcc -Wall   -c -o main.o main.c
gcc -o test main.o

使用@echo指令:

make
gcc -Wall   -c -o main.o main.c

6.2 多文件编译

#可执行文件
TARGET = test
#c文件
SRCS = a.c b.c c.c d.c
#依赖目标
OBJS = $(SRCS:.c=.o) 

#指令编译器和选项
CC=gcc
CFLAGS = -Wall

$(TARGET):$(OBJS)
# @echo TARGET:$@
# @echo OBJECTS:$^
    $(CC) -o $@ $^

%.o:%.c
    $(CC) $(CFLAGS) -o $@ -c $<

clean:
    $(RM) $(TARGET) $(OBJS) 

6.3 生成自定义库

# 指令编译器和选项
CC = gcc
CFLAGS = -Wall 

# 目标文件
#需以lib开头, .so结尾
#在使用该共享库时系统会自动的去除lib和.so
#使用时写成-ltest
TARGET = libtest.so
# C文件
SRCS = test_func.c
# 目标文件
OBJS = $(SRCS:.c=.o)
 
# 链接为可执行文件
#shared参数意为共享形式的目标文件
$(TARGET):$(OBJS)
    $(CC) -shared -o $@ $^
 
clean:
    $(RM) $(TARGET) $(OBJS)
 
# 编译规则 $@代表目标文件 $< 代表第一个依赖文件
#-fPIC参数,意为生成和地址无关的目标文件
%.o:%.c
    $(CC) $(CFLAGS) -o $@ -fPIC -c $
//执行
gcc -Wall  -o test_func.o -fPIC -c test_func.c
gcc -shared -o libtest.so test_func.o

6.4 使用自定义库文件

# 指令编译器和选项
CC = gcc
CFLAGS = -Wall 
 
# 目标文件
TARGET = test
# C文件
SRCS = main.c
# 头文件查找路径
INC = -I.
# 库文件和库查找路径
DLIBS = -ltest
LDFLAGS = -L./lib
# 指定运行时的库文件路径
RPATH = -Wl,-rpath=./lib
 
# 目标文件
OBJS = $(SRCS:.c=.o)
 
# 链接为可执行文件
$(TARGET):$(OBJS)
    $(CC) -o $@ $^ $(LDFLAGS) $(DLIBS) $(RPATH)
 
clean:
    $(RM) $(TARGET) $(OBJS)
 
# 连续动作,请清除再编译链接,最后执行
exec:clean $(TARGET)
    @echo 开始执行
    ./$(TARGET)
    @echo 执行结束
 
# 编译规则 $@代表目标文件 $< 代表第一个依赖文件
%.o:%.c
    $(CC) $(CFLAGS) $(INC) -o $@ -c $<

//输出
gcc -Wall  -I. -o main.o -c main.c
gcc -o test main.o -L./lib -ltest -Wl,-rpath=./lib
```k
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容