为什么我们可以自己编写makefile,却需要使用像Autotools这样的构建工具?

67

最近,我将我的开发环境从Windows切换到了Linux。到目前为止,我只使用Visual Studio进行C ++开发,所以许多概念,比如makeAutotools,对我来说是新的。我已经阅读了GNU makefile文档,并对它有了基本的理解。但是我对Autotools有点困惑。

据我所知,makefile用于使构建过程更加容易。

  1. 为什么我们需要像Autotools这样的工具来创建makefile?既然大家都知道如何创建makefile,我不明白Autotools的真正用途。
  2. 什么是标准?我们需要使用这样的工具还是手写makefile就可以了?
8个回答

92
您在这里谈论了两个分开但相互关联的事情:
  • Autotools
  • GNU编码标准
在Autotools中,您有几个项目:
  • Autoconf
  • Automake
  • Libtool
让我们逐个看一下。 Autoconf Autoconf可以轻松扫描现有的树来查找其依赖项并创建一个在几乎任何类型的shell下运行的配置脚本。配置脚本允许用户控制构建行为(即--with-foo--without-foo--prefix--sysconfdir等),以及执行检查以确保系统可以编译程序。
配置生成一个config.h文件(从模板中),程序可以包含它以解决可移植性问题。例如,如果未定义HAVE_LIBPTHREAD,则使用forks。
我个人在许多项目中使用Autoconf。人们通常需要一些时间来适应m4。然而,它确实节省时间。
您可以使makefile继承configure找到的一些值,而不使用automake。 Automake 通过提供一个简短的模板,描述将构建哪些程序以及需要链接到它们的对象,可以自动创建符合GNU编码标准的Makefile。这包括依赖项处理和所有必需的GNU目标。

有些人觉得这样更容易。我更喜欢自己编写makefile。

Libtool

Libtool是一种非常酷的工具,可简化在任何类Unix系统上构建和安装共享库的过程。有时我会使用它;其他时候(特别是只构建静态链接对象时)我会手动完成。

还有其他选择,请参见StackOverflow问题Alternatives to Autoconf and Autotools?

构建自动化和GNU编码标准

简而言之,如果您向大众发布代码,则确实应该使用某种可移植的构建配置系统。您可以自行决定使用什么。GNU软件已知可以在几乎任何系统上构建和运行。但是,您可能不需要遵循如此(有时极端龟毛的)标准。

如果您为POSIX系统编写软件,我建议尝试使用Autoconf。仅因为Autotools生成与GNU标准兼容的构建环境的一部分并不意味着您必须遵循这些标准(许多人都没有!):) 还有很多其他选择。

编辑

不要害怕m4 :) 总有Autoconf macro archive。有很多示例或可用的检查。编写自己的或使用经过测试的内容。Autoconf太经常与Automake混淆。它们是两个不同的东西。


2
@janneb libtool之所以存在是因为在某些系统上构建共享库非常困难,没有libtool几乎不可能支持这些系统,因为它们需要大量额外的操作。Linux并不需要这些操作...而Windows可能需要你做一些额外的操作才能获得工作的共享库,特别是如果你关心人们使用VC++而不是mingw。所以,是的,libtool存在有很好的理由。它处理的另一件事情是像位置无关代码、共享和静态等方面的问题(有时你需要使用不同的选项进行构建)。 - Spudd86

34
首先,Autotools不是一个不透明的构建系统,而是一个松散耦合的工具链,正如tinkertim所指出的那样。让我补充一些关于Autoconf和Automake的想法: Autoconf是配置系统,它基于特性检查创建configure脚本,这些特性检查应该在各种平台上都能正常工作。在其15年的存在期间,很多系统知识已经进入了它的m4宏数据库中。一方面,我认为后者是Autotools尚未被其他东西取代的主要原因。另一方面,当目标平台更加异构化时,例如需要支持Linux、AIXHP-UXSunOS等以及大量不同的处理器架构时,Autoconf曾经非常重要。如果您只想支持最新的Linux发行版和Intel兼容处理器,我真的看不出它有什么用处。 Automake是GNU Make的抽象层,并从更简单的模板生成Makefile。一些项目最终摆脱了Automake的抽象层,并回归手动编写Makefile,因为您会失去对自己的Makefile的控制,并且您可能不需要所有混淆您的Makefile的预定义构建目标。
现在来谈谈替代方案(我强烈建议根据您的要求选择Autotools的替代方案):

CMake的最大成就是在KDE中替代了AutoTools。如果你想要具有类似Autoconf的功能而不带有m4怪异性,那么这可能是最接近Autoconf的选择。它为Windows支持提供了解决方案,并已被证明适用于大型项目。我对CMake的不满在于,它仍然是一个Makefile生成器(至少在Linux上),具有所有固有问题(例如Makefile调试、时间戳签名、隐式依赖顺序)。

SCons是一个用Python编写的Make替代工具。它使用Python脚本作为构建控制文件,允许使用非常复杂的技术。不幸的是,它的配置系统与Autoconf不相匹配。当适应特定要求比遵循公约更重要时,SCons通常用于内部开发。

如果你真的想坚持使用Autotools,我强烈建议阅读Recursive Make Considered Harmfularchived),并编写自己的GNU Makefile通过Autoconf进行配置。


Autoconf有许多用途,不仅仅是进行琐碎的检查,例如快速查找foo/foo.h中的struct foo是否有名为“bar”的成员,libfoo的版本等。此外,在制作.deb/.rpm软件包时,构建时间选项确实非常有帮助。但是,我想这只是个人偏好的问题。 - Tim Post
@tinkertim:你说得没错,但这并不能使Autoconf在与其他构建系统的对比中脱颖而出。你举的例子在SConf(SCons的配置子系统)中可以很容易地实现。然而,所有的健全性检查和我甚至想不到的检查都可以在Autoconf中免费获得。 - Pankrat
在修复《递归Make有害论》的破损链接时,我发现了2016年的以下内容:非递归Make有害论 - 在这里放置以作对比 :) - toraritte

26
已经提供的答案很好,但如果您有任何类似于标准C / C ++项目的东西,请强烈建议不要采用编写自己的makefile的建议。我们需要使用autotools而不是手写的makefile,因为由automake生成的符合标准的makefile提供了许多有用的目标,并以众所周知的名称提供所有这些目标,手动提供所有这些目标非常繁琐且容易出错。
首先,手动编写Makefile似乎是个好主意,但大多数人都不会费心编写除all、install和可能的clean之外的规则。 automake生成了dist、distcheck、clean、distclean、uninstall和所有这些小助手。这些额外的目标对最终安装软件的系统管理员非常有益。
其次,在可移植且灵活的方式中提供所有这些目标相当容易出错。我最近进行了很多针对Windows目标的交叉编译,autotools表现得非常好。与大多数手写文件相比,它们通常很难编译。请注意,通过手动方式创建良好的Makefile是可能的。但是不要高估自己,这需要很多关于各种不同系统的经验和知识,并且automake可以立即为您创建出色的Makefile。
编辑:并且不要尝试使用"替代品"。 CMake和其他类似的软件对部署者来说是一种恐怖,因为它们与configure及其相关工具不兼容。任何半路出家的系统管理员或开发人员都可以做出像交叉编译这样的重要任务,或仅仅是通过自己的头脑或使用配置脚本的简单--help设置前缀。但是当您必须在BJam上处理此类事物时,您将为其花费一到三个小时。别误会,BJam在内部可能是一个很棒的系统,但是由于几乎没有项目使用它,并且文档很少而且不完整,因此使用起来非常麻烦。在已建立的知识方面,autoconf和automake在这里拥有巨大的优势。

因此,尽管我对这个问题的建议有点晚:还是请你使用autotools和automake。语法可能有点奇怪,但它们比99%的开发人员自己做的要好得多。


12

对于小项目或仅在一个平台上运行的大型项目,手写Makefile 是最好的选择。

当您需要为需要不同选项的不同平台编译时,Autotools 真正发挥作用。 Autotools 经常是典型的

./configure

make

make install

Linux 库和应用程序的编译和安装步骤背后的智慧。

尽管如此,我认为 Autotools 会让人感到痛苦,而且我一直在寻找更好的系统。 最近,我一直在使用 bjam,但它也有其缺点。 祝你好运,找到适合自己的方法。


7

需要使用Autotools,因为Makefile不能保证在不同平台上的工作方式相同。如果您手写一个Makefile,在您的机器上可以工作,但很可能在我的机器上无法正常工作。


6
你知道你的用户将使用哪个Unix系统吗?甚至是哪个Linux发行版?你知道他们想要在哪里安装软件吗?你知道他们有哪些工具,他们想编译什么架构,他们有多少个CPU,有多少RAM和磁盘空间可用?
*nix世界是一个跨平台的领域,你的构建和安装工具需要处理这个问题。
请注意,auto*工具来自早期时代,有很多合理的抱怨,但是几个项目试图用更现代的替代品取代它们,却难以获得发展势头。
在*nix世界中有很多类似的事情。

4
Autotools是一场灾难。生成的./configure脚本检查了过去20年左右没有在任何Unix系统上出现的功能。为此,它花费了大量时间。运行./configure需要很长时间。尽管现代服务器CPU可以拥有数十个核心,并且每个服务器可能有几个这样的CPU,但./configure是单线程的。我们仍然有足够多的摩尔定律年份留下,CPU核心数量将随着时间的推移而大幅增加。因此,./configure所需的时间将保持大致恒定,而由于摩尔定律,并行构建时间每2年就会减少2倍。或者实际上,我会说,./configure所需的时间甚至可能会增加,因为软件复杂性不断提高,利用了改进的硬件。仅添加一个文件到您的项目中的简单操作需要运行automake、autoconf和./configure,这将需要很长时间,然后您可能会发现,由于某些重要文件已更改,所有内容都将被重新编译。因此,只需添加一个文件,make -j${CPUCOUNT}就会重新编译所有内容。

关于make -j${CPUCOUNT}。生成的构建系统是递归的。递归make长期以来被认为是有害的

然后,当您安装已编译的软件时,您会发现它无法正常工作。(需要证明吗?从Github克隆protobuf存储库,检查提交9f80df026933901883da1d556b38292e14836612,将其安装到Debian或Ubuntu系统中,然后嘿——预备: protoc: error while loading shared libraries: libprotoc.so.15: cannot open shared object file: No such file or directory ——因为它在/usr/local/lib而不是/usr/lib; 解决方法是在输入make之前执行export LD_RUN_PATH=/usr/local/lib)。

理论上,使用Autotools可以创建一个软件包,可以在Linux、FreeBSD、NetBSD、OpenBSD、DragonflyBSD和其他操作系统上编译。事实上呢?每个非Linux系统从源代码构建软件包时都需要在其存储库中有大量的补丁文件来解决Autotools的缺陷。只需看看如FreeBSD /usr/ports:它充满了补丁。因此,为每个项目基础上的非Autotools构建系统创建一个小补丁可能比为每个项目基础上的Autotools构建系统创建一个小补丁更容易,甚至更容易,因为标准的make比Autotools更容易使用。
事实上,如果你基于标准的make创建自己的构建系统(并使其具有包容性而不是递归性,遵循“递归make被认为是有害的”论文的建议),事情会更好。此外,如果您的项目非常小,只有10-100个C语言文件,并且每个CPU有数十个核心和多个CPU,则构建时间将降低一个数量级,甚至两个数量级。使用基于标准make的自定义构建系统与自定义自动代码生成工具进行接口也比处理autotools的m4混乱要容易得多。使用标准的make,您至少可以在Makefile中键入shell命令。

因此,回答你的问题:为什么使用autotools?答案是:没有理由这样做。自商业Unix已经过时以来,Autotools一直过时了。多核CPU的出现使Autotools变得更加过时。为什么程序员还没有意识到这一点,是一个谜。我很高兴在我的构建系统中使用标准的make。是的,需要一些工作来生成C语言头文件包含的依赖关系文件,但是不必与autotools斗争,从而节省了大量工作。


你是否曾经使用过Autotools编写项目?当然,将shell命令放入autoconf宏中是可行的。关于它们运行“缓慢”这一点 - 实际上构建一个较大的已配置项目需要消耗更多的总构建时间...等等... - Dima Pasechnik

1
我不认为自己是专家,但我可以通过我的经验给你一个类比。
这在某种程度上与为什么我们应该使用C语言(高级语言)编写嵌入式代码而不是汇编语言非常相似。两者都解决了同样的问题,但后者更冗长、繁琐、耗时,并且更容易出错(除非您非常了解处理器的ISA)。同样的情况也存在于Automake工具和编写自己的makefile之间。编写Makefile.am和configure.ac比编写单个项目的Makefile要简单得多。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接