如何使用 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());
}
问题陈述
- 可以通过运行
成功创建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 设置与 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%
生成 include
d 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
我有一个工作目录如下:
./
|----你好世界/
|----|----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());
}
问题陈述
- 可以通过运行 成功创建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 设置与 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%
生成 include
d 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