Automake linking modules - gcc

I have a problem with automake/autoconf. I will show you the layout of my source tree first:
src
------arch
----------avr
--------------i2c.c
-------sys
-----------thread.c
Now my problem. It isn't that hard to fully compile arch/avr/i2c.c and sys/thread.c. But what i actualy want is to compile all my sub directories partialy (with gcc -c) and then link all objects from one subdir together (ld -r) and make a program of of those subdirectory object files when all subdirectories are compiled. Is this possible, and if so, how?
Greetz,
Michel

Automake has no support for ld -r, and I don't think libtool can do it either. The usual setup is to build one static archive per directory, and link the main program with these static archives.
You could have in arch/avr/Makefile.am
noinst_LIBRARIES = libavr.a
libavr_a_SOURCES = i2c.c ...
something similar in sys/, and src/Makefile.am would look like
SUBDIRS = arch sys .
bin_PROGRAMS = foo
foo_SOURCES = main
foo_LDADD = arch/avr/libavr.a sys/libsys.a

Related

With autotools how do I get pandoc to run in the src dir next to c programs

I am creating a c program where I use a design.md document inside the src directory so the design is close to the source code. I use autotools, but I do not know how to get automake to run pandoc next to the c compiler. This is my Makefile.am:
bin_PROGRAMS = brun
AM_CFLAGS = -Wall -Wextra -std=c11
AM_LDFLAGS = -rdynamic
lib_LTLIBRARIES = libbrun.la
libbrun_la_SOURCES = Object.c Box.c Module.c
libbrun_la_LDFLAGS = -version-info 0:0:0
brun_SOURCES = main.c
brun_LDADD = libbrun.la
include_HEADERS = Object.h Object.r.h Box.h Box.r.h Module.h Module.r.h
# EXTRA_DIST = Object.r Box.r Module.r
#
%.pdf: %.md
pandoc -o $# $<
The above code does nothing to generate my files design.md and todo.md which are in the src directory.
I have searched for clues how to do this but most results point to how to use autotools for compiling or just contain general tutorials. I have been searching for a day or so and my have become blind to the obvious.
Does anyone know how to get automake to run pandoc, next to compiling my c sources?
You have provided a make rule that describes how to build PDFs from your .md files, but your Makefile.am doesn't anywhere express that any PDF files actually should be built, much less which ones.
For files that you want to have installed (and why are you building docs if you don't want to install them) the specifics depend on where you want them to go, but for example,
pkgdata_DATA = design.pdf todo.pdf
That would build them as part of make all and install them to a subdirectory of $(datadir) during make install (probably something like /usr/local/share/brun).
If for some reason you want the files built, but not installed, then you could instead use
noinst_DATA = design.pdf todo.pdf
Either way, since you're relying on a suffix rule for unusual suffixes, you'll probably also have to tell Automake about them:
SUFFIXES = .md .pdf
Note well that make recognizes a similar construct, but you should not use make's variation in Automake; instead, use the above variable-assignment form, and Automake will handle converting that for make's use.

GNU autotool:No rule to make target

my first question in stack overflow!
Quick overview of my question: I use autotool to generate a C program. When I use make command, I meet the error:
No rule to make target `../lib_foo/libfoo.a', needed by `mistery_foo'. Stop.
Something detail of my questions:
I am doing an assignment of my teacher, in which I should use GNU autotool to generate a very simple C program.
File structure: /project: main, lib_foo, Makefile.am, configure.ac
/project/main: main.c, main.h, Makefile.am
/project/lib_foo: foo.c, foo.h, Makefile.am
Following is what I write for configure.ac and makefile.am:
I. "project/configure.ac":
AC_PREREQ([2.67])
AC_INIT([project1],[0.01],[cwentai01#gmail.com])
AM_INIT_AUTOMAKE([1.9 foreign])
AC_CONFIG_SRCDIR([./lib_foo/foo.c])
AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AC_PROG_RANLIB
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <mistery.h>]],\
[[ mistery_value(1);]])],\
[AC_DEFINE([MISTERY_VALUE_ONEPARAM], [],[CONSTANT])],[])
AC_SEARCH_LIBS([mistery_value],[magic vadoo mistery],[],[AC_MSG_ERROR([Libraries (mistery, magic, vadoo) not found])])
AC_CONFIG_FILES([Makefile lib_foo/Makefile main/Makefile])
AC_OUTPUT
P.S. the AC_COMPLIE_IFELSE is used to judge the number of the parameters in function mistery_value(). I think it has nothing to do with the error.
II. project/Makefile.am:
SUBDIRS = main lib_foo
III. project/main/Makefile.am
LDADD = ../lib_foo/libfoo.a
mydir = ../uselessbin
my_PROGRAMS = mistery_foo
mistery_foo_SOURCES = main.c main.h
mistery_foo_LDADD = ../lib_foo/libfoo.a
IV. project/lib_foo/Makefile.am
noinst_LIBRARIES = libfoo.a
libfoo_a_SOURCES = foo.c foo.h
Then I run with the order of commands:
>cd project
> aclocal
> autoheader
> automake -a
> autoconf
> ./configure
> make
> make install
> ./uselessbin/mistery_foo
When I run make command, I got the error:
No rule to make target `../lib_foo/libfoo.a', needed by `mistery_foo'. Stop.
I suppose the problem may be that I don't have libfoo.a properly installed. But the library libfoo.a should not be installed but only compiled so I have to use 'noinst_' in lib_foo/Makefile.am. That's why I get stucked here.
Any answers will be appreciated.
Thanks for your help!
The problem is that you're using recursive automake, and in this case, dependencies crossing directory paths will just not resolve to extra rules: main/Makefile.am does not know how to make targets in lib_foo.
The quick fix up is to change your SUBDIRS declaration in the top-level Makefile.am to:
SUBDIRS = lib_foo main
This way main/mystery_foo will only be built after lib_foo and its targets are built. Of course this does not allow you to just make in main/ and have it work.
The other suggestion from the previous post, to use non-recursive automake is a more proper solution, because then all the dependencies can be resolved from a single Makefile.am.
Your procedure looks mostly totally fine. I just found a few possible mistakes:
Your configure.ac should have LT_INIT instruction
In project/main/Makefile.am I would change ../lib_foo/libfoo.a to libfoo.a
If the previous doesn't work, I would recommend to have a single Makefile.am and not recursive Makefile.am (Recursive Makefile.am can be harder to code and might damage the performance of the compilation)

Linking generated library using autotools

I have a following directory structure
src/
kernel/
gui/
In kernel/ directory, I have generated a library named libkernel.a and in gui/ directory I have to use libkernel.a to generate libgui.a.
I added this to the gui/Makefile.am
libgui_a_LIBADD = $(srcdir)/kernel/libkernel.a
But I am getting the following error
*** No rule to make target `kernel/libkernel.a', needed by `libgui.a'. Stop.
So I don't understand how do I link libkernel.a properly.
Edit/Explanation
In gui/ directory I have one somegui.cpp file that uses xclass.h which is in kernel/ directory.
So in order to solve that issue I am asking how should I proceed.
Try to use non-recursive automake to avoid these kind of problems.
https://www.flameeyes.eu/autotools-mythbuster/automake/nonrecursive.html
Sidenode: use $(top_builddir) when referring to compiled objects. Otherwise your code will break when srcdir != builddir
If you really have to do it recursive, than you can add a rule to gui/Makefile.am
$(top_builddir)/kernel/libkernel.a:
cd $(top_builddir)/kernel && $(MAKE)
Note: If you want to use parallel make (-j) you also need to make sure that in src/Makefile.am there is a dependency between the subdirs
.PHONY kernel gui
kernel:
cd kernel && $(MAKE)
gui: kernel
cd gui && $(MAKE)

Defining additional make targets using gnu autotools

I am beginning to learn autotools in order to first understand and later extend an existing project's build system. Currently the project builds a program as it's output. The build system is quite complex consisting of several subdirectories and Makefile.am's with files generated in a maintainer-mode and so on. I would like to optionally be able to create a library using much of the same source code, reusing much of the the existing build system.
What I am imagining is a new make target so that after running configure, I can then run either make to make the program, or, say, make library to build the library. What is the correct way to do this or something with a similar effect?
I do not want to build both the library and program when I run plain make (just the program as before), and I do not want to build the program when I run make library (I only want the library).
If someone could provide a simple example, e.g. a program made up of main.c, foo.c and bar.c and a library made up of foo.c and bar.c that would be really helpful too.
EDIT
To clarify, I originally thought that the program and lib could be built entirely separately. The library contains only a subset of the code of the main program, and I believed the two were separate entities. However, things are more complicated. The program itself is built and used to output some code which is then compiled into the program in a second step (I think). I have effectively got what I want by doing the following steps.
First add a conditional to configure.ac
dnl Adds LIBRARY conditional for --enable-foolib mode to
dnl build foo as a library
AC_ARG_ENABLE(foolib,
AS_HELP_STRING([--enable-foolib],
[enable qucslib build, default: no]),
[case "${enableval}" in
yes) foolib=true ;;
no) foolib=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-foolib]) ;;
esac],
[foolib=false])
AM_CONDITIONAL(FOOLIB, test x"$foolib" = x"true")
Then in the appropriate Makefile.am I did something similar to the following:
if FOOLIB
noinst_LIBRARIES = libbar.a libfoo.a
else
noinst_LIBRARIES = libbar.a
endif
bin_PROGRAMS = barprog
barprog_SOURCES = main.cpp src1.cpp src2.cpp etc.cpp
barprog_LDADD = libbar.a \
subdir1/libsubdir1.a \
subdir2/libsubdir2.a \
etcdir/libetc.a
... other stuff
if FOOLIB
libfoo_a_LIBADD = libbar.a \
subdir1/libsubdir1.a \
subdir2/libsubdir2.a \
etcdir/libetc.a
libfoo_a_SOURCES = src1.cpp src2.cpp etc.cpp
endif
Then when I want to make the library I do
configure --enable-foolib
make
This works for now, but seems kludgy. I wasn't sure though how to implement the provided answer in the build system.
If the program depends on the library, then it will not be possible to build the program without building the library. You already have the ability to build individual libraries: configure && make libfoo.a should work just fine (or make libfoo.la). If you wish a target named library, you can simply add the following to any Makefile.am:
library:
libfoo.a
(Or you may need libfoo.la. Basically, if the library is specified in Makefile.am under the LIBRARIES primary, then you would use libfoo.a, but if specified under an LTLIBRARIES primary, you would use libfoo.la.) This will only create a library target in each directory that contains a Makefile.am. If you have a complex recursive build (you should really simplify it, but that's another question), you can put something like the following in your top-level Makefile.am to build the libraries throughout the tree:
library:
cd subdir && $(MAKE) $(AM_MAKEFLAGS) library
This assumes you have added a library target to subdir/Makefile.am as described above.
To be pedantic, you might want to use $(am__cd) instead of cd, but it's not strictly necessary.

Link static library against another static library

I am trying to link a static library [1] into another static library [2] with scons.
Unfortunately the emitted call to "ar" never contains any path to library [1].
According to this post How to merge two "ar" static libraries into one it should be possible to merge to archives into one.
Is the usual call to CheckLibWithHeader not sufficient here?
Best regards
Have you tried specifying the complete path to library [1] when referring to it with the SCons ar command?
Brady
Adding more info to my original answer:
Since you havent posted your SCons scripts, I'll assume its something like the one I present below:
Normally, the LIBPATH construction variable is used to specify paths to libraries, but that appears to only work with the Program() builder and is not used with the ar command. What needs to be done then is to specify the complete path for the library in question. Assuming I have the following directory structure:
# tree .
.
|-- SConstruct
|-- fileA.cc
|-- fileA.o
|-- libB
| `-- libmoduleB.a
|-- libmoduleA.a
`-- libmoduleC.a
Here is the SConscript that shows how to do so:
env = Environment()
env.Library(target = 'moduleA', source = 'fileA.cc')
env.Library(target = 'moduleC', source = ['libmoduleA.a', '#libB/libmoduleB.a'])
Or Instead of the relative dir '#libB', you could specify an absolute path. (the '#' in a path means its relative to the SConscript)
And, to make it portable, you should specify the moduleB library (and moduleA) like this:
libBname = "%smoduleB%s" % (env['LIBPREFIX'], env['LIBSUFFIX'])
libB = os.path.join(pathToLibB, libBname)
Here is the result:
# scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o fileA.o -c fileA.cc
ar rc libmoduleA.a fileA.o
ranlib libmoduleA.a
ar rc libmoduleC.a libmoduleA.a libB/libmoduleB.a
ranlib libmoduleC.a
scons: done building targets.
You'd need to create a builder which runs the commands in the other SO question you've linked to.
ar -x libabc.a
ar -x libxyz.a
ar -c libaz.a *.o
Though you might need a scanner to find the files contained in each static library (ar t libabc.a) and then use the output from that as the input to a normal static library builder.
ofiles = env.unArchive('libabc.a')
ofiles.extend(env.unArchive('libxyz.a'))
env.StaticLibrary('az',ofiles)
Something like the above should work.

Resources