Previous Next Contents Index Doc Set Home


Introduction to C++ Libraries

1



Overview

Class libraries are modular components of reusable code. Using class libraries can integrate blocks of code that have been previously built and tested.

A C++ library consists of one or more header files and an object library. The header files provide class and other definitions needed to access the library functions. The object library provides compiled functions and data that are linked with your program to produce an executable program.

This manual describes three class libraries provided with the C++ compiler:


Using Class Libraries

Generally, two steps are involved in using a class library. First, include the appropriate header in your source code. Second, link your program with the object library. Code Example 1-1 is an example of how to use the iostream class library. First, the source code, which we assume is in a file called prog.cc:

Code  Example  1-1     Using the iostream Class Library
// file prog.cc
#include <iostream.h>

main()
{
    cout << "Hello, world!\n";
    return 0;
}

This simple example includes the basic header for the iostream classes, iostream.h. It then makes use of the predefined output stream cout, and the overloaded operator<< (often pronounced "insert") to accomplish output.

Linking the final program requires nothing extra when using iostreams. The object code for the library is included in libC.a, which is always linked with your program. The command that compiles and links prog.cc into an executable program called prog is:

demo% CC prog.cc -o prog

The complex number and coroutine libraries have their own separate object libraries, and require that the appropriate library be linked explicitly. Code Example 1-2 is an example that uses complex numbers. It creates a complex number having the value 1+i, then prints it out using iostreams:

Code  Example  1-2     Using the Complex Library
// file prog2.cc
#include <iostream.h>
#include <complex.h>

main()
{
    complex OnePlusI(1.0, 1.0);
    cout << OnePlusI << "\n";
    return 0;
}

When you link this program, you link the iostream library automatically, but you need to link the complex number library explicitly.

demo% CC prog2.cc -o prog2 -library=complex

The -l flag causes the CC driver to find the complex library in its standard place and link it into the program. See the manual page CC(1) for more information about this flag.


Note - The -l flag appears at the end of the command line.
Alternatively, use the -library plus the command-line flags for the supplied libraries listed in Table 1-1:

Table  1-1 Command-Line Flags for Standard Libraries  

Library
flag

iostream

none needed

complex

-library=complex

tasking

-ltask

Tools.h++ v6

-library=rwtool6

Tools.h++ v7

-library=rwtool7

Using Standard Libraries

Under normal circumstances, you need not do anything special to compile a program that calls routines in a standard library. However, the standard library header file must be included at the beginning of your program using a format like:

#include <stdlib.h>

The standard directory location for the system header files is:

/usr/include

The standard location for C++ header files is:

/opt/SUNWspro/SC4.2/include/CC

If the header files you want to use are in a different directory from the standard location, you can specify the location on the CC command line. For example, if the header files are in /usr/libraries/include, you can specify that location in the following command:

demo% CC -I/usr/libraries/include myprog.cc

Using libC with Threads and Signals

The libC library is multi-thread safe (see Chapter 5), but is not async safe. This means that in a multi-threaded application, functions available in libC should not be used in signal handlers. Doing so could result in a deadlock situation.

It is not safe to use the following in a signal handler in a multi-threaded application:

Statically Linking Standard Libraries

The CC driver links in several libraries by default, including libc and libm, by passing -l options to ld. The options are:

-lC,-lC_mtstubs,-lm, -lw,-lcx, and -lc

These options link shared versions of the libraries libC, libw, libm, and libc. If you want some of these libraries to be linked statically, you can use
-nolib described in the C++ User's Guide. With the -nolib option, the driver does not pass any -l options to ld; you must pass these options yourself. The following example shows how you would link statically with libC, and dynamically with libw, libm, and libc on Solaris 2.x:

demo% CC test.c -nolib -Bstatic -lC -lC_mtstubs -Bdynamic -lm 
-lw -lcx -lc

The order of the -l options is important. The -lC, --lm, -lw, and -lcx options appear before -lc. -nolib suppresses all -l options that are passed to ld. Some CC options link to other libraries. These library links are also suppressed by -nolib.


Note - The -lcx option does not exist on Intel or PowerPC.
For example, using the -mt option causes the CC driver to pass -lthread to ld in addition to passing -lC, -lm,-lw, -lcx, and -lc. If you use both -mt and -nolib, the CC driver does not pass any -l options to ld. For further information on -nolib, see the C++ User's Guide. For further information on ld, see the Linker and Libraries Guide.

You may also use the -library and -staticlib flags to link statically. This alternative is much easier than the one described above. The previous example, for instance could be performed as:

% CC test.c -staticlib=libC

Using Shared Libraries

The following shared libraries are included:

libC.so.5, libcomplex.so.5, librwtool.so.2

The occurrence of each shared object is recorded in the resulting a.out file; this information is used by ld.so to perform dynamic link editing at runtime. Because the work of incorporating the library code into an address space is deferred, the runtime behavior of the program using shared library is sensitive to an environment change, that is, moving a library from one directory to another. For example, if your program is linked with libcomplex.so.5 in /opt/SUNWspro/SC4.2/lib on Solaris 2.x, and the libcomplex.so.5 library is later moved into /opt2/SUNWspro/SC4.2/lib, the following message is displayed when you run the binary code:

ld.so: libcomplex.so.5: not found

You can still run the old binary code without recompiling it by setting the environment variable LD_LIBRARY_PATH to the new library directory.

In a C shell:

demo% setenv LD_LIBRARY_PATH \
/opt2/SUNWspro/SC4.2/lib:{$LD_LIBRARY_PATH}

In a Bourne shell:

demo$ LD_LIBRARY_PATH=/opt2/SUNWspro/SC4.2/lib:{$LD_LIBRARY_PATH}
demo$ export LD_LIBRARY_PATH

The LD_LIBRARY_PATH has a list of directories, usually separated by colons. After you type a.out, the dynamic loader searches the directories in LD_LIBRARY_PATH before the default directories.

To see which libraries are linked dynamically in your executable, use the ldd command, as follows:

% ldd a.out

This step should rarely be necessary, because the shared libraries are seldom moved.

For further information on using shared libraries, please see the Solaris 2.x Linker and Libraries Guide, and the SunOS 4.x linker documentation.


Building Shared Libraries

In the following example, lsrc1.cc and lsrc2.cc are C++ modules that contain library functions. sa1.cc and sa2.cc are modules that contain exported library objects that must be initialized.

Because of the nature of C++ and the automatic generation of some object files, such as templates, always use the CC command to build libraries to ensure that these object files are correctly added to your library.

The C++ compiler does not initialize global variables if they are defined in a shared library. For initializers and exceptions to work, you must use the
CC -G
command to build a shared library.

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

To build a C++ shared library libfoo.so.1, type:

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

To assign a name to a shared library for versioning purposes, type:

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

Building Static Archives with Templates

The mechanism of using templates to build static archives is identical to that of building an executable. The driver CC is used in place of ar. CC automatically invokes tdb_link, which handles the preprocessing of object files that may contain templates or references to templates. Without tdb_link, referenced templates may not be included in the archives as required. For example:

Code  Example  1-3     Array Class

array.h

#ifndef _ARRAY_H_
#define _ARRAY_H_
const int ArraySize = 20;
template <class Type> class Array {
    private:
        Type* data;
        int   size;
    public:
        Array(int sz=ArraySize);
        int GetSize();
};
 
#endif // _ARRAY_H_

array .cc

#include "array.h"
 
template <class Type> Array<Type>::Array(int sz)
{
    size = sz;
    data = new Type[size];
}
 
template <class Type> int Array<Type>::GetSize()
{
    return size;
}



Code  Example  1-4     Array Class

foo.cc

#include "array.h"

int foo()
{
    Array<int> IntArray;
    int size = IntArray.GetSize();
    return size;
}

When the above program is compiled with CC, three object (.o) files are created; for example foo.o, constructor.o, and GetSize.o. The two template object files, Array_constructor.o and GetSize.o, are placed in the template repository. If ar is used to build an archive, the three files must be manually included in the command line to resolve the template references. You may not be able to accomplish this in a normal programming environment since make may not know which template files are actually created and referenced. The solution is to use the -xar option, such as:

% CC -c foo.cc # Compile main file, templates are created
% CC -xar -o foo.a foo.o # "Link" the files, placing them in an 
archive

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


Building Shared Libraries with Templates

Shared libraries are built in the same way as static libraries, except for one difference. Instead of specifying -xar on the command line, use -G instead. When tdb_link is invoked via CC, a shared library is created instead of a static archive. All object files on the command line should have been compiled with -pic.

To create a shared library using the above source files:

%CC -G -pic -c foo.cc # Compile main file, templates are created
%CC -G -o foo.so foo.o # "Link" the files, placing them in a 
shared library


Shared Library Behavior

All static constructors and destructors are called from the .init and .fini sections respectively. All static constructors in a shared library linked to an application are called before main() is executed. This behavior is different from that on Solaris 1.x, where only the static constructors from library modules used by the application are called.




Previous Next Contents Index Doc Set Home