简介
在 Makefile 中,有一些内置的变量可以用于表示常见的目录路径。以下是一些常用的 Makefile 内置变量相关的目录:
$(CURDIR)
: 当前工作目录的绝对路径。$(SRCDIR)
: 源代码目录的路径。$(INCDIR)
: 头文件目录的路径。$(BINDIR)
: 可执行文件目录的路径。$(LIBDIR)
: 库文件目录的路径。
这些内置变量可以用于指定源代码、头文件、可执行文件和库文件的目录路径。你可以根据需要在 Makefile 中使用这些变量,例如:
1 | # 当前工作目录 |
在上述示例中,我们使用了 $(CURDIR)
变量获取当前工作目录的路径,并根据它构建了其他目录的路径。然后,我们使用这些路径变量来设置源代码、头文件、可执行文件和库文件的路径。
示例
编写 Makefile 是一种常用的方式来管理和构建 C++ 项目。下面是一个简单的示例 Makefile,展示了如何编写一个基本的 C++ 项目的 Makefile。
1 | # 编译器设置 |
在上述示例中,我们定义了以下内容:
CXX
和CXXFLAGS
变量用于设置编译器和编译选项。TARGET
变量用于指定最终生成的可执行文件名。OBJS
变量用于指定目标文件(即编译后的中间文件)。all
是默认目标,用于构建整个项目。它依赖于$(TARGET)
。$(TARGET)
目标用于生成最终的可执行文件。它依赖于$(OBJS)
。%.o
是一个模式规则,用于编译每个源文件。它依赖于对应的.cpp
文件,并使用$<
和$@
分别表示依赖和目标文件。clean
目标用于清理生成的目标文件和可执行文件。
你可以根据实际项目的需要进行修改和扩展。例如,你可以添加更多的源文件、头文件目录、链接库等。
要使用上述 Makefile,只需在项目根目录下创建一个名为 Makefile
(注意大小写),并将上述内容粘贴到文件中。然后,在项目根目录下执行 make
命令即可构建项目。执行 make clean
可以清理生成的文件。
请注意,Makefile 的编写可能会因具体的项目需求和构建环境而有所差异。上述示例仅为一个简单的起点,你可以根据自己的需要进行进一步的定制和优化。同时,还可以考虑使用更高级的构建工具和自动化构建系统(如 CMake、Autotools 等)来管理更复杂的项目。
书写规则:
- 依赖关系:生成目标的方法
规则语法:
1 | targets:prerequisites |
参数
make -C dir
,--directory=dir
: Change to directorydir
before reading the makefiles or doing anything else.
变量:
变量在声明时,需要给予初值,而在使用时,需要给变量名前加上$符号,并且用小括号括起来
makefile中变量分为环境变量,内置变量和自动变量
环境变量
DESKTOP_SESSION
: ubuntuXDG_SESSION_TYPE
: x11XAUTHORITY
: /run/user/1000/gdm/Xauthority_
: /usr/bin/make
自动变量
$@
: 表示规则的目标文件名$<
: 规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则代表由隐含规则加入的第一个依赖文件$^
: 规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有库成员(.0文件)名。一个文件可重复的出现在目标的依赖中,变量$^
只记录它的一次引用情况。就是说变量$^
会去掉重复的依赖文件。$+
: 类似于$^
,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合
内置变量
$(CURDIR)
: 显示当前路径$(SHELL)
: /bin/sh$(CC)
: cc , C语言编译器的名称$(CPP)
: $(CC) -E , C语言预处理器的名称$(CXX)
: g++ , C++语言的编译器的名称$(RM)
: rm -f , 删除文件程序的名称$(CFLAGS)
: C语言编译器的编译选项,无默认值$(CXXFLAGS)
: C++语言编译器的编译选项,无默认值
运算符
?=
- 条件变量分配运算符,它仅在尚未定义的变量时具有效果
+=
1
2
3
4
5
6variable = main.o merge.o
variable += delete.o
# ALL:$(variable)
all:
@echo ${variable}
# 输出: main.o merge.o delete.o
函数
$(abspath names...)
: 获取文件的绝对地址ifeq (condition1, condition2) ... endif
- 如果
condition1
等于conditon2
, 则执行下面的操作,否则不执行
- 如果
${addprefix "前缀", filenames...}
- 为文件加前缀
1
2
3
4
5
6variable = main.o merge.o
variable += delete.o
var = ${addprefix -x/, ${variable}}
all:
@echo ${var}
# 输出: -x/main.o -x/merge.o -x/delete.o
- 为文件加前缀
${wildcard /home/user/workspace/shell/*.sh}
- 获取指定路径下的指定文件
1
2
3
4
5var = ${wildcard ./*.txt}
all:
@echo ${var}
# 输出: ./foo.txt ./bar.txt
- 获取指定路径下的指定文件
${patsubst pattern, replacement, text}
- 根据相应规则替换文件名
1
2
3
4
5
6var = ${wildcard ./*.txt}
pat = ${patsubst %.txt, %.md, ${var}}
all:
@echo ${var}
@echo ${pat}
# 输出: ./foo.txt ./bar.txt \ ./foo.md ./bar.md
- 根据相应规则替换文件名
技巧
Makefile中获取当前执行的Makefile所在路径
Linux下我们可以用pwd命令来获取当前所执行命令的目录,在Makefile中对应可用
PWD := $(shell pwd)
来获取。但是如果子Makefile 文件是从别处执行的(通过
make -f .../Makefile
执行),那么$(shell pwd)
得到的目录即为执行make -f
命令的当前目录在这种情况下
- 根据gnu make定义,
gnu make
会自动将所有读取的makefile
路径都会加入到MAKEFILE_LIST
变量中,而且是按照读取的先后顺序添加 - 所以可以通过
$(abspath $(lastword $(MAKEFILE_LIST)))
返回当前正在被执行的Makefile
的绝对路径,然后通过patsubst
去掉文件名得到绝对目录
- 根据gnu make定义,
代码:
1
2
3
4
5
6makefile_path:=$(abspath $(lastword $(MAKEFILE_LIST)))
cur_makefile_path:=$(patsubst %/makefile, %/, ${shell ls $(makefile_path)})
all:
@echo ${makefile_path}
@echo ${cur_makefile_path}