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

How to build in a separate directory with autotool

我有一个工作目录如下:

./
|----你好世界/
|----|----main.cpp
|----|----Makefile.am
|----宠物/
|----|----Pet.h
|----|----Pet.cpp
|----构建/
|----configure.ac
|----Makefile.am

我想用autotool来构造makefile,然后在build目录下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

请注意,我正在使用 include 来确保 exe 位于 make 命令 运行s.

所在的目录中

./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

如果有人想在自己的电脑上尝试,我在这里附上其他源代码: main.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());
}

问题陈述

  1. 可以通过运行
  2. 成功创建makefile
./ $autoreconf --install  
  1. 使用以下命令可以在根目录成功构建项目
./ $./configure   
./ $make  
  1. 在目录 ./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 设置与 include makefile.am 有某种冲突。我的第二个问题是 如何使用 include makefile 正确使用 VPATH?

我通过将 ./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 的路径已更改且 header 路径与源路径不同。但是为什么这样可以解决问题呢?

Why the AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C% in makefile.am cannot solve this problem?

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

How can I use the VPATH correctly with using include makefile?

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

你也在给自己制造麻烦 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

(none)


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

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