Makefile基础

书写规则

规则包括两部分,一个是依赖关系,一个是生成目标的方法.规则的语法:

targets : prerequisites
	command
	...

targets是文件名,以空格分开,可以使用通配符.一般来说,我们的目标基本上是一个文件,但也有可能是多个文件.

command是命令行,如果其不与"targets : prerequisites"在一行,那么必须以Tab键开头.

prerequisites也就是目标所依赖的文件(或依赖目标).如果其中的某个文件要比目标文件要新,那么,目标就被认为是"过时的",被认为是需要重生成的.

如果命令太长,你可以使用反斜杠\作为换行符.马珂对一行上有多少个字符没有限制.规则告诉make两件事,文件的依赖关系和如何生成目标文件.

一般来说,make会以UNIX的标准Shell,也就是/bin/sh来执行命令.

举一个很简单的例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ndfpNDZ-1649680780413)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220411145654490.png)]

当执行make指令的时候,结果如下:

D:\01Project\PA\demo>make
gcc main.c -o main
main.c

至于make的安装,这里不做介绍。

在规则中使用通配符

支持三个通配符:

  • *:*.c表示所有后缀为c的文件。
  • ~:~表示当前用户目录。
  • ?:通常在依赖文件列表中使用,匹配所有有更新的目标。make在编译目标时,会去检查目标的依赖文件列表是否有文件更新,$?表示当前依赖列表中已经更新的依赖文件。
clean:
    rm -f *.o
objects = *.o

上述例子中表示了通配符同样可以使用在变量中。并不是说*.o会展开,不!objects的值就是*.o.Makefile中的变量其实就是C中的宏,如果你要让通配符在变量中展开,也就是让objects的值是所有.o的文件名的集合,那么,你可以这样:

objects:=$(wildcard *.o)

另给一个变量使用通配符的例子:

1、列出一确定文件夹中的所有.c文件。

objects := $(wildcard *.c)

来获取工作目录下的所有.c文件列表

2、列出1中所有文件对应的.o文件,在3中我们可以看到它是由make自动编译出的:

$(patsubst %.c,%.o,$(wildcard *.c))

首先使用wildcard函数获取工作目录下的.c文件列表,之后将列表中的所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。

3、由1,2两步,可写出编译并链接所有.c.o文件

objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
    cc -o foo $(objects)

把Makefile修改为如下:

main: main.c
	gcc main.c -o main	
	@echo $?

那么执行make指令的时候结果如下:

D:\01Project\PA\demo>make
gcc main.c -o main
main.c

在目标文件没有被生成的时候,make工具会将所有的依赖文件视为已更新的文件,从而重新编译生成目标。

文件搜寻

在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的办法是把一个路径告诉make,让make再自动去找。

Makefile文件中的特殊变量VPATH就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。

VPATH=src:../headers

上面的定义指定了两个目录,src../headers,make会按照这个顺序进行搜索。目录由:冒号分割。

另一个设置文件搜索路径的方法是使用make的vpath关键字,这不是变量,这是一个make的关键字。

vpath %.h ../headers

该语句表示,要求make在../headers目录下搜索所有以.h结尾的文件。

伪目标

我们提到过一个clean的目标,这是一个"伪目标"。

clean:
	rm *.o temp

为了避免和文件重名的情况,我们可以使用搞一个特殊的标记.PHONY来显示地指明一个目标就是“伪目标”。

.PHONY : clean
clean :
	rm *.o temp

特殊变量

在makefile的编译规则中,有一些特殊的内建变量,下面就列出一些常用的内建变量。

$@:表示需要被编译的目标

$<:依赖列表中第一个依赖文件名

$^:依赖列表中所有文件

$?:依赖文件列表中所有有更新的文件,以空格分割

~或者./:用户目录。

AR:静态库打包命令的名字,缺省值时ar

ARFLAGS:静态库打包命令的选项,缺省值时rv

AS:汇编器的名称,缺省值是as

ASFLAGS:汇编器的选项,没有定义

CC:C编译器的名称,缺省值是cc

CFLAGS:C编译器的选项,没有定义。

CXX:C++编译器的名称,缺省值是g++

CXXFLAGS:C++编译器的选项,没有定义。

CPP:C预处理的名字,缺省值是$(CC) -E

CPPFLAGS:C预处理器的选项,没有定义。

LD:链接器的名字,缺省值是ld

LDFLAGS:链接器的选项,没有定义。

TARGET_ARCH:和目标平台相关的命令行选项,没有定义。

OUTPUT_OPTION:输出的命令行选项,缺省值是-o $@

LINK.o:把.o文件链接在一起的命令行,缺省值是$(CC) $(LDFLAGS) $(TARGET_ARCH)

COMPILE.c:编译.c文件的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

RM:删除命令的名字,缺省值是rm -f

make的隐含规则数据库中用到了很多变量,有些变量没有定义(例如CFLAGS),有些变量定义了缺省值(例如CC),我们写Makefile时可以重新定义这些变量的值,也可以在缺省值的基础上追加。

模式规则

模式规则类似于普通规则。只是在模式规则中,目标名中需要包含有模式字符%,包含有模式字符%的目标被用来匹配一个文件名,%可以匹配任何非空字符串。下列示例就是一个makefile内建的模式规则,由所有的.c文件生成对应的.o文件:

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

示例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7A8BmAjN-1649680780414)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220411202346726.png)]

#指定编译器和链接器
CC=gcc
LD=gcc

#-I头文件目录 -l库名 -L 库路径
#指定头文件目录
#指定库文件路径 和 库文件
INCLUDE = -I./ -I./include   
LIB = -L./lib -lhello        

BUILD_PATH := ./build
TARGET_NAME := main
TARGET := $(BUILD_PATH)/$(TARGET_NAME)

#当前目录所有.c文件
SRCS := $(wildcard *.c)  
#Build目录下所有的.o文件
OBJS := $(patsubst %.c, $(BUILD_PATH)/%.o, $(SRCS))  

.PHONY : all clean

all: $(TARGET)

 #要生成可执行文件需要依赖.o文件 
 #将所有目标文件和库文件链接即可生成可执行文件
$(TARGET): $(OBJS)  
	$(LD) $^ $(LIB) -o $@                   

#.o文件由.c编译而来 
#编译每一个.o文件
$(BUILD_PATH)/%.o: %.c  
	$(CC) -c $< $(INCLUDE) -o $@ 

#make clean命令 清空生成的文件
clean:
	rm -rf $(OBJS) $(TARGET)

多目录源文件通用Makefile示例

PWD := ${shell pwd}

CC = ${CROSS_COMPILE}gcc
LD = ${CROSS_COMPILE}gcc

BUILD_PATH := ./build
TARGET_NAME := audio_demo.bin
TARGET := ${BUILD_PATH}/bin/${TARGET_NAME}

#all source code path,can add more....
SRC_PATH:=./ ./subdir1 ./subdir2
${info "SRC_PATH:${SRC_PATH}"}

#all *.c file
SRCS:=${foreach dir,${SRC_PATH},${wildcard ${dir}/*.c}}
${info "SRCS:${SRCS}"}

#all *.o file
OBJS := ${patsubst %.c, ${BUILD_PATH}/%.o, ${notdir ${SRCS}}}
${info "OBJS:${OBJS}"}

#add source code search path
VPATH=${SRC_PATH}
${info "VPATH:${VPATH}"}

 #-I header file directory,can add more
INCLUDE = ${addprefix -I,${SRC_PATH}} -I./include
${info "INCLUDE:${INCLUDE}"}

#-l libName -L lib directory,can add more
LIB = -L./lib -lasound -lm -pthread \
	# -L${CROSS_TOOL_PATH}/aarch64-buildroot-linux-gnu/sysroot/usr/lib -lasound -lm -pthread

CFLAGS = -g -Wall -O2 -std=gnu11

.PHONY : all clean

all:build_prepare ${TARGET}

${TARGET}: ${OBJS}
	${LD} -o $@ $^ ${LIB}

${BUILD_PATH}/%.o: %.c
	${CC} -c $^ -o $@ ${INCLUDE} ${CFLAGS}

#mkdir
build_prepare:
	if [ ! -e ${BUILD_PATH}/bin ]; then \
		mkdir ${BUILD_PATH};\
		mkdir ${BUILD_PATH}/bin;\
	fi
clean:
	rm -rf ${OBJS} ${TARGET}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值