元编程

2020-12-13 15:53:51

“元编程”是什么意思?嗯,这是我们可以提出的最好的集体术语,它涉及的更多内容是过程而不是编写代码或更有效地工作。在本讲座中,我们将研究构建和测试代码的系统,以及管理依赖性。在您作为学生的日常工作中,这些似乎似乎无足轻重,但是当您通过实习与更大的代码库进行交互时,或者一旦您进入“现实世界”,您将在任何地方看到它。我们应该注意,“元编程”也可以表示“在程序上运行的程序”,但这并不是我们在本讲座中使用的定义。

如果您在LaTeX中写论文,则需要执行哪些命令来生产论文?那些用于运行基准测试,绘制基准然后将其插入到论文中的基准呢?还是要编译您正在上课的课程中提供的代码,然后运行测试?

对于大多数项目,无论它们是否包含代码,都有一个“ buildprocess”。从输入到输出,您需要执行一些操作序列。通常,该过程可能有很多步骤,并且分支很多。运行此命令以生成该图,以生成那些结果,并进行其他操作以生成最终论文。就像我们在课堂上看到的很多事情一样,您并不是第一个遇到这种烦恼的人,幸运的是,有很多工具可以帮助您!

这些通常称为“构建系统”,其中有很多。您使用哪种系统取决于手头的任务,您的偏好语言以及项目的规模。在他们的核心,他们却非常相似。您定义了许多依赖关系,许多目标以及从一个到另一个的规则。您告诉构建系统您想要一个特定的目标,它的工作是找到该目标的所有传递依赖关系,然后应用规则以一路产生中间目标,直到最终目标产生为止。理想情况下,构建系统无需对依赖关系未发生变化且目标可从以前的构建中获得结果的目标执行不必要的规则。

make是最常用的构建系统之一,通常您会发现它几乎安装在任何基于UNIX的计算机上。它有疣,但对于简单到中等的项目效果很好。运行make时,它将在当前目录中查询名为Makefile的文件。所有目标,它们的依存关系以及规则都在该文件中定义。让我们看一个:

该文件中的每个指令都是有关如何使用右侧产生左侧的规则。或者用不同的措词,在右侧命名的事物是依赖关系,而在左侧命名为目标。缩进块是一系列程序,用于从那些依赖项生成目标。在make中,第一个指令还定义了默认目标。如果运行不带任何参数的make,则这是它将建立的目标。另外,您可以运行诸如make plot-data.png之类的东西,它将代替该目标。

规则中的%是“模式”,将匹配左右两侧的相同字符串。例如,如果请求目标plot-foo.png,make将查找依赖项foo.dat和plot.py。现在,让我们看一下如果使用空源目录运行make。

make有助于告诉我们要生成paper.pdf,需要paper.tex,并且没有规则告诉它如何制作该文件。让我们尝试制作!

$ touch paper.tex $ make make:***没有规则可以使target' paper.pdf'成为目标。停止。

嗯,有趣的是,有一个制作plot-data.png的规则,但这是一个模式规则。由于源文件不存在(foo.dat),makeimply指出无法创建该文件。让我们尝试创建所有文件:

$ 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 matplotlibimport matplotlib.pyplot as pltimport numpy as npimport argparseparser = 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 12 23 34 45 8

它什么也没做!为什么不?好吧,因为它不需要。它检查了所有先前构建的目标相对于列出的依赖项是否仍是最新的。我们可以通过修改paper.tex然后重新运行make来进行测试:

注意make没有重新运行plot.py,因为那是不必要的; plot-data.png的依赖项都没有改变!

在更宏观的层面上,您的软件项目可能具有本身就是项目的依赖性。您可能依赖于编程语言中的已安装程序(例如python),系统软件包(例如openssl)或库(例如matplotlib)。如今,大多数依赖关系将通过可在单个位置托管大量此类依赖关系的存储库提供,并为安装它们提供了便捷的机制。一些示例包括用于Ubuntu系统软件包的Ubuntu软件包系统信息库,您可以通过apt工具访问该系统,通过Ruby库的RubyGems,用于Python库的PyPi或用于Arch Linux用户提供的软件包的Arch用户系统信息库。

Warning: Can only detect less than 5000 characters

大多数大型软件项目都带有“测试套件”。您可能已经熟悉测试的一般概念,但是我们认为我们会迅速提到一些您可能在野外遇到的测试和测试术语的方法:

集成测试:一种“宏观测试”,在系统的较大部分运行,以检查不同的功能部件或组件是否可以协同工作。

回归测试:一种实现特定模式的测试,该模式先前导致一个错误,以确保该错误不会再次出现。

模拟:用假实现替换功能,模块或类型,以避免测试不相关的功能。例如,您可以“模拟网络”或“模拟磁盘”。

大多数makefile提供一个称为clean的目标。这并不是要产生一个称为clean的文件,而是要清理所有可以由make重建的文件。将其视为“撤消”所有构建步骤的一种方式。为上面的paper.pdf Makefile实现一个干净的目标。您必须将目标虚假化。您可能会发现gitls-files子命令有用。此处列出了许多其他非常常见的make目标。

看一下为Rust构建系统中的依赖关系指定版本要求的各种方法。大多数软件包存储库都支持类似的语法。对于每一个(插入号,波浪号,通配符,比较和倍数),请尝试提出一个用例,在该用例中,这种特定种类的需求是有意义的。

Git本身就可以充当简单的CI系统。在任何git存储库内的.git / hooksinside中,您将找到(当下处于非活动状态)在特定操作发生时作为脚本运行的文件。编写一个运行make paper.pdf的预提交挂钩,如果make命令失败,则拒绝提交。这样可以防止任何提交都具有无法构建的纸张版本。

使用GitHubPages建立一个简单的自动发布页面。向存储库添加GitHub Action以对该存储库中的任何shell文件运行shellcheck(这是一种执行方法)。 检查它是否有效! 构建您自己的GitHub动作以在存储库中的所有.md文件上运行proselint或写良好。 在您的存储库中启用它,并通过提交带有错字的拉取请求来检查它是否工作。