如何将 automake 文件写入递归构建子目录?

Posted

技术标签:

【中文标题】如何将 automake 文件写入递归构建子目录?【英文标题】:How to write automake files to recursive build subdirectories? 【发布时间】:2019-10-12 23:53:10 【问题描述】:

我的工作目录如下树所示:

./  
|--HelloWorld/  
|--|--main.cpp  
|--|--Dog/   
|--|--|--Dog.h  
|--|--|--Dog.cpp    
|--Pet/  
|--|--Pet.h  
|--|--Pet.cpp  
|--build/  

main.cpp 包括dog.hpet.h。 Dog 是 Pet 的继承类,所以Dog.h 也包含Pet.h。我知道这是一种组织代码的有线方式,但我只是好奇 如何为每个子目录创建 makefile.am 文件,以便 autotool 可以在构建目录中构建项目。

请注意,我想要一些额外的功能:

    是否可以在build 目录而不是build/HelloWorld/ 目录中构建hello.exe?为此,我是否必须将bin_PROGRAMS 放在./Makefile.am 我不想将 Pet 构建为库,我想知道是否有一种方法可以告诉 automake 在不同位置查找源代码。 我知道使用非递归生成文件会更容易。但我只想学习如何为多个目录创建递归 makefile。

我试过的是:

configure.ac

AC_PREREQ([2.69])
AC_INIT([Hello], [1.0], [qub@oregonstate.edu])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_CONFIG_SRCDIR([HelloWorld/main.cpp])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
#AC_PROG_CPP

AC_CONFIG_FILES([Makefile
                 HelloWorld/Makefile
                 Pet/Makefile
                 HelloWorld/Dog/Makefile])
AC_OUTPUT

Makefile.am

SUBDIRS = HelloWorld Pet

HelloWorld/Makefile.am

AM_CPPFLAGS=-I$(srcdir)/../Pet -I$(srcdir)/Dog 
SUBDIRS = Dog
bin_PROGRAMS=hello 
hello_SOURCES = main.cpp

宠物/Makefile.am

hello_SOURCES = Pet.h Pet.cpp

HelloWorld/Dog/Makefile.am

AM_CPPFLAGS=-I$(srcdir)/../../Pet

hello_SOURCES = Dog.h Dog.cpp 

我刚开始学习 automake 的东西,我知道这些代码根本不起作用。

谁能帮我解决它们?谢谢。

【问题讨论】:

密切相关:***.com/questions/58352194/… 【参考方案1】:

你说你有兴趣

如何为每个子目录创建makefile.am文件,以便autotool可以在构建目录下构建项目

,但这不是一个合适的目标,正如这个例子本身所展示的。没有定义任何要构建的目标的Makefile.am 很少有用或不合适。您已经规定您不想将 Pet 构建为库,那么其目录中的 Makefile.am 将定义什么目标?如果您想避免将其构建为库,则类似的情况适用于 Dog。在这种情况下使用递归 make 几乎没有意义。

不过,我确实注意到 Automake 具有“便利库”的概念,它是一个中间目标,它本身从未安装,但包含可以链接到可执行文件或更大库的目标代码。稍后我将对此进行演示,因为在这种特殊情况下,这是设置您要求的每个目录的 makefile 结构的最明智的方法。

另外,关于将输出定向到源树中的特定目录:这是可以做到的,但这可能是浪费精力。 Autotools 已经为源外构建提供了一种方便的方法,如果构建项目的人希望这样做,它可以更轻松地实现将构建结果与源代码分离的目标。

NEVERTHELESS、the basics of recursive builds with the Autotools 非常简单。主要有两件事要做:

每个想要将递归表达到一个或多个子目录的Makefile.am 都是通过在变量SUBDIRS 中列出每个子目录的相对路径来实现的。

项目configure.ac 必须通过其AC_CONFIG_FILES 宏指定要构建的Makefiles。

这就是一般设置递归所需要做的所有事情,如何设置特定目标和选项的详细信息是项目特定的。

    是否可以在build 目录而不是build/HelloWorld/ 目录中构建hello.exe?要做到这一点,我必须把 bin_PROGRAMS ./Makefile.am

是的,您可以指定构建到 build/hello 而不是 build/HelloWorld/hello。您可能没有严格将相应的bin_PROGRAMS 放入***Makefile.am,但您绝对应该把它放在那里或在build/Makefile.am 文件中。我敦促您避免尝试将任何 makefile 构建目标放在以特定 makefile 所在目录为根目录的树之外。

    我不想将 Pet 构建为库,我想知道是否有一种方法可以告诉 automake 在 不同的地点。

您绝对可以在与Makefile.am 不同的目录中指定源文件。只需提供相对于 makefile 目录的适当路径。这对于与 makefile 位于同一树中的源更有意义,但使用位于其他位置的源并不像尝试在其他位置构建目标那样大。

    我知道使用非递归生成文件会更容易。但我只想学习如何为多个创建递归makefile 目录。

非递归生成文件不一定比递归生成文件更容易,但它们通常更好,因为它们将整个目标/先决条件树表示为一个单元,而不是将其分割成多个部分。 make 可以在一次掌握所有信息时做出更好的构建决策。

我刚开始学习 automake 的东西,我知道这些代码不会 完全可以工作。

我对@9​​87654322@ 的回答为相关问题提供了递归解决方案。它演示了您似乎缺少的关键原则之一:指定目标的源和其他构建属性的变量需要出现在定义目标本身的同一 Makefile.am 文件中。每个Makefile.am 对应一个单独的makefile。大致而言,数据不会在 makefile 之间共享,因此构建给定目标所需的所有信息都需要出现在同一个目标中。

似乎将此问题与您的其他问题区分开来的另一件事是您希望(无论多么错误地)在您的makefile 中指定一个特定的输出目录。请记住,无论构建文件最初去哪里,它都是一个暂存区——这并不重要,因为它们被make install 放入最终目的地。即使这样,您也可以通过提供正确的相对路径来指定驻留在不同目录中的目标。当然,这样对目标名称的改变需要在the names of the variables derived from the target name中体现出来。

那么,这里是一个递归 Automake 设置,它应该使用每个源目录一个 makefile 来构建您的示例项目:


Makefile.am

SUBDIRS = Pet HelloWorld

# Note: specifying output into a different directory
bin_PROGRAMS = build/hello

# Note the form of the following names:
build_hello_SOURCES = HelloWorld/main.cpp
build_hello_CPPFLAGS = -I$(srcdir)/Pet -I$(srcdir)/HelloWorld/Dog
# Note that library order matters
build_hello_LDADD = HelloWorld/Dog/libDog.a Pet/libPet.a

宠物/Makefile.am

noinst_LIBRARIES = libPet.a

libPet_a_SOURCES = \
    Pet.cpp        \
    Pet.h

HelloWorld/Makefile.am

SUBDIRS = Dog

# No own targets defined here, just the recursion into Dog.  This could have been
# skipped altogether, but I'm sticking to the letter of one Makefile.am per source
# directory.

HelloWorld/Dog/Makefile.am

noinst_LIBRARIES = libDog.a

libDog_a_SOURCES = \
  Dog.cpp          \
  Dog.h
libDog_a_CPPFLAGS = -I$(top_srcdir)/Pet

您的 configure.ac 应该按原样使用。

注意这里不依赖VPATH;它特别地构建到构建树的build/ 子目录中,包括当您直接在源代码树中构建时。

【讨论】:

感谢@john Bollinger 的详细回答。我相信这会起作用,但是每个目录都构建到一个库中。只是好奇,有没有办法让make file只编译每个子目录里面的cpp文件,输出.o文件,然后让./makefile.am链接到main函数? @Burton,如果您对从未安装过的便利库都不满意,那么您提出的问题没有答案。我给出的答案已经解释了为什么会这样,但回顾一下:您只构建一个目标,并且有关任何给定目标的所有信息都需要进入同一个 Makefile (.am)。您提出的示例不适用于递归make,而便利库是强制其进入该范式的最佳可用住宿。他们为想要构建的额外 Makefile 引入了额外的目标。

以上是关于如何将 automake 文件写入递归构建子目录?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用带有子目录的 automake/autoconf?

如何将python集成到automake并在python语法错误时退出构建过程

Automake:如何在不安装的情况下构建共享库

如何根据vs工程构建makefile文件

基于automake构建工程

如何在 KDevelop 中为基于 automake 的项目添加自定义构建步骤?