元编程

构建系统

make 是最常用的构建系统之一，您会发现它通常被安装到了几乎所有基于 UNIX 的系统中。make 并不完美，但是对于中小型项目来说，它已经足够好了。当您执行 make 时，它会去参考当前目录下名为 Makefile 的文件。

Copy
paper.pdf: paper.tex plot-data.png
pdflatex paper.tex

plot-%.png: %.dat plot.py
./plot.py -i $*.dat -o $@

冒号左侧的是构建目标，冒号右侧的是构建它所需的依赖。缩进的部分是从依赖构建目标时需要用到的一段程序。在 make 中，第一条指令还指明了构建的目的，如果您使用不带参数的 make，这便是我们最终的构建结果。或者，您可以使用这样的命令来构建其他目标：make plot-data.png。

Copy
$ cat paper.tex
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics[scale=0.65]{plot-data.png}
\end{document}
$ cat plot.py
#!/usr/bin/env python
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-i', type=argparse.FileType('r'))
parser.add_argument('-o')
args = parser.parse_args()

data = np.loadtxt(args.i)
plt.plot(data[:, 0], data[:, 1])
plt.savefig(args.o)
$ cat data.dat
1 1
2 2
3 3
4 4
5 8

依赖管理

持续集成系统

课后练习

习题解答

大多数的 makefiles 都提供了一个名为 clean 的构建目标，这并不是说我们会生成一个名为 clean 的文件，而是我们可以使用它清理文件，让 make 重新构建。您可以理解为它的作用是 “撤销” 所有构建步骤。在上面的 makefile 中为 paper.pdf 实现一个 clean 目标。您需要将构建目标设置为 phony。您也许会发现 git ls-files 子命令很有用。其他一些有用的 make 构建目标可以在这里找到；

Copy
paper.pdf: paper.tex plot-data.png
pdflatex paper.tex

plot-%.png: %.dat plot.py
./plot.py -i $*.dat -o $@

.PHONY: clean
clean:
Rm *. Pdf *. Aux *. Log *. Png
#git ls-files -o | xargs rm -f

~$ cat makefile
paper.pdf: paper.tex plot-data.png
pdflatex paper.tex

plot-%.png: %.dat plot.py
./plot.py -i $*.dat -o $@

.phony: clean
clean:
mkdir -p Untrack
rm -f *~ .*~
git ls-files -o | grep -v Untrack | xargs -r mv -u -t Untrack

~$ cat .gitignore
Untrack
# 设置git忽略该目录，用来放置untracked文件

指定版本要求的方法很多，让我们学习一下 Rust 的构建系统的依赖管理。大多数的包管理仓库都支持类似的语法。对于每种语法 (尖号、波浪号、通配符、比较、乘积)，构建一种场景使其具有实际意义；

Git 可以作为一个简单的 CI 系统来使用，在任何 git 仓库中的 .git/hooks 目录中，您可以找到一些文件（当前处于未激活状态），它们的作用和脚本一样，当某些事件发生时便可以自动执行。请编写一个pre-commit 钩子，它会在提交前执行 make paper.pdf并在出现构建失败的情况拒绝您的提交。这样做可以避免产生包含不可构建版本的提交信息；

基于 GitHub Pages 创建任意一个可以自动发布的页面。添加一个GitHub Action 到该仓库，对仓库中的所有 shell 文件执行 shellcheck(方法之一)；

构建属于您的 GitHub action，对仓库中所有的.md文件执行proselint 或 write-good，在您的仓库中开启这一功能，提交一个包含错误的文件看看该功能是否生效。