Antimake variable EMBED_SUBDIRS list names of directories that contains Makefile fragmants that are to be embedded into current Makefile.
-
Plus: Proper dependencies, work well with parallel Make.
-
Minus: Cannot go into subdir and run make there.
-
Minus: Fragments are not stand-alone, so need some care when writing.
Intro to EMBED_SUBDIRS
To better understand what EMBED_SUBDIRS does, let's start with simple case - single Makefile that references files under subdir:
$ mkdir -p src $ cp ../../antimake.mk .
bin_PROGRAMS = src/myprog src_myprog_SOURCES = src/myprog.c include antimake.mk
#include <stdio.h> int main(void) { printf("myprog\n"); return 0; }
$ make CC src/myprog.c CCLD src/myprog $ ./src/myprog myprog $ make clean CLEAN src/myprog
Now you can put the lines that reference files under src/ also into src and include that from top-level Makefile:
bin_PROGRAMS = src/myprog src_myprog_SOURCES = src/myprog.c
include src/Makefile.inc include antimake.mk
$ make CC src/myprog.c CCLD src/myprog $ ./src/myprog myprog
This works but the problem is that although the Makefile is local, it still sees files from top-Makefile-level. So that is what EMBED_SUBDIRS helps with - it allow to use local filenames in Makefile fragment, and it converts them to top-level filenames when including. It knows only few type of variables it needs to convert:
-
target filenames in primares lists (*_PROGRAMS, *_LIBRARIES, etc)
-
target_SOURCES: foo_SOURCES → sub_dir_foo_SOURCES with filename conversion
-
other target variables: foo_* → sub_dir_foo_* without filename conversion
-
EXTRA_DIST, CLEANFILES, DISTCLEANFILES, MAINTAINERCLEANFILES
Any other variables stay untouched, and obviously they can mess up top-level variables. So the included Makefile should be as clean as possible.
Setup source tree for EMBED_SUBDIRS
Setup directories, install Antimake
$ mkdir -p lib1/sublib lib2 $ cp ../../antimake.mk .
Prepare sources
#include <stdio.h> void func1(void); void func2(void); void func3(void); int main(void) { func1(); func2(); func3(); printf("main\n"); return 0; }
#include <stdio.h> void func1(void) { printf("func1\n"); }
#include <stdio.h> void func2(void) { printf("func2\n"); }
#include <stdio.h> void func3(void) { printf("func3\n"); }
Prepare Makefiles
PACKAGE_NAME = test-subdirs PACKAGE_VERSION = 1.0 EMBED_SUBDIRS = lib1 lib1/sublib lib2 bin_PROGRAMS = prog prog_SOURCES = main.c prog_LDADD = lib1/func1.a lib1/sublib/func2.a lib2/func3.a EXTRA_DIST = Makefile antimake.mk include antimake.mk
noinst_LIBRARIES = func1.a func1_a_SOURCES = func1.c EXTRA_DIST = Makefile.am
noinst_LIBRARIES = func2.a func2_a_SOURCES = func2.c EXTRA_DIST = Makefile.am
noinst_LIBRARIES = func3.a func3_a_SOURCES = func3.c EXTRA_DIST = Makefile.am
Building
Build the project
$ make CC main.c CC lib1/func1.c AR lib1/func1.a RANLIB lib1/func1.a CC lib1/sublib/func2.c AR lib1/sublib/func2.a RANLIB lib1/sublib/func2.a CC lib2/func3.c AR lib2/func3.a RANLIB lib2/func3.a CCLD prog $ ls Makefile antimake.mk lib1 lib2 main.c prog src $ ./prog func1 func2 func3 main
We can now install it:
$ make install prefix=/opt DESTDIR=./inst INSTALL prog ./inst/opt/bin $ ls ./inst/opt/bin prog
Now we can create package that can be given to others.
$ make dist CHECK dist-gzip MKDIR test-subdirs-1.0 COPY test-subdirs-1.0 PACK test-subdirs-1.0.tar.gz $ ls Makefile inst lib2 prog test-subdirs-1.0.tar.gz antimake.mk lib1 main.c src $ tar tzf test-subdirs-1.0.tar.gz | sort test-subdirs-1.0/ test-subdirs-1.0/Makefile test-subdirs-1.0/antimake.mk test-subdirs-1.0/lib1/ test-subdirs-1.0/lib1/Makefile.am test-subdirs-1.0/lib1/func1.c test-subdirs-1.0/lib1/sublib/ test-subdirs-1.0/lib1/sublib/Makefile.am test-subdirs-1.0/lib1/sublib/func2.c test-subdirs-1.0/lib2/ test-subdirs-1.0/lib2/Makefile.am test-subdirs-1.0/lib2/func3.c test-subdirs-1.0/main.c
Clean the tree
$ make clean CLEAN prog CLEAN lib1/func1.a CLEAN lib1/sublib/func2.a CLEAN lib2/func3.a CLEAN clean $ ls Makefile antimake.mk inst lib1 lib2 main.c src test-subdirs-1.0.tar.gz
Done!