Table of Contents
In most cases, development efforts consisting of large amounts of dynamic and evolving code will be best served by sticking with static libraries. Sometimes, however, it may be desirable or necessary to create shared library object files. Abuild provides support for creating shared libraries on UNIX-based systems and DLLs on Windows systems. Note that there are many ancillary concerns one must keep in mind when using shared libraries such as binary interface compatibility. We touch lightly on these topics here, but a full discussion is out of scope for this document.
Building shared libraries with abuild is essentially identical
to building static libraries. You still set up your shared
library targets using TARGETS_lib in
Abuild.mk just as you would for static
libraries. In order to tell abuild that a library should be
created as a shared library, you must set the additional variable
SHLIB_ where
libnamelibname is the name of the library
target. The value of this variable consists of up to three
numbers: major version, minor
version, and revision. These values
tell potential users of your library when the library has
changed. In general, you should only modify these values when
you are releasing versions of your library. During development,
it's best to just leave them alone or else your version numbers
will get very large and you will lose all the advantages of using
shared libraries because of the need to relink everything all the
time. Before a release, the major version number should be
incremented if the shared library has had interfaces removed or
modified since the last release as those operations would make
old binaries that linked with the shared library fail to work
with the new version. The minor version should be incremented if
no interfaces were changed or removed but new interfaces were
added. This indicates that old binaries would work with new
libraries but new binaries may not work with old libraries. The
revision number should be incremented if any changes were made to
the shared library code that did not affect the interfaces. This
just tells the user that the library has changed relative to
another version that may be installed. On UNIX platforms,
abuild will build executables that link against shared
libraries in such a way that they will fail to locate shared
libraries whose major version numbers do not match what they
linked against. The unversioned .so file
and the .so file with only the major version
will be symbolic links to the fully versioned file name. (For
example, if the actual shared library file were
libmoo.so.1.2.3, both
libmoo.so and
libmoo.so.1 would be symbolic links to it.)
On Windows systems, the version number parameters are ignored.
Note that all the version number parameters are optional.
Although they should always be used when creating actual shared
libraries that you intend to link programs against, they may be
omitted in some other cases. For example, if you are building a
shared library object file that will be loaded at runtime or used
as a plugin (such as with Java native code), then it may be
appropriate to omit the version numbers altogether. Even if the
SHLIB_
variable is set to an empty string, abuild will still make a
shared library instead of a static library. There is no way to
create both a shared and a static version of the same library at
the same time, but it is possible to create a shared library that
links against a static library, which can be used to achieve the
same effect.
libname
By default, when a shared library depends on a static library,
abuild will not link the static library into the shared
library. On some systems, you must link
static libraries into shared libraries in order for the build to
succeed, and on other systems, it is optional. When mixing
shared libraries and static libraries, you should make sure that
you don't include two copies of the same symbols in more than one
place (two shared libraries or a shared library and an
executable). Some systems handle this case acceptably, and
others don't. Even in the best case, doing this is wasteful and
potentially confusing. In order to tell abuild to link a
static library into a shared library, set the variable
LINK_SHLIBS to 1 in your
Abuild.mk. This applies to all shared
libraries built in a build item.
Abuild allows you to mix executables, shared libraries, and
static libraries in the same build item. If you do this, all
executable targets will link with all shared and all static
library targets. If LINK_SHLIBS is set, then
all shared libraries will also link with all static libraries.
In order to allow static libraries to be linked into shared
libraries, abuild compiles all library object files as
position-independent code. In some extremely rare cases, you may
wish to avoid doing this as there is a very minor performance
cost to do it. If you wish to prevent a specific source file
from being compiled as position-independent code, set the
variable
NOPIC_ to
filename1 where filename is
the name of the source file. For example, the code
NOPIC_File.cc := 1 in your
Abuild.mk file would prevent
File.cc from being compiled as
position-independent code. Note that abuild does not check to
make sure that code compiled in this way is not eventually linked
into a shared library. If you try to link
non-position-independent code into a shared library, it may not
link at all, or it may cause undefined and hard-to-trace
behavior. Use of this feature is not recommended unless
absolutely needed to fix some specific problem.
In order to run a program that is linked with shared libraries,
the operating system will have to know where to find the shared
library. Abuild does not include library run path information
in the executables as doing so is inherently dangerous and
non-portable. Even if abuild were to ignore this danger and
include run path information, doing so would potentially preclude
the ability to swap out shared libraries at runtime, which is
often the main reason for wanting to use them in the first place.
[31]
Instead, you will need to make sure that, one way or another, the
shared libraries you need are located in a directory that is in
your shared library path. On most UNIX systems, you can set the
LD_LIBRARY_PATH environment variable or install
the shared libraries into certain system-defined locations. On
some systems (like Linux), you can also add directories to
/etc/ld.so.conf. On Windows, you can
colocate the DLL files with the executables, or you can add the
directories containing the DLL files to your path.
[31] The way the runtime loader behaves when shared library location information is compiled into an executable (as run path data) varies from system to system. In most systems, if the shared library doesn't exist at the compiled-in location, the system will fall back to its standard rules for locating shared libraries. In some systems, if the shared library does exist in the compiled-in location, that copy of the shared library will be used with no way to override it. This may have undesired implications. For example, suppose you were to create an executable that linked with a shared library and included run path information to the development version of the shared library. If you installed that executable and shared library in standard locations on a system without a copy of the development environment, everything would work fine. Then suppose you put a development environment on that system and built a newer version of the same shared library. Your installed executable would actually use the new development copy of the library because it still has that path compiled into it! This is almost certainly not what would be intended. Abuild avoids this issue entirely but not including support for specifying run path data.
For another approach to using shared libraries, look at libtool. The libtool program gets around this problem by creating wrappers around executables and shared libraries in the development tree. Although abuild is not integrated with libtool, such an integration would be possible. The possibility of including support for libtool is actually one of the motivations behind allowing library object files and non-library object files to have different extensions.