问题
I have a working directory as below:
./
|----HelloWorld/
|----|----main.cpp
|----|----Makefile.am
|----Pet/
|----|----Pet.h
|----|----Pet.cpp
|----build/
|----configure.ac
|----Makefile.am
I would like to use the autotool to construct makefile and then build the project in the build directory.
The ./configure.ac is
# -*- 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
The ./Makefile.am is
include HelloWorld/Makefile.am
Note that I'm using the include to make sure the exe locates at the directory where the make command runs.
The ./HelloWorld/Makefile.am is
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
In case some people would like to try on their own computer, I attach other source codes here: 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());
}
Problem Statement
- Can successfully create makefile by run
./ $autoreconf --install
- Can successfully build the project at root directory with using following commands
./ $./configure
./ $make
- Get error when building in directory ./build. Commands are:
./build/ $../configure
./build/ $make
Got an error as below image shows:
build error image
I think this error is caused by the compiler cannot successfully find the header files. My first question is Why the AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C%
in makefile.am cannot solve this problem?
Since the compiler will create the .o files in the build directory with making the build tree has the same subdirectory layout as the source tree. So I can fix this problem by copy the Pet.h file to \build\Pet. However, this means I always need to copy the header files to the build directory, which is not convenient.
I find some info about VPATH. So I commented out #VPATH = ./HelloWorld ./Pet
in ./HelloWorld/Makefile.am. However, it will give me a new problem:
automake error image
My assumption is the VPATH setting somehow conflicts with the include makefile.am. My second question is How can I use the VPATH correctly with using include makefile?
回答1:
Why the
AM_CPPFLAGS=-I%D%/../Pet/ -I%D% -I%C%
in makefile.am cannot solve this problem?
Because %D%
and %C%
produce paths to the include
d makefile fragment relative to the makefile that includes it, not relative to the build directory. They are not intended or suited for handling out-of-source building, though when used correctly, they do not interfere with that.
How can I use the VPATH correctly with using include makefile?
You are overthinking the problem. Automake supports out-of-source building automatically. You don't need to (and shouldn't) set up VPATH
yourself.
You are also making trouble for yourself with the Makefile include
directive. That directive definitely has good uses, but you would do better here by either consolidating everything into the top-level Makefile.am
or by setting up for recursive make
. You shouldn't need that %D%
and %C%
stuff.
Automake will set up VPATH
for you, and that takes care of locating prerequisites when you perform an out-of-source build. For the most part, you just specify paths to sources and targets relative to the location of your Makefile.am
and / or configure.ac
.
Occasionally you do need to refer to the source directory, and in that case you should use the appropriate one of $(srcdir)
, $(top_srcdir)
, $(abs_srcdir)
, or $(abs_top_srcdir)
to ensure that out-of-source builds work correctly.
Your project layout is a bit odd, but either one of these alternatives ought to do it:
Recursive
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
Non-recursive
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)
Either way, you perform an out-of-source build just as you were trying to do: change to the wanted build directory, creating it first if necessary, run the configure
script from there via an appropriate path, and then proceed with make
.
$ mkdir build
$ cd build
$ path/to/configure
$ make
回答2:
I accidently fix the problem by changing the ./HelloWorld/Makefile.am to
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
Note that the path of hello_SOURCES are changed and header path is different from source path. But why would this solve the problem?
来源:https://stackoverflow.com/questions/58352194/how-to-build-in-a-separate-directory-with-autotool