Makefile

Makefile #

xxx.mk 文件或者 Makefile 都统称为 Makefile 脚本文件

功能:指导 Make 软件控制 arm-gcc 等工具链去编译工程文件最终得到可执行文件

image-20240831224125900

基础规则 #

目标:依赖条件
	命令	

拓展

#.mk-V0
#根据工作原理,如果只改变其中一个文件,就只会编译这个文件
hello: main.cpp printhello.cpp factorial.cpp
	g++ -o hello main.cpp printhello.cpp factorial.cpp
#.mk-V1
#使用变量CXX、TARGET 、OBJ,同时采用不同的依赖分别编译
#根据工作原理,如果只改变其中一个文件,就只会编译这个文件
CXX = g++
TARGET = hello 
OBJ = main.o printhello.o factorial.o

$(TARGET): $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp
##.mk-V2: ALL
#makefile 默认第一个目标文件为终极目标,生成就跑路,这时候可以用 ALL 来指定终极目标。
CXX = g++
TARGET = hello 
OBJ = main.o printhello.o factorial.o

ALL : $(TARGET)

$(TARGET): $(OBJ)
	$(CXX) $(OBJ) -o $(TARGET) 

main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp
#.mk-V3: wildcard & patsubst 
src = $(wildcard ./*.c) #匹配当前工作目录下的所有.c 文件
obj = $(patsubst %.c, %.o, $(src)) # 将参数 3 中,包含参数 1 的部分,替换为参数 2

###
CXX = g++
TARGET = hello 
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp

$(TARGET): $(obj)
	$(CXX) $(obj) -o $(TARGET) 
#.mk-V4: clean
src = $(wildcard ./*.c) #匹配当前工作目录下的所有.c 文件
obj = $(patsubst %.c, %.o, $(src)) # 将参数 3 中,包含参数 1 的部分,替换为参数 2

###
CXX = g++
TARGET = hello 
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp

$(TARGET): $(obj)
	$(CXX) $(obj) -o $(TARGET) 

clean :
	-rm -rf $(obj) $(TARGET)# “-” :作用是,删除不存在文件时,不报错。顺序执行结束。
#.mk-V5: 三个自动变量
$@	# 在规则的命令中,表示规则中的目标。
$^	# 在规则的命令中,表示所有依赖条件。组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
$<	# 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。

CXX = g++
TARGET = hello 
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


main.o: main.cpp
	$(CXX) -c $<

printhello.o: printhello.cpp
	$(CXX) -c $<
factorial.o: factorial.cpp
	$(CXX) -c $<

$(TARGET): $(obj)
	$(CXX) $^ -o $@ 

clean :
	-rm -rf $(obj) $(TARGET)
#.mk-V6: 模式规则
#要添加一个.cpp文件,不需要在 makefile 里面增加这个文件的 -o 的部分

CXX = g++
TARGET = hello 
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


%.o : %.c
	$(CXX) -c $< -o $@

$(TARGET): $(obj)
	$(CXX) $^ -o $@ 

clean :
	-rm -rf $(obj) $(TARGET)
#.mk-V7: 静态模式规则??
#使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给 obj 用,以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

CXX = g++
TARGET = hello 
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


$(obj) : %.o : %.c
	$(CXX) -c $< -o $@

$(TARGET): $(obj)
	$(CXX) $^ -o $@ 

clean :
	-rm -rf $(obj) $(TARGET)
#.mk-V8: 伪目标
#当前文件夹下有 ALL 文件或者 clean 文件时,会导致 makefile 瘫痪,此时使用.PHONY: clean ALL
.PHONY: clean ALL

CXX = g++
TARGET = hello 

src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))

ALL : $(TARGET)


$(obj) : %.o : %.c
	$(CXX) -c $< -o $@

$(TARGET): $(obj)
	$(CXX) $^ -o $@ 

clean :
	-rm -rf $(obj) $(TARGET)
#.mk-V9: 文件分类
#将上述 .cpp 文件都放到 src 目录中,.h 文件都放在 inc 目录中
CXX = g++
TARGET = hello
src = $(wildcard ./src/*.cpp)
obj = $(patsubst ./src/%.cpp, ./obj/%.o, $(src))

inc_path = ./inc
CXXFLAGS = -Wall -c -I$(inc_path)

ALL : $(TARGET)

./obj/%.o : ./src/%.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

$(TARGET): $(obj)
	$(CXX) $^ -o $@

clean :
	-rm -rf $(obj) $(TARGET)

.PHONY: clean

make 的参数 #

  • -n:模拟执行 make、 make clean 命令。仅输出执行过程中的命令序列,但并不执行。
  • -f:指定文件执行 make 命令。 xxxx.mk
  • -j:可以并行构建多个目标,加快构建速度
  • -s‌ 或 ‌**–silent‌ 或 ‌–quiet**‌:不显示命令。

Makefile 语法 #

使用echo进行printf

:= # 即时变量 = # 延时变量 ?= # 延时变量,如果是第 1 次定义才起效,如果在前面该变量已定义则忽略这句 += # 附加,他是即时变量还是延时变量取决于前面的定义,中间会有空格,加在后面

Makefile 函数 #

  • wildcard 函数 格式: $ (wildcard PATTENR) 展开指定的目录

  • notdir 函数 格式: $ (notdir $ (var) ) 去掉路径。

  • dir 函数: $(dir ) 取出目录

  • patsubst 函数:$(patsubst 原文件,目标文件,文件列表)替换

  • foreach 函数: 格式:$(foreach ,,)功能:把参数 中的单词逐一取出放到参数 所指定的变量中,然后再执行 所包含的表达式。每一次 会返回一个字符串

编译标志

  • -O2:优化代码。
  • -g:包含调试信息。
  • -Wall:开启所有警告。
  • -std=c++11:指定使用 C++11 标准。
  • -I:指定包含(头文件)搜索路径。
  • -L:指定库文件搜索路径。
  • -l:指定链接时使用的库。

参考 #

makefile文件基本语法-CSDN博客

CMake #

用于生成make文件

同类产品:XMake

cmake_minimum_required (VERSION 2.8)#lowest version requirement 
 
project (learn_cmake)   #project name
 
add_executable(hello hello.cpp)#要生成的可执行文件名为hello,后面的参数是需要的依赖

aux_source_directory(./your_src_dir var)#把dir目录中的所有源文件都储存在var变量中, 用“${var}”替换上面的hello.cpp.如果分别在多个文件,那么可以多次使用aux_source_directory

include_directories ( ./your_inc_dir )#他的作用是 自动去dir目录下寻找头文件,相当于 gcc中的 gcc -I dir
cmake . #执行CMakeLists.txt 
#之后会生成Makefile
make #执行Makefile

案例1 #

image-20240927155345991

image-20240927155437588

  • PROJECT_BINARY_DIR是cmake系统变量,意思是执行cmake命令的目录,我们计划在build目录下执行cmake命令,所以这个变量也就等同于build目录
  • set_target_properties重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称。具体可以参考官方文档
  • LIBRARY_OUTPUT_PATH 是cmake系统变量,项目生成的库文件都放在这个目录下。这里我指定库生成到lib目录。

场景2 #

image-20240927160058472

image-20240927160106858

image-20240927160113890

image-20240927160123943