C++ User's Guide

Chapter 6 Building Libraries

This chapter explains how to build your own libraries.

Understanding Libraries

Libraries provide two benefits. First, they provide a way to share code among several applications. If you have such code, you can create a library with it and link the library with any application that needs it. Second, libraries provide a way to reduce the complexity of very large applications. Such applications can build and maintain relatively independent portions as libraries and so reduce the burden on programmers working on other portions.

Building a library simply means creating .o files (by compiling your code with the -c option) and combining the .o files into a library using the CC command. You can build two kinds of libraries, static (archive) libraries and dynamic (shared) libraries.

With static (archive) libraries, objects within the library are linked into the program's executable file at link time. Only those .o files from the library that are needed by the application are linked into the executable. The name of a static (archive) library generally ends with a .a suffix.

With dynamic (shared) libraries, objects within the library are not linked into the program's executable file, but rather the linker notes in the executable that the program depends on the library. When the program is executed, the system loads the dynamic libraries that the program requires. If two programs that use the same dynamic library execute at the same time, the operating system shares the library among the programs. The name of a dynamic (shared) library generally ends with a .so suffix or .so.number suffix, which specifies a version number.

Linking dynamically with shared libraries has several advantages over linking statically with archive libraries:

However, dynamic libraries have some disadvantages:

Building Static (Archive) Libraries

The mechanism for building static (archive) libraries is similar to that of building an executable. A collection of object (.o) files can be combined into a single library using the -xar option of CC.

You should build static (archive) libraries using CC -xar instead of using the ar command directly. The C++ language generally requires that the compiler maintain more information than can be accommodated with traditional .o files, particularly template instances. The -xar option ensures that all necessary information, including template instances, is included in the library. You might not be able to accomplish this in a normal programming environment since make might not know which template files are actually created and referenced. Without CC -xar, referenced template instances might not be included in the library, as required. For example:


% CC -c foo.cc # Compile main file, templates objects are created.
% CC -xar -o foo.a foo.o # Gather all objects into a library.

The -xar flag causes CC to create a static (archive) library. The -o directive is required to name the newly created library. The compiler examines the object files on the command line, cross-references the object files with those known to the template repository, and adds those templates required by the user's object files (along with the main object files themselves) to the archive. Use of the -xar flag is only for creating or updating an existing archive, not for maintaining the archive. It is equivalent to specifying ar -cr.

It is a good idea to have only one function in each .o file. If you are linking with an archive, an entire .o file from the archive is linked into your application when a symbol is needed from that particular .o file. Having one function in each .o file ensures that only those symbols needed by the application will be linked from the archive.

Building Dynamic (Shared) Libraries

Dynamic (shared) libraries are built the same way as static (archive) libraries, except that you use -G instead of -xar on the command line.

You should not use ld directly. As with static libraries, the CC command ensures that all the necessary template instances from the template repository are included in the library if you are using templates. Furthermore, the C++ compiler does not initialize global variables if they are defined in a dynamic library, unless the library is built correctly. All static constructors and destructors are called from the .init and .fini sections, respectively. All static constructors in a dynamic library linked to an application are called before main() is executed. Finally, exceptions might not work, unless you use the CC -G command to build the dynamic library.

To build a dynamic (shared) library, you must create relocatable object files by compiling each object with the -Kpic or -KPIC option of CC. You can then build a dynamic library with these relocatable object files. If you get any bizarre link failures, you might have forgotten to compile some objects with -Kpic or -KPIC.

To build a C++ dynamic library, libfoo.so.1, containing objects from source files lsrc1.cc and lsrc2.cc, type:


% CC -G -o libfoo.so.1 -h libfoo.so.1 -Kpic lsrc1.cc lsrc2.cc

The -G option specifies the construction of a dynamic library. The -o option specifies the file name for the library. The -h option specifies a name for the shared library. The -Kpic option specifies that the object files are to be position-independent.

Building Shared Libraries With Exceptions

When shared libraries are opened with dlopen(), you must use RTLD_GLOBAL for exceptions to work.


Note -

When building shared libraries with exceptions in them, do not pass the option -Bsymbolic to ld. Exceptions that should be caught might be missed.


Building Libraries for Private Use

When an organization builds a library for internal use only, the library can be built with options that are not advised for more general use. In particular, the library need not comply with the system's application binary interface (ABI). For example, the library can be compiled with the -fast option to improve its performance on a known architecture. Likewise, it can be compiled with the -xregs=float option to improve performance.

Building Libraries for Public Use

When an organization builds a library for use by other organizations, the management of the libraries, platform generality, and other issues become significant. A simple test for whether or not a library is public is to ask if the application programmer can recompile the library easily. Public libraries should be built in conformance with the system's application binary interface (ABI). In general, this means that any processor-specific options should be avoided. (For example, do not use -fast or -xtarget.)

The SPARC ABI reserves some registers exclusively for applications. For V7 and V8, these registers are %g2, %g3, and %g4. For V9, these registers are %g2 and %g3. Since most compilations are for applications, the C++ compiler, by default, uses these registers for scratch registers, improving program performance. However, use of these registers in a public library is generally not compliant with the SPARC ABI. When building a library for public use, compile all objects with the -xregs=no%appl option to ensure that the application registers are not used.

Building a Library With a C API

If you want to build a library that is written in C++ but that can be used with a C program, you must create a C API (application programming interface). To do this, make all the exported functions extern "C". Note that this can be done only for global functions and not for member functions.

If you also want to remove any dependency on the C++ runtime libraries, you should enforce the following coding rules in your library sources:

Using dlopen to Access a C++ Library From a C Program

If you want to dlopen() a C++ shared library from a C program, make sure that the shared library has a dependency on the appropriate C++ runtime (libC.so.5 for -compat=4, or libCrun.so.1 for -compat=5).

To do this, add -lC for -compat=4 or add -lCrun for -compat=5 to the command line when building the shared library. For example:


demo% CC -G -compat=4 ... -lC
demo% CC -G -compat=5 ... -lCrun

If the shared library uses exceptions and does not have a dependency on the C++ runtime library, your C program might behave erratically.


Note -

When shared libraries are opened with dlopen, RTLD_GLOBAL must be used for exceptions to work.


Building Multithreaded Programs

All libraries shipped with the C++ compiler are multithreading-safe. If you want to build a multithreaded application, or if you want to link your application to a multithreaded library, you must compile and link your program with the -mt option. This option passes -D_REENTRANT to the preprocessor and passes -lthread in the correct order to ld. For -compat=4, the -mt option ensures that libthread is linked before libC. You should not link your application directly with -lthread as this causes libthread to be linked in an incorrect order.

The following example shows the correct way of building a multithreaded application:


demo% CC -c -mt myprog.cc
demo% CC -mt myprog.o

The following example shows the wrong way of building a multithreaded application:


demo% CC -c -mt myprog.o
demo% CC myprog.o -lthread

Indicating Multithreaded Compilation

You can check whether an application is linked to libthread or not by using the ldd command:


demo% CC -mt myprog.cc
demo% ldd a.out
libm.so.1 =>      /usr/lib/libm.so.1
libCrun.so.1 =>   /usr/lib/libCrun.so.1
libw.so.1 =>      /usr/lib/libw.so.1
libthread.so.1 => /usr/lib/libthread.so.1
libc.so.1 =>      /usr/lib/libc.so.1
libdl.so.1 =>     /usr/lib/libdl.so.1

Using libC With Threads and Signals

The C++ support libraries, libCrun, libiostream, libCstd, and libC are multithread safe but are not async safe. This means that in a multithreaded application, functions available in the support libraries should not be used in signal handlers. Doing so can result in a deadlock situation.

It is not safe to use the following in a signal handler in a multithreaded application: