Table of Contents
In C and C++, most environments create library archives that consist of a collection of object files. Most linkers only link object files from libraries into executables if there is at least one function in the object file that is in the calling chain of the executable. In other words, if an object file in a library appears not to contain any code that is ever accessed, that object file is not included in the final executable. Abuild provides a way to force inclusion of all object files in a given library for underlying systems in which this is supported.
There are some instances in which it may be desirable to tell the
linker to include all the object files from a library. Common
examples include times when static libraries are converted into
shared libraries or when an object file is self-contained but
contains a static initializer whose side effects are important.
The doc/example/whole-library
directory
contains an example of doing this. The lib1
and lib2
directories both contain
self-contained classes and have static variables that call those
classes' constructors:
whole-library/lib1/thing1.hh
#ifndef __THING1_HH__ #define __THING1_HH__ class Thing1 { public: Thing1(); virtual ~Thing1(); }; #endif // __THING1_HH__
whole-library/lib1/thing1.cc
#include "thing1.hh" #include <iostream> static Thing1* static_thing = new Thing1; Thing1::Thing1() { std::cout << "in thing1 constructor" << std::endl; } Thing1::~Thing1() { std::cout << "in thing1 destructor" << std::endl; }
whole-library/lib2/thing2.hh
#ifndef __THING2_HH__ #define __THING2_HH__ class Thing2 { public: Thing2(); virtual ~Thing2(); }; #endif // __THING2_HH__
whole-library/lib2/thing2.cc
#include "thing2.hh" #include <iostream> static Thing2* static_thing = new Thing2; Thing2::Thing2() { std::cout << "in thing2 constructor" << std::endl; } Thing2::~Thing2() { std::cout << "in thing2 destructor" << std::endl; }
Neither library is referenced by main.cc
(in
bin
):
whole-library/bin/Abuild.conf
name: main platform-types: native deps: thing1 thing2
whole-library/bin/main.cc
#include <iostream> int main() { std::cout << "In main" << std::endl; return 0; }
Therefore, the linker would not ordinarily link them in even with the dependency on both library build items.
In this example, we force lib1
to be linked
in but not lib2
. This is done by adding the
variable WHOLE_lib_thing1
(since
thing1
is the name of the library) to
lib1
's
Abuild.interface
:
whole-library/lib1/Abuild.interface
INCLUDES = . LIBDIRS = $(ABUILD_OUTPUT_DIR) declare WHOLE_lib_thing1 boolean WHOLE_lib_thing1 = 1 LIBS = thing1
On systems that support this, defining this variable causes the corresponding library to be linked in its entirety into any executables that use the library. This facility may not be supported by all compilers. In particular, it is not supported for Microsoft Visual C++ in versions at least through .NET 2005, in which case setting this variable has cause an error.
For cases in which some users of a library may want to link in
the whole library and others may not, it is also possible to set
the
WHOLE_lib_
variable in an libname
Abuild.mk
. For example, if
you were converting a static library to a shared library, you
might want to do this in the shared library build item's
Abuild.mk
rather than the static library's
Abuild.interface
file. That would prevent
other users of the static library from needlessly linking with
the whole library.
We do not set this variable for lib2
:
whole-library/lib2/Abuild.interface
INCLUDES = . LIBDIRS = $(ABUILD_OUTPUT_DIR) LIBS = thing2
This means that its static initializer will not be linked in on any system. On a system that supports whole-library linking, the main program generates this output:
whole-library.out
in thing1 constructor In main
This output includes the static initializer from
Thing1
but not from
Thing2
.
Note that, in order to be truly portable, an application would have to contain explicit code that accessed the static initializers. We illustrate this in some Java code in Section 25.2, “Mixed Classification Example”. The same technique used for that example would work in C or C++ code.