Build system
Author : | Christoph Egger |
Author : | Peter Ekberg |
Revision : | 1.5 |
Revision date : | 2005-12-19 |
This document tries to describe generic things from the buildsystem common to all libraries in the GGI project since version 2.2 and how to integrate a new target into a library. This document uses the terms lib for the library, foo for the target and module for the target variant (= usually display, but input or filter in libgii) in the code segments.
The concept
In ancient history, in the land of dinos, the build system did not work like it does today.
The reason was a chicken-egg like problem, you can't build a lib with builtin targets unless you have built the targets and you can't build the targets unless you have built the lib. This chicken-egg problem is not stated quite as accurately as is needed though, and it turns out that it is not a chicken-egg problem at all.
Here is what really matters:
- The lib must be linked prior to linking the shared targets, otherwise you cannot satisfy the lib dependencies of the shared targets.
- However, the targets must be compiled before linking the lib, otherwise they cannot be built into the lib.
In the ancient build system, static linking was disabled and the lib was simply compiled and linked first, followed by compiling and linking the shared targets, i.e. no builtins.
Enter libtool convenience libraries.
Libtool convenience libraries enable the build process to separate the compiling of the targets from the linking of the shared targets in an easy way. So, first the targets are compiled and "linked" into a libtool convenience library. I have quoted "linked" here as it is not really linking that is done, it is more like a collection of the pieces of the target under a single convenient name. A libtool convenience library is a static archive /with/ dependencies and extra twist that if you link with it, you get the whole archive, and not only the referenced object files within the archive as is the normal action with static archives.
Then, the source files of libgii are compiled and linked. When lib*lib* is linked, the libtool convenience libraries of all targets that should be builtin are added to the link. Libtool looks inside the libtool convenience libraries and adds all object files of the target to the link and also merges the dependencies of all targets and those of the lib itself.
Finally, when lib is linked, it is possible to do the actual linking of the shared targets. This is done within the module-shared directories. The actual linking of the target only needs the libtool convenience library and the exported symbol(s) as input, as all target dependencies are recorded in the libtool convenience library.
Adding a target to the build system
It is here assumed that the target is implemented in module/foo/foo.c and that it is having the entry point libdl_foo. The implementation of foo and the actual target functionality is not covered here.
The needed build system changes are grouped by which file the change takes place in.
configure.in
Add a line like this along with the ones with other targets:
build_foo_module="auto"
Add a user option to manually disable the target:
AC_ARG_ENABLE(foo, [ --disable-foo don't build the foo modulelib], build_foo_module=$enableval)
- If the target needs any specific includes, add checks for that. The hypothetical foo target needs bar.h so bar.h is added to the list of other headers looked for by AC_CHECK_HEADERS (For readability in alphabetical order).
If the target needs any specific libraries, add checks for those, too. The hypothetical foo target needs libbar, which has the symbol bar_init, so the following is added:
GGI_CHECK_LIB(bar, bar_init)
NoteGGI_CHECK_LIB has the same syntax as AC_CHECK_LIB, but it tracks dependencies using libtool.
- If the target needs anything else, add checks for that too, if it's not already tested for.
Disable the target if a prerequisite component could not be found:
if test "x$ac_cv_header_bar_h" != "xyes"; then build_foo_module="no" fi if test "x$ac_cv_lib_bar_bar_init" != "xyes"; then build_foo_module="no" fi
Make sure your target is built by adding a hunk of code like this (if you use GGI-current then use the GGI_CHECK_TARGET below):
AC_MSG_CHECKING(if we should build foo modulelib) if test "x$build_foo_module" = "xno"; then AC_MSG_RESULT(no) else MODULESUBDIRS="$MODULESUBDIRS foo" if test "$enable_shared" = "yes"; then MODULEMODULES="$MODULEMODULES foo.la" fi if test "$enable_static" = "yes"; then AC_DEFINE(BUILTIN_MODULE_FOO, 1, [Support for builtin module-foo]) fi AC_MSG_RESULT(yes) fi AM_CONDITIONAL(BULITIN_MODULE_FOO, test "$enable_static" = "yes" -a \ "x$build_foo_module" != "xno")
GGI_CHECK_TARGET(module-foo, build_foo_module, MODULESUBDIRS, MODULEMODULES, foo, foo.la, BUILTIN_MODULE_FOO)
- Add module/foo/Makefile the list in AC_CONFIG_FILES
The config file
Add the target to the configuration along with the other targets:
module-foo module/foo.@DLLEXT@:GGIdl_foo
Also add an alias along with the other aliases:
alias foo module-foo
module/Makefile.am
Add foo to the DIST_SUBDIRS variable (preferably in alphabetical order).
module/foo/Makefile.am
The following Makefile.am builds a libtool convenience library. A libtool convenience library is simply a collection of object files suitable for linking into other libraries (or applications, but that is not usable in this context), shared or not. It also conveniently records dependencies and such.
Make sure that any additional source files are listed in libfoo_la_SOURCES and that any additional header files (or others) are listed in EXTRA_DIST.
AM_CPPFLAGS = -DDEBUG_NAMESPACE='"lib.module.foo"' INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include $(extra_libraries) libfoo_la_LIBADD = -lbar noinst_LTLIBRARIES = libfoo.la libfoo_la_SOURCES = foo.c EXTRA_DIST = EXPSYMS DISTCLEANFILES = Makefile .deps MAINTAINERCLEANFILES = Makefile.in
module/foo/EXPSYMS
The only exported symbol(s) should be the entry point(s) GGIdl_foo (in most cases).
lib/builtins.am
Make sure the foo convencience library above is included in lib, if and only if the foo target should be 'builtin' in lib by adding the following snippet to lib/builtins.am.
if BUILTIN_MODULE_FOO builtins_libs += ${moduledir}/foo/libfoo.la endif
lib/builtins.c
Add this snippet along with the other similar declarations:
#ifdef BUILTIN_MODULE_FOO libfunc_dlinit GGIdl_foo; #endif
Add this snippet to the _target variable definition along with the other similar constructs:
#ifdef BUILTIN_MODULE_FOO { "module-foo", &GGIdl_foo }, #endif
module-shared/Makefile.am
Arrange for a shared module of the target to be built by relinking the libtool convenience library into a libtool shared module.
- Add foo.la to the list in the variable EXTRA_LTLIBRARIES (preferably in alphabetical order).
Add the following snippet:
foo_la_LIBADD = ${top_builddir}/module/foo/libfoo.la ${lib} foo_la_SOURCES = foo_la_LDFLAGS = -rpath $(modulelibdir) ${extra_libraries} \ -shared -module -no-undefined -avoid-version \ -export-symbols ${top_srcdir}/module/foo/EXPSYMS