Search code examples
c++autotoolsautomakelibtool

Best way to compile subdirectories into libraries with automake?


I have the following files

├── configure.ac
├── main.cpp
├── Makefile.am
└── procs
    ├── Makefile.am
    ├── proc1
    │   └── subprocs
    │       ├── subprocA
    │       │   ├── ProcA_SubprocA.cc
    │       │   └── ProcA_SubprocA.h
    │       └── subprocB
    │           ├── ProcA_SubprocB.cc
    │           └── ProcA_SubprocB.h
    ├── proc2
    │   └── subprocs
    │       ├── subprocA
    │       │   ├── ProcB_SubprocA.cc
    │       │   └── ProcB_SubprocA.h
    │       └── subprocB
    │           ├── ProcB_SubprocB.cc
    │           └── ProcB_SubprocB.h
    └── Subprocs.h

My goal is to create a library from everything in procs so it can be used in main.cpp which could look something like this:

main.cpp

#include "Subprocs.h"

int main(){

    ProcA_SubprocA * p = new ProcA_SubprocA();
    p->use();
    delete p;

    return 0;
}

I would like to have all the includes of the subprocs in Subprocs.h, so it can be used as some kind of interface:

Subprocs.h

#include "ProcA_SubprocA.h"
#include "ProcA_SubprocB.h"
#include "ProcB_SubprocA.h"
#include "ProcB_SubprocB.h"

My configure.ac looks like this:

configure.ac

AC_PREREQ([2.69])
AC_INIT([main], [0.1])
AM_INIT_AUTOMAKE([foreign subdir-objects])

#AC_CONFIG_MACRO_DIR([m4]) 
#LT_INIT

AC_PROG_CXX
AC_PROG_CC
AC_PROG_RANLIB

AC_CONFIG_FILES([Makefile procs/Makefile])
AC_OUTPUT

and my Makefile.am's like this

Makefile.am

SUBDIRS = procs

AM_CPPFLAGS = -Iprocs

bin_PROGRAMS = main
main_SOURCES = main.cpp
#added:
main_LDADD = procs/libprocs.a

#ACLOCAL_AMFLAGS = -I m4

procs/Makefile.am

AM_CPPFLAGS = -Iproc1/subprocs/subprocA -Iproc1/subprocs/subprocB \
              -Iproc2/subprocs/subprocA -Iproc2/subprocs/subprocB

#lib_LIBRARIES = libprocs.la
noinst_LIBRARIES = libprocs.a
libprocs_a_SOURCES = Subprocs.h \
                      proc1/subprocs/subprocA/ProcA_SubprocA.cc proc1/subprocs/subprocA/ProcA_SubprocA.h \
                      proc1/subprocs/subprocB/ProcA_SubprocB.cc proc1/subprocs/subprocB/ProcA_SubprocB.h \
                      proc2/subprocs/subprocA/ProcB_SubprocA.cc proc2/subprocs/subprocA/ProcB_SubprocA.h \
                      proc2/subprocs/subprocB/ProcB_SubprocB.cc proc2/subprocs/subprocB/ProcB_SubprocB.h

When I type

#libtoolize && autoreconf -i -f && ./configure && make
autoreconf -i -f && ./configure && make

I get a file called libprocs.la in procs but I don't get a binary. I am also fairly certain that my Makefiles are wrong since I can't even compile main.cpp by hand.

Is it at all possible to do what I want here? Or am I overthinking this and I don't even need a library in the first place? The important part for me is that main.cpp only includes Subprocs.h which then contains all includes of the subprocs.

Thank you in advance!


Solution

  • There are numerous oddities in what you've presented, and one clear error. You say,

    I get a file called libprocs.la in procs but I don't get a binary. I am also fairly certain that my Makefiles are wrong since I can't even compile main.cpp by hand.

    Surely make's output contains one or more error messages that explain why the build fails. Unless your makeing only the procs subdirectory in the first place, I guess, in which case of course you would not be getting main built.

    But I'm reasonably confident that I can guess: you're getting a linker error complaining that it can't find ProcA_SubprocA::ProcA_SubprocA. This would be because although your Makefile specifies that the library should be built (and also installed), it nowhere says that it needs to be linked into main. There's a pretty easy fix for that, which I will return to in a moment.

    First, however, let's talk about libprocs.la. The .la suffix is meaningful to the Autotools, designating a "libtool archive", but you're actually building it as an ordinary static library. Indeed libtool isn't doing anything particularly useful for you here; I would dump it by removing the LT_INIT from your configure.ac (and do not run libtoolize again, as it will put that back). Then, change the name of the library to be built to the more standard libprocs.a.

    Furthermore, since this library seems to be intended only for use with the one program being built, it is unhelpful to include it in the install in its own right. Therefore, instead of designating it in lib_LIBRARIES, designate it as a non-installed convenience library:

    noinst_LIBRARIES = libprocs.a
    

    You will then need to make a corresponding change to the library's SOURCES variable:

    libprocs_la_SOURCES = ...
    

    libprocs_a_SOURCES = ...
    

    Coming back to the main program now, you need to tell make (and Automake) that the library needs to be linked into program main. There are a few variations on how you could do that, but I'm going to suggest a fairly simple one:

    main_LDADD = procs/libprocs.a
    

    After those changes, rerun autoreconf (but not libtoolize). Remember, however, that you need to run that only after changing Autotools sources -- just Makefile.am and configure.ac files in your case. It is a detail of maintaining and developing the package and its build system in particular. It should not be a routine part of building or installing the package.