Linking generated library using autotools - makefile

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)

Related

automake - target folder in source blocks executing destination

I am trying to understand a makefile from a project I am working on. It's using automake/autotools and contains this simple rule:
DEPS_SRC = $(shell cd $(srcdir); find . -name '*.ez')
DEPS = $(basename $(DEPS_SRC))
all : $(DEPS)
$(DEPS) : % : %.ez
$(UNZIP) -o $<
Say the directory structure is:
my-app/deps/
build/
When executing make my-app in the build folder the rule will basically unpack *.ez files located in the my-app/deps/ folder into build/my-app/deps/ folder.
I don't know if that's enough information to solve the problem that I am going to explain as I don't know enough about automake/autotools. Please ask if any additional information is needed.
The problem is that I noticed that having the unpacked directory in the source folder prevents make from unpacking the archive in the target folder. For example, given the following structure in the source folder:
my-app/deps/archive1.ez
my-app/deps/archive2.ez
my-app/deps/archive2/
make will only unpack archive1.ez in the build folder:
build/my-app/deps/archive1/
I would like to know if this is a bug in my makefile or a feature of automake. If the later, is there any workaround or setting or variable available to disable it?
This is primarily a GNU make question, not particularly specific to the Autotools. However, since the target system's make is of GNU's flavor (else none of this works), we can assume that the Makefile generated by configure uses GNU make's VPATH feature as part of its support for out-of-source (a.k.a. VPATH) builds such as the one you are performing.
The value of the VPATH variable that configure will have inserted into the Makefile is used as a search path for prerequisites that are not found relative to the build directory. The key point, however, is that it is also used as a search path for rule targets. That makes a certain amount of sense, especially for targets that are prerequisites of other rules.
In your case, however, that leads directly to the behavior you describe:
the default target depends on ./my-app/deps/archive2
resolving that name against the build directory does not produce a valid file name
before attempting to build that target, make looks in the directories listed in the VPATH, which, in your example case, will contain .. or an equivalent
make finds .././my-app/deps/archive2 in this VPATH search, and therefore determines that the specified target already exists, and does not need to be built
Thus, the behavior you observe is normal for GNU make, supposing the Makefile is constructed by Autoconf from an Automake-generated template.
is there any workaround or setting or variable available to disable it?
Do you really need one? If the archive file has already been unpacked in the source tree, then you can expect make to find its contents, too, via the VPATH. At least if the Makefile is well-prepared overall for for out-of-source builds.
But if you want to be certain to get the archive files unpacked in the build directory then you can specify that explicitly. This ought to do it:
DEPS_SRC = $(shell cd $(srcdir); find . -name '*.ez')
DEPS = $(basename $(DEPS_SRC))
LOCAL_DEPS = $(addprefix $(abs_builddir)/,$(DEPS))
all : $(LOCAL_DEPS)
$(LOCAL_DEPS) : $(abs_builddir)/% : %.ez
$(UNZIP) -o $<
That prefixes the name of each dependency with the absolute path to the build directory, and updates the rule for unzipping the archives to accommodate it. Targets with absolute paths such as that cannot be located in the VPATH.

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)

Makefile target with wildcard to create symlink using target string

I'd like a set of makefile rules that create a symlink to one of several code modules before building the project. The name of the make target would determine the file to which the symlink points. For example:
The user invokes 'make R3000'
Make sees that 'data.asm' doesn't exist yet, so a symlink is created from 'data_R3000.asm' to 'data.asm'
The build process continues, using data.asm
How can I set up make rules to do this?
Maybe something like:
MODULES := $(patsubst data_%.asm,%,$(wildcard data_*.asm))
all:
...
data.asm:
[ -n "$(filter $(MAKECMDGOALS),$(MODULES))" ] || { echo unknown module: $(MAKECMDGOALS) ; exit 1; }
ln -s $(filter $(MAKECMDGOALS),$(MODULES)) $#
Then make sure data.asm is listed as a prerequisite in the appropriate rules.
I would do something like this:
.PHONY mklink
mklink:
test -e data_$(MAKECMDGOALS).asm || exit 1
ln -s data_$(MAKECMDGOALS).asm data.asm
and then make all (and other targets) dependent on mklink. The reason you shouldn't make data.asm your target in the rule is that if you run make R3000, then data.asm will be created, and then if you run make L2000, the data.asm file will be pointing to the wrong directory, and will not be overwritten (I'll assuming this is not what you want). The test line checks if the link target exists, and if not, it exits with 1, causing the target to fail. You should also add a check that MAKECMDGOALS is exactly one element as well.

(GNU make) installcheck a library

How do I implement the make installcheck target when building a library? That is, I have a check target that creates a test program that links to the created library, called by some script in order to check if the library code functions properly, and I wish to perform the same checks but linking to the library after it has been installed; how can I implement this?
Since I can't find any guides on this, I will present the method that I have come up with, which has been patched together from reading the GNU automake manual and some general trial and error. It might be ugly, but it works...
If the check routines for building a library involve linking the library to a test program and seeing if that program works correctly, then to installcheck the library we need only do the same thing but link the test program to the installed library rather than the locally built library.
Let's call the library alpha (so we'll be creating libalpha.so and/or libalpha.a). Supposing alpha's source code is in the file alpha.cpp in the src directory, we'll create src/Makefile.am as usual:
# src/Makefile.am
lib_LTLIBRARIES = libalpha.la
libalpha_la_SOURCES = alpha.cpp
include_HEADERS = alpha.h
The check routine involves creating a binary beta that links to alpha. The source code for beta is in the file beta.cpp in the directory tests. The automake file tests/Makefile.am looks like this:
# tests/Makefile.am
check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la
We will create our check and installcheck routines by creating "local" targets in tests/Makefile.am like so:
# tests/Makefile.am
# ...
check-local:
# recipe to run when 'make check' is called.
installcheck-local:
# recipe to run when 'make installcheck' is called.
The check and installcheck targets conflict because use of either target prevents the other target from executing properly (one target "taints" the build tree for the other target); in order for the other target to execute properly we need to remove beta and its object files and have the target recompile and re-link as it sees fit according to its nature (installcheck to installed files, check to local files).
We can solve this issue of tainted build trees by simply running make clean in the recipe of both targets. This will clearly remove the tainted builds, but is overzealous because we don't need to rebuild whenever we run the same target again. The build tree is only tainted whenever we run the other target.
We can only solve this complication by remembering which of the two targets had been called previously, which we can do via the creation/destruction of an intermediary file (let's call it taint). The check target is tainted whenever the file taint exists, which it resolves by cleaning, rebuilding and removing taint; and the installcheck target is tainted when the file taint does not exist, which it resolves by cleaning, rebuilding and creating taint.
Our targets will take the form:
# tests/Makefile.am
# ...
check-local:
# First, check to see if the build tree is tainted and rebuild if so
test ! -f taint || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
# Then, run our check tests. Substitute with your shell scripts or testsuite files as appropriate
./beta
installcheck-local:
# First, check to see if the build tree is tainted and rebuild if so
test -f taint || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
# Then, run our installcheck tests. Substitute with your shell scripts or testsuite files as appropriate
./beta
The target check_rebuild needs to rebuild according to how check will run, and will look like this:
# tests/Makefile.am
# ...
.PHONY: check_rebuild
check_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean # remove tainted build tree
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) # rebuild beta
rm -f taint # mark build tree as untainted
The target installcheck_rebuild likewise looks like this:
# tests/Makefile.am
# ...
.PHONY: installcheck_rebuild
installcheck_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean # remove tainted build tree
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
echo 1 > taint # mark build tree as untainted
Note that rebuilding beta in installcheck_rebuild now requires the overriding of the automake variables so that they point to the installed library.
Finally, we need to add the taint file to DISTCLEANFILES so that running distcheck does not fail with "files left in build directory after distclean" errors.
And that should be it. The final tests/Makefile.am should look like this:
# tests/Makefile.am
check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la
taint_file = .taint
check-local:
test ! -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
./beta # substitute with your actual test routines
installcheck-local:
test -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
./beta # substitute with your actual test routines
.PHONY: check_rebuild
check_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
rm -f $(taint_file)
.PHONY: installcheck_rebuild
installcheck_rebuild:
$(MAKE) $(AM_MAKEFLAGS) clean
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
echo 1 > $(taint_file)
DISTCLEANFILES = $(taint_file)
Disclaimer
This has been checked on Linux for a "standard" build, but it may not work on other build environments or if you are trying to do something "exotic". Hopefully it should, but it is not something that I have bothered to check. If there are errors, the problem will likely be a missing or misused variable in one of my targets above.
For example, the check_rebuild target has the line:
check_rebuild:
# ...
$(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
# ...
The variables $(AM_MAKEFLAGS) and $(EXEEXT) are a part of how automake itself creates routines to populate in the Makefiles it creates, and had I neglected them in my targets above, then it might have caused the build to fail (or at least not function as expected).
I have tried to make sure the targets that I have suggested above are likewise canonically constructed, but I may have missed something out. Your best bet in case of build errors is to open the Makefiles generated by automake itself during the build, seeing how it is creating objects and mimicking those constructs in the corresponding Makefile.am files, as I have tried to do.
The other likely issue may be in the "hackish" way I've built the beta binary in the installcheck_rebuild target. Again, your best bet in diagnosing problems will be to see how automake is doing things in the Makefiles it generates, and trying to mimic that. Otherwise, a read of the automake manual will be in order, and failing that, you will likely need the help of people more knowledgeable than me. Good luck.

Makefile - How to save the .o one directory up?

Imagine the following folder structure:
project
src
code.c
makefile
bin
How can I compile code.c to code.o and directly put it inside bin? I know I could compile it to code.o under src and the do "mv code.o ../bin" but that would yield an error if there were compile errors, right? Even if it works that way, is there a better way to do it?
Thanks.
The process should or should not "yield an error" depending on what you mean. If there are compiler errors, you'll know it.
That said, there are several ways to do it with make. The best in this case are probably:
You could put the Makefile in bin. Make is good at using files there to make files here, but not the other way around.
You could specify the target path in the makefile target:
$(MAIN_DIR)/bin/%.o: %.c
$(COMPILE)...
A little late, but if it can be helpful.
This is how I get the up one level directory path from where the makefile is.
$(subst $(notdir $(CURDIR)),,$(CURDIR))
if your project looks like that:
~/myProject/
src/
Makefile
#all the .c and .cpp
bin/
#where you want to put the binaries.
$(CURDIR) will output ~/myProject/src
$(subst $(notdir $(CURDIR)),,$(CURDIR)) will output ~/myProject
You could try moving, but only when the compilation was successful using &&:
code.o: code.c code.h
g++ -c code.c && mv code.o ../
mv code.o ../ will only be executed if g++ returned 0, which is when the compilation was successful. This may not be suitable solution for you if you have very complicated makefile, but I thought I'd share what I know.
You can still use the move approach and survive compiler errors:
cc -c code.c && mv code.o ../bin
This won't run the "mv" part if the "cc" part fails.

Resources