【C++进阶】Makefile基础(二)

文章目录

    • 1. 变量
      • 1.1 自动变量
      • 1.2 特殊变量
      • 1.3 变量的类型
      • 1.4 变量值的来源
      • 1.5 高级变量的引用功能
      • 1.6 override指令
      • 1.7 总结
    • 2. 模式
    • 3. 函数
      • 3.1 addprefix
      • 3.2 filter
      • 3.3 filter-out
      • 3.4 patsubst
      • 3.5 strip
      • 3.6 wildcard

1. 变量

1.1 自动变量

自动变量是Makefile中的一种特殊变量,它们在规则中的命令行被执行时自动设置。以下是一些常用的自动变量:

  • $@:代表当前目标
  • $^:代表所有依赖文件,以空格分隔,不包含重复的依赖文件
  • $<:代表第一个依赖文件
  • $?:代表所有比目标更新的依赖文件,以空格分隔
  • $*:代表目标文件名中去掉后缀的部分

例如:

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

在这个例子中,$<表示当前规则的第一个依赖文件(对应某个.c文件),$@表示当前规则的目标(对应某个.o文件)。

1.2 特殊变量

特殊变量是Makefile中的预定义变量,它们具有特定的含义和功能。

  • MAKE:当前正在执行的Make命令
  • MAKEFILE_LIST:已经包含的Makefile文件列表
  • MAKECMDGOALS:当前执行的目标

1.3 变量的类型

在Makefile中,变量可以分为两类:简单变量和递归变量。

  • 简单变量:简单变量使用 := 进行赋值。它们在赋值时就会被展开
  • 递归变量:递归变量使用 = 进行赋值。它们在使用时才会被展开

例如:

VAR1 = $(VAR2)
VAR2 := hello world

在这个例子中,VAR1 是一个递归变量,VAR2 是一个简单变量。

1.4 变量值的来源

变量的值可以来源于以下途径:

  • 直接在Makefile中赋值
  • 命令行参数传递
  • 环境变量

1.5 高级变量的引用功能

在Makefile中,我们可以使用高级变量引用来更灵活地处理变量。例如:

  • $(VAR:str1=str2):在变量VAR的值中,将所有的str1替换为str2。

1.6 override指令

在Makefile中,我们可以使用override指令来强制使用Makefile中的变量值,即使该变量已经在命令行中定义。例如:

CFLAGS = -Wall
override CFLAGS += -g

在这个例子中,我们使用了override指令来确保CFLAGS变量在Makefile中的定义被保留,而不是被命令行中的定义覆盖。即使在命令行中重新定义了CFLAGS,Makefile中的CFLAGS仍会被追加-g选项。

1.7 总结

我们通过一个Makefile示例来展示上述讨论的各种变量类型和功能:

CC = gcc
CFLAGS = -Wall
override CFLAGS += -g
SRC = main.c foo.c bar.c

OBJS = $(SRC:.c=.o)

.PHONY: all clean

all: my_program

my_program: $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

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

clean:
	rm -f $(OBJS) my_program

在这个Makefile中:

  • 我们定义了简单变量CCCFLAGSSRC
  • 使用override指令确保CFLAGS在Makefile中的定义不被命令行参数覆盖
  • 使用高级变量引用$(SRC:.c=.o)将所有.c文件转换为.o文件列表
  • 在目标my_program的命令行中,使用自动变量$@代表当前目标(my_program),使用$^代表所有依赖文件($(OBJS))。

2. 模式

Makefile 中的模式是一种简化书写 Makefile 的方法,它允许你为多个类似的目标定义通用规则。模式规则有一个或多个模式,通过使用通配符(%)表示。通配符可以匹配任意字符串。这使得我们可以为多个目标使用相同的规则,而不必为每个目标单独编写规则。

以下是一些常见的 Makefile 模式的例子:

  1. 编译 C 文件为目标文件(.o):

    %.o: %.c
        gcc -c $< -o $@
    

    这个模式表示:任何以.o结尾的文件(目标文件)都依赖于一个对应的以.c结尾的文件(源文件)。规则中的命令行告诉编译器如何从源文件生成目标文件。$<$@是自动变量,分别代表依赖文件和目标文件。

  2. 编译 C++ 文件为目标文件(.o):

    %.o: %.cpp
        g++ -c $< -o $@
    

    这个模式与上面的例子类似,只是它适用于 C++ 源文件。

  3. 将多个目标文件链接为一个可执行文件:

    my_program: main.o helper.o
        gcc $^ -o $@
    
    main.o: main.c
        gcc -c $< -o $@
    
    helper.o: helper.c
        gcc -c $< -o $@
    

    在这个例子中,我们没有使用模式,但我们可以用模式规则简化它:

    my_program: main.o helper.o
    	gcc $^ -o $@
    
    %.o: %.c
        gcc -c $< -o $@
    

    这个简化后的 Makefile 适用于所有 C 文件,而不仅仅是 main.c 和 helper.c。

  4. 在一个目录中生成 PDF 文件:

    %.pdf: %.tex
        pdflatex $<
    

    这个模式表示:任何以.pdf结尾的文件都依赖于一个对应的以.tex结尾的文件。规则中的命令行告诉 pdflatex 如何从 LaTeX 源文件生成 PDF 文件。

3. 函数

Makefile 中的函数提供了一些实用的文本操作功能,可以让你更容易地处理文件名和路径。

3.1 addprefix

作用:给列表中的每个单词添加指定的前缀

语法:$(addprefix , )

示例:

files = file1.txt file2.txt file3.txt
prefixed_files = $(addprefix backup/, $(files))

# 结果:prefixed_files = backup/file1.txt backup/file2.txt backup/file3.txt

3.2 filter

作用:从列表中筛选出符合模式的单词

语法:$(filter , )

示例:

files = file1.txt file2.cpp file3.h file4.c
c_files = $(filter %.c, $(files))

# 结果:c_files = file4.c

3.3 filter-out

作用:从列表中移除符合模式的单词

语法:$(filter-out , )

示例:

files = file1.txt file2.cpp file3.h file4.c
non_c_files = $(filter-out %.c, $(files))

# 结果:non_c_files = file1.txt file2.cpp file3.h

3.4 patsubst

作用:根据指定的模式替换列表中的单词

语法:$(patsubst , , )

示例:

files = file1.txt file2.txt file3.txt
csv_files = $(patsubst %.txt, %.csv, $(files))

# 结果:csv_files = file1.csv file2.csv file3.csv

3.5 strip

作用:去除列表中的单词的前导和尾随空白字符

语法:$(strip )

示例:

text =      foo    bar   baz
stripped_text = $(strip $(text))

# 结果:stripped_text = foo bar baz

3.6 wildcard

作用:返回符合指定模式的文件列表

语法:$(wildcard )

示例:

src_files = $(wildcard *.c)
# 结果:src_files = file1.c file2.c file3.c(假设目录中存在这些文件)

你可能感兴趣的:(C++,c++,linux,运维)