How to handle library dependencies with automake? - c

Let's assume the following project structure composed of one executable in src and two libraries, lib1 and its dependency lib1_dep:
+--src/
| |
| +--Makefile.am
| +--main.c
|
+--lib/
| |
| +--Makefile.am
| +--library1.c
| +--library1.h
+--lib_dep/
| |
| +--Makefile.am
| +--library1_dep.c
| +--library1_dep.h
+--Makefile.am
+--configure.ac
The contents of the files are
configure.ac
# Add libraries dependance
AC_CONFIG_SUBDIRS([lib_dep])
AC_CONFIG_SUBDIRS([lib])
# Add src files
AC_CONFIG_FILES([Makefile
lib_dep/Makefile
lib/Makefile
src/Makefile
])
Makefile.am
SUBDIRS = lib_dep lib src
lib1_dep/Makefile.am
lib_LTLIBRARIES = lib_libdep.la
# Dynamic library
lib_libdep_la_SOURCES = library1_dep.c library1_dep.h
lib_libdep_la_LIBADD =
# Compiler options.
lib_libdep_la_CPPFLAGS = $(AM_CPPFLAGS)
lib1/Makefile.am
lib_LTLIBRARIES = lib_lib.la
# Dynamic library
lib_lib_la_SOURCES = library1.c library1.h
lib_lib_la_LIBADD = $(top_builddir)/lib_dep/lib_libdep.la
# Compiler options.
lib_lib_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib_dep/lib_dep.h
src/Makefile.am
bin_PROGRAMS = main
main_SOURCES = main.c
main_LDADD = $(AM_LDADD) $(top_builddir)/lib/lib_lib.la $(top_builddir)/lib_dep/lib_libdep.la
# Compiler options.
main_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/lib_dep/lib_dep.h -I$(top_srcdir)/lib/lib_lib.h
Observation
The build and install work well but I doubt I do it properly. The main program only uses functions defined in lib (not in lib_dep), so it looks strange that I have to also diretly link the main program to lib_dep. I would like your feedbacks on this please.
Question
Is there a way to build/compile lib so that I don't have to add the LDAPP and CPPFLAGS related to lib_dep when I build y main program (src/Makefile.am) ?
Thanks

The build and install work well but I doubt I do it properly. The main program only uses functions defined in lib (not in lib_dep), so it looks strange that I have to also diretly link the main program to lib_dep. I would like your feedbacks on this please.
It is system-dependent whether indirect shared-library dependencies need to be included in the link. On Linux, they do. Compare to the situation with static library dependencies, which absolutely need to be included in the final link, on any system.
However, since you are using libtool, in a context where you can rely on its generated .la files to be available, you shouldn't need to provide explicitly for linking indirect dependencies. Libtool can handle that for you.
Is there a way to build/compile lib so that I don't have to add the LDAPP and CPPFLAGS related to lib_dep when I build y main program (src/Makefile.am) ?
That's actually two separate questions, one for LDADD and one for CPPFLAGS.
The CPPFLAGS are relevant only for compilation, not linking. Roughly speaking, if the main program's sources #include any headers from lib_dep/, whether directly or indirectly, then it is necessary for its CPPFLAGS to contain an -I flag for that directory. Otherwise, not.
An indirect inclusion would be if main.c includes library1.h and library1.h includes library1_dep.h.
Since you are using libtool to build both libraries, and consistently declaring link dependencies by putting the appropriate libtool archives in the LIBADD / LDADD variables, you do not need to specify the indirect library dependency in the main program's LDADD. libtool can and will figure out the indirect library dependency and add it to the main program's link if needed, and at the correct location in the link command.
Thus, if the main program has neither a compile-time dependency nor a direct link dependency on libdep, then its Makefile.am could look like this:
bin_PROGRAMS = main
main_SOURCES = main.c
main_LDADD = $(top_builddir)/lib/lib_lib.la
main_CPPFLAGS = -I$(top_srcdir)/lib
NOTE: it is not wrong to add $(AM_LDADD) to main_LDADD or to add $(AM_CPPFLAGS) to main_CPPFLAGS, as in the version of this Makefile.am presented in the question, but that is useful only if you've actually defined values for those AM_* variables.
NOTE2: Your -I flags should specify directories to search for header files, not the names of specific header files.

Related

Set Preproccessor directive for only one program in Automake file

Let us assume that we have a source file "a.c".
The "a.c" source file is used in building programs "Prog1","Prog2", and 'Prog3".
"Prog1" also uses source file "x.c"
"Prog2" uses source file "y.c"
"Prog3" uses source file "z.c"
Assume that "a.c" uses a function called "foo()" that is only defined in "x.c". Hence "Prog1" would get built, but "Prog2" and "Prog3" would not compile.
Also assume that "a.c" needs to call function bar1() when building program Prog1, bar2() when building program Prog2, and bar3() when building program Prog3.
How should we create the automake Makefile.am to support this?
I have been trying to specify distinct preprocessor directives when building each program in the automake file "Makefile.am", but so far could not see how it is done.
Any help would be appreciated. Thanks.
Simplest solution? Create three different rules for three different object files all built from the a.c source file.
Then each rule can easily add extra flags needed for the specific build.
bin_PROGRAMS = prog1 prog2 prog3
prog1_SOURCES = a.c x.c
prog1_CPPFLAGS = -DPROG1
prog2_SOURCES = a.c y.c
prog2_CPPFLAGS = -DPROG2
prog3_SOURCES = a.c z.c
prog3_CPPFLAGS = -DPROG3
But to use this you need to make sure you call AM_PROG_CC_C_O in your configure.ac, since a.c is then compiled three times with different options.

Linking a Shared Library Autotools

I'm an autotools beginner, and I can't seem to figure out how to use an external library correctly with autotools.
Here is my directory hierarchy.
.
├── configure.ac
├── Makefile.am
├── README
└── src
(source files)
└── Makefile.am
The library's name is acml_mp and is, by default, installed in /opt/acml5.3.1/gfortran64/lib. There is also a directory called /opt/acml5.3.1/gfortran64/include to include. When I compile without autotools, including the usual compiler flags works fine:
g++ ... -L/opt/acml5.3.1/gfortran64_mp/lib -I/opt/acml5.3.1/gfortran64_mp/include -lacml_mp ...
In configure.ac, I put the command AC_LIB_LINKFLAGS([acml_mp]) which I think only deals with the -lacml_mp flag.
Basically, the end goal is to have autoconf search for this library, and have the makefile generated by automake include the correct link/include paths when compiling. Finally, when compiling by hand, I always need to modify the environment variable LD_LIBRARY_PATH using the command
Export LD_LIBRARY_PATH=/opt/acml5.3.1/gfortran64_mp/lib:$LD_LIBRARY_PATH
which, ideally, I would like to avoid having the user do. Apologies if this information exists already, I looked through SO and Google for a few hours to no avail.
The problem with searching is that /opt/acml5.3.1/gfortran is never going to be a standard (search) location for libraries (and headers) like /usr/lib, /usr/local/lib etc. Probably the best bet is to supply this location explicitly via --with-acml to configure.
The AC_ARG_WITH macro is described here. Assuming test "x$with_acml" != xno, you can try linking a program with AC_LINK_IFELSE.
AC_LANG_PUSH([C]) # or [Fortran]
ac_save_acml_CPPFLAGS="$CPPFLAGS" # or FCFLAGS instead of CPPFLAGS.
ac_save_acml_LIBS="$LIBS"
ac_acml_CPPFLAGS="-I${with_acml}/include"
ac_acml_LIBS="-L${with_acml}/libs -lacml_mp"
CPPFLAGS+="$ac_acml_CPPFLAGS"
LIBS+="$ac_acml_LIBS"
AC_LINK_IFELSE([AC_LANG_PROGRAM( ... some C or Fortran program ... )],,
AC_MSG_FAILURE([couldn't link with acml]))
AC_LANG_POP
# we *could* stop here... but we might need the original values later.
CPPFLAGS="$ac_save_acml_CPPFLAGS"
LIBS="$ac_save_acml_LIBS"
AC_SUBST(ACML_CPPFLAGS, $ac_acml_CPPFLAGS)
AC_SUBST(ACML_LIBFLAGS, $ac_acml_LIBS)
Assuming you've initialized libtool support with LT_INIT, you can add the acml library with $(ACML_LIBFLAGS) to your own libraries in src/Makefile.am via the LIBADD variable, or to executables with the LDADD variable. or <lib>_la_LIBADD, <prog>_LDADD respectively.
To compile sources with the $(ACML_CPPFLAGS) include path, add it to the AM_CPPFLAGS variable. Or the <prog>_CPPFLAGS variable.
It's difficult to be specific without knowing how your Makefile.am is already set up. I know it looks complicated - but it's better to get the infrastructure right the first time. I'll add to the answer if you have further questions.

Missing header files for linked ".c" file

I have linked a ".c" file to another one. ld doesn't return any error but the compiler can't find included header files in this ".c" file and returns this error:
../libvmi/driver/xen.c:27:20: fatal error: libvmi.h: No such file or directory
Here is the Makefile of my project:
## Source directory
SUBDIRS =
INCLUDES = -I$(top_srcdir) $(top_srcdir)/libvmi
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/ $(top_srcdir)/libvmi/driver $(top_srcdir)/libvmi/libvmi.h
LDADD = -lvmi -lm $(LIBS) $(top_srcdir)/libvmi/driver/xen.c $(top_srcdir)/libvmi/libvmi.h
bin_PROGRAMS = module-list process-list map-symbol map-addr dump-memory
module_list_SOURCES = module-list.c
process_list_SOURCES = process-list.c
map_symbol_SOURCES = map-symbol.c
map_addr_SOURCES = map-addr.c
dump_memory_SOURCES = dump-memory.c
As you see above I thought I should add "$(top_srcdir)/libvmi" to "INCLUDES"; this is the directory that libvmi.h is located.
The original Makefile is:
## Source directory
SUBDIRS =
INCLUDES = -I$(top_srcdir)
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/
LDADD = -lvmi -lm $(LIBS)
c_sources = process-list.c $(top_srcdir)/libvmi/driver/xen.c
bin_PROGRAMS = module-list process-list map-symbol map-addr dump-memory
module_list_SOURCES = module-list.c
process_list_SOURCES = $(c_sources)
map_symbol_SOURCES = map-symbol.c
map_addr_SOURCES = map-addr.c
dump_memory_SOURCES = dump-memory.c
I have modified it to link "libvmi/driver/xen.c" to process-list.c file which are located in different directories.
This is because of something's wrong in Makefile, yes?
Add a -I to the path you added. Note this is a compiler, not linker question
The reason ld doesn't return an error is because it is not invoked. The error message you are getting is coming from the compiler, and the loader is not invoked until the compiler is successful.
Yes, you do need to add $(source_dir)/libvmi to INCLUDES; you just need to do it symmetrically with the existing entry:
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/libvmi
Note the -I preceding the directory name. You have a similar problem in AM_LDFLAGS and LDADD:
AM_LDFLAGS = -L$(top_srcdir)/libvmi/.libs/ -L$(top_srcdir)/libvmi/driver
LDADD = -lvmi -lm $(LIBS)
but you do not want to add the header file $(top_srcdir)/libvmi/libvmi.h to the load flags. Headers are not libraries; headers are not appropriate for sending to the linker/loader. You should only supply the linker/loader with object files, libraries, and options — no source files, no headers.
That more or less deals with the surface issues. What is the real problem you are trying to solve?
If you need to link with code from a library built in libvmi directory, why don't you make the dependency changes in this makefile to pick up the library from the libvmi directory (and separately run the build for the library in the libvmi directory)? Or, if you really want to do the compilation in the current directory (but why?), create links to the libvmi files locally (or copy them; no, on second thoughts, don't copy them), and compile them locally? Mixed directory working is painful at best — and to be avoided when possible, which it almost always is.
I note that the original makefile does in fact include -lvmi on the link line, so what I outlined is what you're expected to use. Why isn't that working for you? This is very much an XY Problem. I recommend reworking the question so that you get a solution to the real problem you started out with, rather than the artificial problem you ran into attempting to solve the real problem in a misguided way.

autotools: one project with one executable, one shared obj and a "shared" internal library

I am trying my hand at autotools. I have the following project hierarchy:
project/src
project/src/utilities
project/src/utilities/util.c
project/src/utilities/util.h
project/src/sharedObject
project/src/sharedObject/sharedObject.c
project/src/sharedObject/sharedObject.h
project/src/sharedObject/thing.c
project/src/executable
project/src/executable/exec.c
project/src/executable/exec.h
project/src/executable/thing1.c
project/src/executable/thing2.c
"executable" and "sharedObject.so" both depend on "util.o" and "util.h". I have seen examples of creating convenience libraries but I am not sure how to specify them in the "Makefile.am" files in the other two sub-projects. How are these kinds of inter-project dependencies defined?
Both "executable" and "sharedObject.so" will be installed. The "util.o" and "util.h" files will only be used in the build process.
Thank you
In the utilities/Makefile.am:
noinst_LTLIBRARIES = libutil.la
libutil_la_SOURCES = util.h util.c
In executable/Makefile.am, the use of the library should use the LDADD primary, e.g.,
bin_PROGRAMS = exec
exec_SOURCES = exec.h exec.c thing.h thing.c
exec_LDADD = ../utilities/libutil.la
In sharedObject/Makefile.am, use the LIBADD primary:
lib_LTLIBRARIES = sharedObject.la
sharedObject_la_SOURCES = sharedObject.h sharedObject.c thing.c
sharedObject_la_LIBADD = ../utilities/libutil.la
If you actually want a sharedObject.so that is to be dynamically loaded, you also need:
sharedObject_la_LDFLAGS = -module
Otherwise, the target should be called libsharedObject.
The top level Makefile.am should order SUBDIRS so that the dependency is built first:
SUBDIRS = utilities executable sharedObject

How to use autotools for deep projects?

I have a C project that has the following structure
Main/
Makefile.am
bin/
src/
Makefile.am
main.c
SomeLibrarySource/
SomeFuncs.c
SomeFuncs.h
The main.c contains the main function that uses functions defined in the SomeFuncs.{h/c} files.
I want to use autotools for this project. I read a couple of resources on autotools. But, I was only able to manage using autotools for a single level project where all source, object and other files reside in the same directory.
Then I got some links that talked about using autotools for deep projects like this one and then I got confused.
Right now I have two Makefile.am as follows
Makefile.am
SUBDIRS=src
src/Makefile.am
mainprgdir=../
mainprg_PROGRAMS=main
main_SOURCES=main.c
I am pretty sure that these files should not be as I have them now :P
How do I use autotools for the above project structure? (At least what should be there in those Makefile.am(s) and where should I place them.
EDIT:
One more thing! At the end I would like to have the object files created in the bin directory.
Thanks
mainprogdir=../ does not make a whole lot of sense (you don't know what it is relative to on installation). Probably intended:
# Main/Makefile.am
# .━━ target for `make install`
# |
# ↓ ↓━━ target for compilation
bin_PROGRAMS = bin/main
# ↓━━ based upon compilation target name
bin_main_SOURCES = src/main.c
There are two main approaches. If the functions in SomeLibrarySource are used only by main, then there's no need to build a separate library and you can simply specify the source files in src/Makefile.am
main_SOURCES = main.c SomeLibrarySource/SomeFuncs.c
However, if you actually want to use the functions in other code in your tree, you do not want to compile SomeFuncs.c multiple times but should use a convenience library.
# Assigning main_SOURCES is redundant
main_SOURCES = main.c
main_LDADD = SomeLibrarySource/libSomeFuncs.a
noinst_LIBRARIES = SomeLibrarySource/libSomeFuncs.a
AM_CPPFLAGS = -I$(srcdir)/SomeLibrarySource
(You'll need AC_PROG_RANLIB in configure.ac to use convenience libraries.)
If the source file is named SomeFuncs.c, automake will not need Makefile.am to specify SomeLibrarySource_libSomeFuncs_a_SOURCES, but if the name of the source code file does not match the name specified in noinst_LIBRARIES, SomeLibrarySource_libSomeFuncs_a_SOURCES should be set to the list of files used to build the library. Note that you do not need to specify main_SOURCES, since main.c is the default value if left unspecified (but it's not a bad idea to be explicit.) (In all of this, I am not comfortable use CamlCase names, but the system I'm using uses a case insensitive file system (biggest mistake apple ever made) and the examples I give here are working for me. YMMV)
You could of course do a recursive make, or build the library as a separate project and install it. (I like the final option. Libraries with useful features should exist on their own.)

Resources