跳至主要內容

makefile使用方法

张威大约 5 分钟linux编译工具

makefile使用方法

使用方法

先建立一个名为makefile或者是Makefile的文件,然后在里面写入符合语法规则的编译命令,完成以后只需要在文件所在目录使用make命令就能运行编译命令

书写规则

从第一行命令开始,先确认目标文件,根据目标文件确定所需的依赖文件,然后递归地找到依赖文件的依赖文件,直到依赖文件是没有子依赖文件

#注释   书写格式
[目标文件]:[依赖文件]
<tab>[command]

原则

,即只有目标文件比依赖旧或者目标文件不存在,才会执行命令

伪目标

以不会存在的文件名作为目标。make伪目标,命令会一直执行

make .PHONY #查看定义了哪些伪目标
make clean # 清除所有生成的目标文件和最终程序 
make rebuild #重新编译

变量名

  1. 自定义变量变量名:=变量内容(字符串)$(变量名)使用变量,实际上就是

  2. 自动变量:变量内容会随着规则自动变化

    变量说明
    $@目标文件
    $<第一个依赖文件
    $^所有依赖文件,以空格分隔
    $?日期新于目标文件的所有相关文件列表,逗号分隔
    $(@D)目标文件的目录名部分
    $(@F)目标文件的文件名部分
  3. 预定义变量

变量名功能默认含义
AR打包库文件ar
AS汇编程序as
CCC编译器gcc
CPPC预编译器$(CC) -E
CXXC++编译器g++
RM删除rm –f
ARFLAGS库选项
ASFLAGS汇编选项
CFLAGSC编译器选项
CPPFLAGSC预编译器选项
CXXFLAGSC++编译器选项

= 和 := 的区别

使用 = 赋值的变量被称为递归展开变量。这可能导致变量的值在每次引用时都可能不同。

A = $(B)  
B = Hello  
  
all:  
	@echo $(A)  # 输出 "Hello"

使用 := 赋值的变量被称为直接展开变量。在赋值时就被展开,之后不会再次展开,因此变量的值在赋值后就固定不变。这也是工作当中的

A := $(B)  
B = Hello  
  
all:  
	@echo $(A)  # 输出空行,因为A在赋值时B还未定义

通配符和模式匹配

使用bash的规则来应用通配符

clean:
    rm -rf *.o

%通配符

  1. %表达式 可以作某个规则的目标(目标:上一个规则的依赖)

    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
    
  2. %表达式根据变量内容生成新的内容

    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

make命令的-f指定makefile文件

有些时候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 
image-20240310234105841
image-20240310234105841

Makefile missing separator. Stop.怎么解决

makefile的命令行,开头必须用tab键