Burton
Burton

Reputation: 71

How to write automake files to recursive build subdirectories?

My working directory as following tree shows:

./  
|--HelloWorld/  
|--|--main.cpp  
|--|--Dog/   
|--|--|--Dog.h  
|--|--|--Dog.cpp    
|--Pet/  
|--|--Pet.h  
|--|--Pet.cpp  
|--build/  

The main.cpp includes dog.h and pet.h. Dog is an inherited class of Pet, so Dog.h also includes Pet.h. I know this is a wired way to organize the codes, but I'm just curious about how to create makefile.am files for each subdirectories so that autotool can build the project in the build directory.

Note that I would like to have some additional features:

  1. Is that possible we build the hello.exe at build directory instead of build/HelloWorld/ directory? To do this, do I have to put the bin_PROGRAMS at the ./Makefile.am
  2. I do not want to build Pet as librarys, I'm wondering whether there is a way I can just tell automake to find source codes in different locations.
  3. I know that using non-recursive makefile would be easier. But I just want to learn how to create recursive makefiles for multiple directories.

What I have tried is:

configure.ac

AC_PREREQ([2.69])
AC_INIT([Hello], [1.0], [[email protected]])
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_PROG_CPP

AC_CONFIG_FILES([Makefile
                 HelloWorld/Makefile
                 Pet/Makefile
                 HelloWorld/Dog/Makefile])
AC_OUTPUT

Makefile.am

SUBDIRS = HelloWorld Pet

HelloWorld/Makefile.am

AM_CPPFLAGS=-I$(srcdir)/../Pet -I$(srcdir)/Dog 
SUBDIRS = Dog
bin_PROGRAMS=hello 
hello_SOURCES = main.cpp

Pet/Makefile.am

hello_SOURCES = Pet.h Pet.cpp

HelloWorld/Dog/Makefile.am

AM_CPPFLAGS=-I$(srcdir)/../../Pet

hello_SOURCES = Dog.h Dog.cpp 

I just started learning automake things, and I know these codes do not work at all.

Could anyone help me to fix them? Thank you.

Upvotes: 0

Views: 3298

Answers (1)

John Bollinger
John Bollinger

Reputation: 180286

You say you're interested in

how to create makefile.am files for each subdirectories so that autotool can build the project in the build directory

, but this is not an appropriate goal, as this example itself demonstrates. It is rarely useful or appropriate to have a Makefile.am that does not define any targets to be built. You have stipulated that you don't want to build Pet as a library, so what target would a Makefile.am in its directory define? Similar applies to Dog if you want to avoid building it as a library. There is little or no point to using recursive make in this situation.

I do note, however, that Automake has the concept of a "convenience library", which is an intermediate target that is never itself installed, but contains object code that can be linked into an executable or a larger library. I will demonstrate this later, as it's the most sensible way to set up the makefile-per-directory structure you are asking for in this particular case.

Additionally, with respect to directing the output to a specific directory in the source tree: this can be done, but it is probably a waste of effort. The Autotools already provide a convenient method for out-of-source building that more easily accomplishes the goal of separating the build results from the source in the event that the person building the project wishes to do that.

NEVERTHELESS, the basics of recursive builds with the Autotools are pretty simple. There are two main things to do:

  • each Makefile.am that wants to express a recursion into one or more subdirectories does so by listing the relative paths to each of those subdirectories in the variable SUBDIRS.

  • the project configure.ac must designate of the Makefiles to be built via its AC_CONFIG_FILES macro.

That's all you need to do to set up the recursion generally, and the details of how to set up specific targets and options are project-specific.

  1. Is that possible we build the hello.exe at build directory instead of build/HelloWorld/ directory? To do this, do I have to put the bin_PROGRAMS at the ./Makefile.am

Yes, you can specify building into build/hello rather than build/HelloWorld/hello. You might not strictly have to put the corresponding bin_PROGRAMS into the top-level Makefile.am, but you definitely should put it there or in a build/Makefile.am file. I urge you to avoid trying to have any makefile build targets outside the tree rooted at the directory where that particular makefile resides.

  1. I do not want to build Pet as librarys, I'm wondering whether there is a way I can just tell automake to find source codes in different locations.

You can absolutely specify source files in a different directory from the Makefile.am. Just provide the appropriate path, relative to the makefile's directory. This makes more sense for sources in the same tree as the makefile, but using sources located elsewhere is not as much of an issue as trying to build targets elsewhere.

  1. I know that using non-recursive makefile would be easier. But I just want to learn how to create recursive makefiles for multiple directories.

Non-recursive makefiles are not necessarily easier than recursive ones, but they are generally better, because they express the whole target / prerequisite tree as a unit instead of chopping it up into pieces. make can make better build decisions when it has all the information at once.

I just started learning automake things, and I know these codes do not work at all.

My answer to your related question provides a recursive solution to a related problem. It demonstrates one of the key principles that you seem to be missing: the variables specifying a target's sources and other build properties need to appear in the same Makefile.am file in which the target itself is defined. Each Makefile.am corresponds to a separate makefile. To a first approximation, data are not shared between makefiles, so all the information needed to build a given target needs to appear in the same one.

The other thing that seems to distinguish this question from your other is that you want (however wrongheadedly) to specify a particular output directory in your makefile. Do remember that wherever the built files initially go, it is a staging area -- it doesn't much matter, because they get put in their final destination by make install. Even so, you can specify a target residing in a different directory by giving the correct relative path to it. Of course, such a change to the target name needs to be reflected in the names of the variables derived from the target name.

Here, then, is a recursive Automake setup that should build your example project using one makefile per source directory:


Makefile.am

SUBDIRS = Pet HelloWorld

# Note: specifying output into a different directory
bin_PROGRAMS = build/hello

# Note the form of the following names:
build_hello_SOURCES = HelloWorld/main.cpp
build_hello_CPPFLAGS = -I$(srcdir)/Pet -I$(srcdir)/HelloWorld/Dog
# Note that library order matters
build_hello_LDADD = HelloWorld/Dog/libDog.a Pet/libPet.a

Pet/Makefile.am

noinst_LIBRARIES = libPet.a

libPet_a_SOURCES = \
    Pet.cpp        \
    Pet.h

HelloWorld/Makefile.am

SUBDIRS = Dog

# No own targets defined here, just the recursion into Dog.  This could have been
# skipped altogether, but I'm sticking to the letter of one Makefile.am per source
# directory.

HelloWorld/Dog/Makefile.am

noinst_LIBRARIES = libDog.a

libDog_a_SOURCES = \
  Dog.cpp          \
  Dog.h
libDog_a_CPPFLAGS = -I$(top_srcdir)/Pet

Your configure.ac ought to work with that as-is.

Note this does not rely on VPATH; it builds specifically into the build/ subdirectory of the build tree, including when you build directly in the source tree.

Upvotes: 1

Related Questions