Makefile,“配置”文件和其他编译工具 - 它们如何工作?他们为什么按照他们的方式工作?

时间:2011-03-22 09:17:17

标签: makefile mingw configure makefile-project

我还是UNIX / Linux世界的新手,尤其是相关工具,比如GCC编译器。也就是说,我仍然是makefiles和类似东西的新手(我在Windows上使用MinGW),因为到目前为止,我的大多数开发都是使用像Visual Studio和Eclipse这样的IDE。

当我打开一个典型的项目文件夹时,我会看到这样的文件:

configure
make
INSTALL
install-sh  (or a variant)

这里有很多我不明白的事情,我的主要问题是:

  1. 这些之间有什么区别,为什么我们需要每一个? (在IDE世界中,你所拥有的只是一个项目文件;就是这样。所以我很困惑为什么我们这里不仅仅是一个makefile。)

  2. 这些文件是如何生成的?对于小型项目,您可以手工编写它们,但对于像GCC这样的大型项目,即使尝试也是荒谬的。我发现编辑这些文件很痛苦,我得出的结论是我不应该手动修改它们。但如果是这样,那么人们通常使用哪些工具来添加和修改这些文件?

  3. 为什么他们不在makefile中使用通配符?为什么每个目标文件都有一行?这是因为限制,还是有优势呢?

  4. 有一个shell脚本调用编译器和每个文件,并且 makefile 执行相同的操作有什么区别?在Windows中,我很想在文件夹中创建批处理文件,并使用它编译所有内容 - 不需要只有一个文件。有什么不同?为什么不只有一个.sh文件来编译所有内容?

  5. 奖金问题:

    • 是否有“标准”makefile格式?我见过不同的make工具不接受彼此的格式......我怎么知道使用什么? GCC只是通常的工具,还是每个人都应遵循一些标准?

    我可能会有更多问题,因为我对此类项目的结构有了更多了解,但就目前而言,这些是我最大的问题。 :)

3 个答案:

答案 0 :(得分:15)

  1. 在普通包装中,这些文件各有特定目的。这与unix的理念是一致的,即“每个程序应该做一件事并做好事”。在大多数项目中,您将看到如下文件:

    • configure
    • configure.ac
    • Makefile
    • Makefile.in
    • Makefile.am
    • install-sh
    • INSTALL

    configure(通常)是一个shell脚本,它在构建任何内容之前检查系统是否具有所有必需的功能。 Makefile.inMakefile的模板。配置测试的结果将替换为Makefile.in以生成Makefile。这是为了处理人们在不明确的路径中有事物(编译器,标题,库),交叉编译(例如,在x86上为ARM构建),可选的库支持(某些程序具有可以打开或关闭的附加功能),使用不同的选项进行编译,等等。写一个万能的Makefile实际上真的很难

    正如您所注意到的,configure脚本本身就是一团糟。它既不是凡人的眼睛所见,也不是凡人的手所编辑。它实际上是使用名为configure.ac的程序编译autoconf的结果。 autoconfm4宏处理器周围的宏包和包装器,它是当时唯一的好工具(autoconf是非常古老的软件,但已经非常好了)。 autoconf允许开发人员轻松编写测试以检查构建软件所需的头文件,库或程序(这在程序之间有所不同)。

    如果你深入挖掘一下,你会注意到Makefile.in也有点难看。这是因为写好Makefile s通常是很多样板,这激发了另一个工具automakeautomakeMakefile.am(通常是简短的和声明性的)编译成Makefile.in(这是巨大的),然后由Makefile(基本上)编译成configure

    install-sh是一个与automake一起分发但复制到其他包中的脚本。如果系统上install的版本是废话(install将文件复制到安装目录中,它就作为替代。一些非常旧的系统已经破坏了install的版本,{{1关于删除旧系统的警告是非常保守的)。其他一些履行类似角色的脚本是automakecompiledepcomp

    ylwrap只是一个描述如何安装软件包的文档。它通常是由INSTALL复制到包中的样板内容。

  2. 我已经在上面回答了这个问题,但这里是摘要:

    • automake
    • configure.ac ==[autoconf]=> configure

    负责程序在箭头内。为了详细了解这一点,我建议使用此autotools tutorial。不要被页数计算,大部分都是逐个出现的图表。

  3. 有时会使用Makefile.am ==[automake]=> Makefile.in ==[configure]=> Makefile中的通配符。例如,GNU Make支持Makefile函数,您可以在其中编写如下内容:

    $(wildcard)

    未使用SOURCES := $(wildcard src/*.c)等功能的主要原因是它们是扩展程序,$(wildcard)非常难以生成可与任何automake POSIX兼容Makefile。在项目成熟之后,无论如何,要编译的文件列表都不会发生太大变化。

    明确列出文件的第二个原因是程序获得可选功能。通配符不再合适,您必须列出编译其他功能的条件。

  4. A make跟踪文件之间的依赖关系,而shell脚本无法跟踪(无论如何都不会付出太大的努力)。

  5. 如果您有Makefile规则,请执行以下操作:

    Makefile

    告诉foo.out: foo.in generate-foo foo.in 如果make 较新而不是foo.in,则可以通过执行foo.out创建新的foo.out 。这节省了大型项目的大量冗余工作,您可能只在重新编译之间更改一个或两个文件。

    你的奖金问题似乎有些不合时宜。最常见的generate-foo foo.in可能是GNU Make,虽然我猜测BSD make会紧随其后,其次是Solaris,AIX等提供的各种专有make版本。

    这些都接受make中相同的基本结构(因为POSIX这样说),但可能具有特定于供应商的语法扩展。

    GCC不是Makefile之类的构建工具。 GCC是一个命令行编译器,类似于Windows上的make

答案 1 :(得分:5)

不同的事情有很多原因,但最终归结为可移植性。在unix战争期间,每个平台都是不同的,人们试图制作尽可能多的软件。因此必须找到共同的分母。 sh就是这样的共性,所以配置脚本被编写为使用最大可移植的sh。最大可移植性意味着使用最少的一组功能。 make的不同实现在它们支持的功能上有很大差异,因此编写了尽可能少使用的Makefile。今天的情况略好一些,但是可移植性问题仍然会引发很多你所看到的事情。

答案 2 :(得分:2)

  1. configure是一个脚本,用于设置构建环境并可能生成makefile。使用make构建项目,使用make installinstall.sh或类似项目,安装已编译的文件。如果你想在本地测试一些东西,你可能想把最后的部分留下来,所以它是分开的。
  2. 您可以使用GNU autotools
  3. 你能给出具体的例子吗? Makefile确实支持通配符,并且不时使用它们。
  4. 如果您更改源文件中的某些内容然后决定重建项目,Makefile将仅处理所需文件的依赖关系和自动重新编译。使用批处理文件,您将重新编译所有内容,使用Makefile时,您只需编译已更改的内容。