Makefile¶
Makefile 是一个用来描述源文件之间的依赖关系以及如何编译和链接这些源文件的脚本文件。它可以大大简化编译过程,使得代码的维护和管理更加方便。我们建议同学们在 lab2 以及 lab3 中使用 Makefile 编写编译脚本,以便助教检查实验。
Makefile 的功能非常强大,我们在此给出一些基础的介绍以及一些参考资料,如有感兴趣的同学可以参考或自行搜索相关资料。
Makefile 有一套专用的语法系统,大致语法规则如下:
target ... : prerequisites ...
    recipe
    ...
    ...
target 可以是一个 object file(目标文件),也可以是一个可执行文件,还可以是一个标签(label)。
prerequisites 生成该target所依赖的文件和/或target。
recipe 该 target 要执行的命令(任意的 shell 命令)。
这是一个文件的依赖关系,也就是说,target 这一个或多个的目标文件依赖于 prerequisites 中的文件,其生成规则定义在 recipe 中。
prerequisites 中如果有一个以上的文件比 target 文件要新的话,recipe 所定义的命令就会被执行。
以下是一个简单的 Makefile 示例:
# 定义编译器和编译选项
CC = g++
CFLAGS = -O2
VERSION = -std=c++11
# 定义目标文件和源文件
TARGET = program
SRCS = main.cpp utils.cpp
# 生成可执行文件
$(TARGET): $(SRCS)
    $(CC) $(CFLAGS) $(VERSION) -o $@ $^
# 清理文件
clean:
    rm -f $(TARGET)
在这个示例中:
CC 定义了使用的编译器(这里是 g++)。
CFLAGS 定义了编译选项(这里开启了编译优化选项-O2)。
VERSION 指定了编译器使用的 C++版本。
TARGET 定义了最终生成的可执行文件的名称。
SRCS 定义了源文件的列表。
$(TARGET): $(SRCS) 表示 TARGET 依赖于 SRCS 中的所有源文件。
$(CC) $(CFLAGS) -o $@ $^ 是编译和链接的命令,$@ 表示目标文件,$^ 表示所有依赖文件。
clean 是一个伪目标,用于清理生成的可执行文件。
$后面紧跟某个变量即为在此处用这个变量的值替换其内容,例如,$(CC)将会被替换成变量 CC 的值,即 g++。
如果在当前目录只使用 make 命令,Makefile 会查找到文件中的第一个目标文件,在本示例中为 $(TARGET),即 program,并使用 $(CC) $(CFLAGS) -o $@ $^,即 g++ -O2 -o program main.cpp utils.cpp 编译目标文件。
注:从网页上复制的 Makefile 文件会将 tab 缩进替换为四个空格,复制后请替换回去,以免 Makefile 无法识别命令。
练习¶
「必做」
以下是一些示例代码文件:
main.cpp
#include <iostream>
#include "bubblesort.hpp"
int main() {
    std::vector<int> arr = {64, 34, 25, 12, 22, 11, 90};
    bubbleSort(arr);
    for (int num : arr) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
bubblesort.cpp
#include <iostream>
#include <vector>
void bubbleSort(std::vector<int>& arr) {
    int n = arr.size();
    for (int i = 0; i < n - 1; ++i) {
        for (int j = 0; j < n - i - 1; ++j) {
            if (arr[j] > arr[j + 1]) {
                std::swap(arr[j], arr[j + 1]);
            }
        }
    }
}
bubblesort.hpp
#include <iostream>
#include <vector>
void bubbleSort(std::vector<int>& arr);
请你将上述三段代码复制到lab0/目录下,并在该目录下:
参照上述示例 Makefile 格式,编写 Makefile 文件来编译这段代码,输出可执行文件命名为 bubble_sort.
要求:
- 使用 
make命令时,编译生成可执行文件 - 使用 
make clean命令时,删除生成的可执行文件 
「选做」
请你参考 C++的宏机制以及 g++的编译选项,在 Makefile 中加入一段代码,以及对 cpp 源代码进行适当修改,来打印出冒泡排序中每次交换元素之后的 vector 的值。
要求:
- 使用 
make debug命令时,编译生成的可执行文件在每次交换元素之后会打印出 vector 的值 (debug 信息),与此同时,使用make命令生成的可执行文件不会打印 debug 信息 
参考资料:
- https://seisman.github.io/how-to-write-makefile/introduction.html
 - https://www.gnu.org/software/make/manual/make.html
 - https://makefiletutorial.com/