How to build in a separate directory with autotool - c++

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?

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 included 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

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?

Related

Where does bazel project store its ".so" files?

I've got a very simple bazel project which builds out a library and a binary like below:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [":hello-greet"],
)
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
Yes it works in my ubuntu box:
# cat hello-greet.cc
#include<stdio.h>
void f(){
printf("f function\n");
}
# cat hello-world.cc
#include<stdio.h>
#include"hello-greet.h"
int main(){
f();
printf("%s \n", "abc");
return 0;
}
"bazel build hello-world && bazel run hello-world" will print:
f function
abc
Ok, fine. But I cannot find where is my libhello-greet.so is, where is it stored? I cannot find it under my current directory.
Thanks a lot.
Bazel treats the source tree as read-only and puts its outputs in a separate output directory. The official way to find the this directory is to run bazel info output_base. However, as a convenience, Bazel also makes a symlink to this directory called bazel-out in the workspace root.
In your specific case, there may or may not be a shared library for hello-greet actually created—it's perfectly possible to build a binary without creating the intermediate shared objects. bazel build //:hello-greet should build and display the path to a shared object for hello-greet.
It says where in the output of bazel build. Typically in bazel-bin/..., following the same directory structure as the source file.

A generated C file and autotools

In an autoools-based build, I'd like to replace a version-controlled C file with a generated C file.
This dummy, hello world example sort-of works:
#!/bin/sh -ex
cat > configure.ac <<EOF
AC_INIT([hello], [0.01])
AC_PREREQ([2.68])
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.11])
AC_CONFIG_FILES([Makefile])
AC_PROG_CC
AC_OUTPUT
EOF
cat > autogen.sh <<EOF
touch NEWS README AUTHORS ChangeLog COPYING
autoreconf -i
EOF
chmod +x autogen.sh
printf "
bin_PROGRAMS = hello
hello_SOURCES = hello.c
hello.c: generate
\t./generate
" > Makefile.am
cat > hello.c <<EOF
#include <stdio.h>
int main()
{
puts("hello world");
return 0;
}
EOF
cat > generate <<EOF0
#!/bin/sh
cat > hello.c <<EOF
#include <stdio.h>
int main()
{
puts("HELLO WORLD");
return 0;
}
EOF
EOF0
chmod +x generate
./autogen.sh
./configure
make -j$(nproc)
except it prevents me from doing an out-of-tree build such as:
mkdir B
cd B
../configure
make
which I can normally do in an autotools-based package.
How can I generated the C file so that out-of-tree builds continue to work?
It is important to remember that make doesn't really know much about directories; for the most part, everything is a string to it. That's not always so obvious, but it tends to really bite you when you are trying to write a build system that can handle out-of-source builds.
You provide a build rule wherein hello.c depends on your generate script, which is fine in principle. Make will even handle the dependency processing correctly in an out-of-source build, finding the generate script in the source directory. But the recipe in the build rule explicitly runs ./generate, which does not exist when you're performing an out-of-source build. Furthermore, you have a disconnect between the dependency and the build rule: 'generate' is not the same thing as './generate'.
There are two main alternatives:
In your build rules, rely only on automatic make variables (e.g. $<) to refer to dependencies. When make is performing an out-of-source build, it initializes automatic variables with viable paths.
Refer to files in the source directory via explicit paths.
To use option (1) by itself, you would need to work around the problem of how to run the generate script when it is (presumably) not in the path. You can do that by running it indirectly, via the shell. The make rule you would want in that case would be
hello.c: generate
$(SHELL) $<
That should work for either in-source or out-of-source building. The $(SHELL) make variable should be provided by the Autotools.
To use option (2), on the other hand, you would probably rely on $(srcdir) or $(top_srcdir):
# Note that the dependency name will always contain a '/':
hello.c: $(srcdir)/generate
$<
(You can also name the generate script, with path, in the build recipe, but it's usually best to avoid repeating yourself.) The $(srcdir) and $(top_srcdir) variables are also provided by the Autotools. The former refers to the directory in the source tree that corresponds to the build-tree directory we are currently building; the latter refers to the source-tree directory containing the configure script.
Of those two, I'd rate (1) a bit more in the spirit of out-of-source building, but there isn't really that much difference.

automake third party libraries

How to compile and link third party libraries with automake?
My file structure is:
program/
|
+--src/
| |
| +--Makefile.am
| +--main.cpp
|
+--lib/
| |
| +--Makefile.am
| +--library.cpp
|
+--Makefile.am
+--configure.ac
+--README
Contents of automake files are pretty generic:
# src/Makefile.am
bin_PROGRAMS = program
program_SOURCES = main.cpp
# Makefile.am
SUBDIRS = src lib
dist_doc_DATA = README
# configure.ac
AC_INIT([program], [1.0])
AM_INIT_AUTOMAKE([-Wall])
AC_PROG_CXX
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile src/Makefile lib/Makefile])
AC_OUTPUT
What should be the contents of lib/Makefile.am?
(Not sure why you said "third-party" when you appear to have control of the library code yourself... For more info related to creating and working with libraries using Automake, I refer you to the GNU Automake manual's section on libraries)
lib/Makefile.am
lib_LIBRARIES = libYOURLIB.a
libYOURLIB_a_SOURCES = library.cpp
You can use noinst_lib_LIBRARIES if you don't want to install the library itself. Note that I'm assuming you want to build a static library only. See the Building A Shared Library section of the GNU Automake manual for integrating with Libtool to produce a shared library. You can do it manually of course, but it's a lot easier with Libtool as it takes care of various platform differences.
To link your library to program, you'd add the following lines insrc/Makefile.am:
program_DEPENDENCIES = $(top_builddir)/lib/libYOURLIB.a
program_LDADD = $(top_builddir)/lib/libYOURLIB.a
The _DEPENDENCIES line simply tells Automake that program relies on lib/libYOURLIB.a being built first, and the _LDADD line simply adds the library to the linker command.
The above assumes that you have a rule to build the library already. Since you're using SUBDIRS, you received a "no rule to make target XXXXXX" build failure, which indicates that you don't (at least from the perspective of the Makefile in the src subdirectory). To remedy this, you can try the following in src/Makefile.am (taken from "Re: library dependency" on the GNU Automake mailing list archives):
FORCE:
$(top_builddir)/lib/libYOURLIB.a: FORCE
<TAB>(cd $(top_builddir)/lib && $(MAKE) $(AM_MAKEFLAGS) libYOURLIB.a)
You can also simply make lib a subdirectory of src as your comment indicated of course and make it simpler.
Alternatively, you can stop using a recursive build setup and use what is perhaps a simpler non-recursive build setup. See GNU Automake Manual §7.3: An Alternative Approach to Subdirectories and Non-recursive Automake for some information on that, but the general idea would be to alter things to allow for :
configure.ac
AM_INIT_AUTOMAKE([-Wall subdir-objects])
...
AC_CONFIG_FILES([Makefile])
Makefile.am
# Instead of using the SUBDIRS variable.
include src/Makefile.am.inc
include lib/Makefile.am.inc
dist_doc_DATA = README
lib/Makefile.am renamed to lib/Makefile.am.inc
# Full path relative to the top directory.
lib_LIBRARIES = lib/libYOURLIB.a
lib_libYOURLIB_a_SOURCES = lib/library.cpp
src/Makefile.am renamed to src/Makefile.am.inc
# Full path relative to the top directory.
bin_PROGRAMS = bin/program
bin_program_SOURCES = src/main.cpp
bin_program_DEPENDENCIES = lib/libYOURLIB.a
bin_program_LDADD = lib/libYOURLIB.a
Renaming the files is optional (you could always just include src/Makefile.am), but it helps to denote that it isn't meant to be a standalone Automake source file.
Also, supposing that lib/library.cpp and src/main.cpp both #include "library.hpp", and it's in another directory, you might also want to use AM_CPPFLAGS = -I $(top_srcdir)/include for all files or obj_program_CPPFLAGS = -I include for all source files that are used in building bin/program, assuming library.hpp is in program/include. I'm not sure if $(top_srcdir) is right when another project includes your entire program source directory in its own SUBDIRS variable, but $(srcdir) will always refer to the top-level program directory in the case of a non-recursive automake, making it perhaps more useful in larger projects that include this package as a component.

autotools: no rule to make target all

I'm trying to port an application I'm developing to autotools. I'm not an expert in writing makefiles and it's a requisite for me to be able to use autotools.
In particular, the structure of the project is the following:
..
../src/Main.cpp
../src/foo/
../src/foo/x.cpp
../src/foo/y.cpp
../src/foo/A/k.cpp
../src/foo/A/Makefile.am
../src/foo/Makefile.am
../src/bar/
../src/bar/z.cpp
../src/bar/w.cpp
../src/bar/Makefile.am
../inc/foo/
../inc/bar/
../inc/foo/A
../configure.in
../Makefile.am
The root folder of the project contains a "src" folder containing the main of the program AND a number of subfolders containing the other sources of the program. The root of the project also contains an "inc" folder containing the .h files that are nothing more than the definitions of the classes in "src", thus "inc" reflects the structure of "src".
I have written the following configure.in in the root:
AC_INIT([PNAME], [1.0])
AC_CONFIG_SRCDIR([src/Main.cpp])
AC_CONFIG_HEADER([config.h])
AC_PROG_CXX
AC_PROG_CC
AC_PROG_LIBTOOL
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_FILES([Makefile
src/Makefile
src/foo/Makefile
src/foo/A/Makefile
src/bar/Makefile])
AC_OUTPUT
And the following is ../Makefile.am
SUBDIRS = src
and then in ../src where the main of the project is contained:
bin_PROGRAMS = pname
gsi_SOURCES = Main.cpp
AM_CPPFLAGS = -I../../inc/foo\
-I../../inc/foo/A \
-I../../inc/bar/
pname_LDADD= foo/libfoo.a bar/libbar.a
SUBDIRS = foo bar
and in ../src/foo
noinst_LIBRARIES = libfoo.a
libfoo_a_SOURCES = \
x.cpp \
y.cpp
AM_CPPFLAGS = \
-I../../inc/foo \
-I../../inc/foo/A \
-I../../inc/bar
And the analogous in src/bar.
The problem is that after calling automake and autoconf, when calling "make" the compilation fails. In particular, the program enters the directory src, then foo and creates libfoo.a, but the same fail for libbar.a, with the following error:
Making all in bar
make[3]: Entering directory `/user/Raffo/project/src/bar'
make[3]: *** No rule to make target `all'. Stop.
I have read the autotools documentation, but I'm not able to find a similar example to the one I am working on. Unfortunately I can't change the directory structure as this is a fixed requisite of the project I'm working on.
I don't know if you can help me or give me any hint, but maybe you can guess the error or give me a link to a similar structured example.
Thank you.
if it fails in src/bar, why is src/bar/Makefile.am the only code that you do not post?
and btw, you should use $(srcdir) or $(top_srcdir) rather than referring to relative paths like "../../" (this comes in handy if people want to produce binaries without poluuting the source directory)

Eclipse c++ How to work with existing makefile

I'm a newbie and I've a problem!
I've to work with a c++ code and I don't know how to import it and how to compile it on eclips ( I compiled it by command line).
The code has a particular structure and it is organized in this way:
repos____lib____configure (execute the configure file inside the libraries folders)
I I___makefile (execute the make file inside the libraries folders,
requires make/make.def)
I I___ib1____.cpp
I I I____.h
I ... I____configure (it requires make/configure_lib and
make/configure_includes
I ... I____makefile (generated by configure)
I I___lib2___....
i I___.......
I I___libn____.cpp
i I____.h
i I____configure
i I____makefile (generated by configure)
I
I___make(folder)__bashrc (are set the some environment variables)
I I__configure_bin
I I__configure_includes
I I__configure_lib
I I__make.def (are set all the include path and library path used
I in the configure file)
I___application__main.cpp
I__configure
I__makefile(generated by the configure file)
to be sure that you understand my problem...(sure... :) )
the first configure file is:
cd lib1; ./configure
cd ../lib2; ./configure
.....
....
cd ../libn; ./configure
cd
and the first makefile is
include /media/Dati/WORKHOME/repos/make/make.def
this is the makefile for the whole library
lib:
make -C lib1
make -C lib2
make -C libn
an example of configure file (the one inside lib1):
#!/usr/bin/perl
$INC = '$(OPENCVINC) $(FLTKINC) $(DC1394V2INC)'; ##<-DEFINED IN /make.def
$LIB = '$(OPENCVLIB) $(FLTKLIB) $(DC1394V2LIB)'; #####################
#-------------------------------------------------------------------------------
require '/media/Dati/WORKHOME/repos/make/configure_lib';
print "Created Makefile.\n";
# this will create a include file for the whole directory,
# using the template <dirname>.h.templ
require '/media/Dati/WORKHOME/repos/make/configure_includes';
print "Created $libname.h\n";
compile it without eclipse is simple
type /.configure in the lib folder
type make
go into the application folder
type ./configure
type make
run the program
my question is....in eclipse???
I imported the three with import/ import existing code as makefile project but now I don't know how compile it.
could you please help me? it's important!
thank you very much
gabriele
You have done the right thing by using "import existing code as makefile project".
Now eclipse know that it needs to call make and use your makefile. But Your build process is not only driven by make.
One solution is to write a makefile that call all your build steps. Something Like :
all:
cd dir1 && ./configure && make
cd dir2 && ./configure && make
etc.
my2c
Edit:
I currently have no eclipse installed, so I can not send you detailled steps ... sorry