如何使用 autotool 在单独的目录中构建

Posted

技术标签:

【中文标题】如何使用 autotool 在单独的目录中构建【英文标题】:How to build in a separate directory with autotool 【发布时间】:2019-10-12 08:15:06 【问题描述】:

我有一个工作目录如下:

./ |----HelloWorld/ |----|----main.cpp |----|----Makefile.am |----宠物/ |----|----宠物.h |----|----Pet.cpp |----构建/ |----configure.ac |----Makefile.am

我想用autotool构建makefile,然后在build目录下构建项目。

./configure.ac

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

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_CONFIG_FILES([Makefile])
AC_OUTPUT

./Makefile.am

include HelloWorld/Makefile.am

请注意,我使用包含来确保 exe 位于 make 命令运行的目录中。

./HelloWorld/Makefile.am

AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C%
#VPATH = ./HelloWorld ./Pet

bin_PROGRAMS=hello

hello_SOURCES=%D%/../Pet/Pet.h 
hello_SOURCES+=%D%/../Pet/Pet.cpp 
hello_SOURCES+=%D%/main.cpp

如果有人想在自己的电脑上尝试,我在这里附上其他源代码: ma​​in.cpp

#include <stdio.h>
#include <vector>
#include "Pet.h"

int main() 

    printf("Hello World\n");

    std::vector<Pet*> all_pets;

    Pet *dog = new Pet(string("Apple"));
    all_pets.push_back(dog);

    Pet *cat = new Pet(string("Pear"));
    all_pets.push_back(cat);

    for (int i = 0; i < all_pets.size(); i++) 
        all_pets[i]->showName();
    

    return 0;


**Pet.h**
#pragma once
#include <string>
using namespace std;
class Pet

    public:
    Pet(string name);
    ~Pet();

    void showName();
    void showIndex();

    string _name;
    int _index;
;

Pet.cpp

#include "Pet.h"

Pet::Pet(string name)

    _name = name;
    srand(2345);
    _index = (rand() % 100);



Pet::~Pet()



void Pet::showIndex()

    printf("Index is %d\n", _index);


void Pet::showName()

    printf("Name is %s\n", _name.c_str());


问题陈述

    运行可以成功创建makefile
./ $autoreconf --install  
    使用以下命令可以在根目录成功构建项目
./ $./configure   
./ $make  
    在目录 ./build 中构建时出错。命令是:
./build/ $../configure   
./build/ $make 

出现如下图所示的错误:

build error image

我认为这个错误是由于编译器无法成功找到头文件造成的。我的第一个问题是为什么makefile.am 中的AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C% 不能解决这个问题?

由于编译器将在构建目录中创建 .o 文件,从而使构建树具有与源树相同的子目录布局。所以我可以通过将 Pet.h 文件复制到 \build\Pet 来解决这个问题。但是,这意味着我总是需要将头文件复制到构建目录,这很不方便。

我找到了一些关于VPATH 的信息。所以我在./HelloWorld/Makefile.am 中注释掉了#VPATH = ./HelloWorld ./Pet。但是,它会给我一个新的问题:

automake error image

我的假设是 VPATH 设置与包含 makefile.am 有某种冲突。我的第二个问题是如何使用包含 makefile 正确使用 VPATH?

【问题讨论】:

【参考方案1】:

为什么makefile.am中的AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C%不能解决这个问题?

因为%D%%C% 生成included makefile 片段的路径相对于包含它的makefile,而不是相对于构建目录。它们不适用于或不适合处理源外构建,但如果使用得当,它们不会对此产生干扰。

如何通过包含 makefile 正确使用 VPATH?

你想太多问题了。 Automake 自动支持源外构建。您不需要(也不应该)自己设置VPATH

您还使用 Makefile include 指令为自己制造麻烦。该指令肯定有很好的用途,但您可以通过将所有内容合并到***Makefile.am 或设置递归make 来做得更好。你不应该需要 %D%%C% 的东西。

Automake 将为您设置VPATH,并在您执行源外构建时负责定位先决条件。大多数情况下,您只需指定相对于Makefile.am 和/或configure.ac 位置的源和目标路径。

有时您确实需要参考源目录,在这种情况下,您应该使用适当的$(srcdir)$(top_srcdir)$(abs_srcdir)$(abs_top_srcdir) 之一来确保源外构建正常工作。

您的项目布局有点奇怪,但这些替代方案中的任何一个都应该这样做:


递归

Makefile.am

SUBDIRS = HelloWorld

HelloWorld/Makefile.am

# VPATH helps *make* identify prerequisites, but the compiler doesn't know about it.
# We therefore need to give compiler options with real paths.  But we shouldn't need 
# any extra options to support sources that #include headers via (correct) paths expressed
# relative to the sources' own location.
AM_CPPFLAGS = -I$(srcdir)/../Pet

# Note: builds 'hello' in subdirectory HelloWorld/ of the build directory
bin_PROGRAMS = hello

hello_SOURCES =    \
    ../Pet/Pet.h   \
    ../Pet/Pet.cpp \
    main.cpp

非递归

Makefile.am

AM_CPPFLAGS = -I$(srcdir)/Pet

# Builds 'hello' directly in the build directory
bin_PROGRAMS = hello

hello_SOURCES = \
    Pet/Pet.h   \
    Pet/Pet.cpp \
    HelloWorld/main.cpp

HelloWorld/Makefile.am

(无)


无论哪种方式,您都可以像尝试做的那样执行源外构建:更改到想要的构建目录,如有必要首先创建它,从那里通过适当的路径运行 configure 脚本,然后然后继续make

$ mkdir build
$ cd build
$ path/to/configure
$ make

【讨论】:

谢谢@John Bollinger,我认为非递归方式对我来说是最简单的解决方案。我还有一些关于如何以递归方式创建 makefile 的问题question,你介意看看吗。非常感谢。 我会看看你的另一个问题,@Burton。同时,如果您对这个或另一个答案令人满意地回答了问题感到满意,那么通常(但不是强制性)通过单击其左侧的复选标记(靠近其分数)“接受”一个答案。【参考方案2】:

我无意中将 ./HelloWorld/Makefile.am 更改为

AM_CPPFLAGS=-I%D%/../../Pet/ -I%D% -I%C%
#VPATH = ../Pet
#srcdir = @srcdir@
#VPATH = %D/Pet/

bin_PROGRAMS=hello

hello_SOURCES=%D%/../../Pet/Pet.h 
hello_SOURCES+=%D%/../Pet/Pet.cpp 
hello_SOURCES+=%D%/main.cpp 

请注意,hello_SOURCES 的路径已更改,并且标头路径与源路径不同。但是为什么这会解决问题呢?

【讨论】:

这为您解决了问题是您对构建目录的特定选择的一个怪癖。显然您选择了***源目录的子目录。如果您在任何其他位置选择一个目录——比方说,更深一层,或者靠近***源目录——那么这将不起作用(但您可以生成一个类似的“解决方案”,适用于那种相对位置)。 具体来说:-I%D%/../../Pet/ 恰好适合编译器定位标头,而 hello_SOURCES+=%D%/../Pet/Pet.cpphello_SOURCES+=%D%/main.cpp 恰好与为 @987654326 自动生成的 VPATH 一起正常工作@ 定位 C++ 源代码。请注意,在 _SOURCES 中列出标头没有编译时影响;它只是确保标头包含在通过 make dist 构建的分发包中。

以上是关于如何使用 autotool 在单独的目录中构建的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 autotools 与库同时构建 Python 接口

如何在 c++ Autotools 项目中使用不同版本的 g++ 进行编译

如何在 autotools 项目中传播配置选项?

Autotools:如何设置全局编译标志

如何从现有的 C++ 源代码在 Eclipse CDT 中创建 GNU Autotool 项目?

autotools:如何测试需要配置文件的程序?