Library Files
Libraries are collections of
precompiled functions that have been written to be reusable. Typically, they
consist of sets of related functions to perform a common task. Examples include
libraries of screen handling functions (the curses
library) and database access routines (the dbm library).
We'll meet these libraries in later chapters.
Standard system libraries are
usually stored in /lib and /usr/lib. The
C compiler (or more exactly, the linker) needs to be told which libraries to
search, as, by default, it searches only the standard C library. This is a
remnant of the days when computers were slow and CPU cycles expensive. It's not
enough to put a library in the standard directory and hope the compiler will
find it; libraries need to follow a very specific naming convention and need to
be mentioned on the command line.
A library name always starts with lib. Then
follows the part indicating what library this is (like c for the C
library, or m for the mathematical library). The last part of
the name starts with a dot ., and specifies the type of the library:
Ø
.a for traditional, static
libraries
Ø
.so and .sa for shared
libraries (see below)
Usually, the libraries exist in both static and shared
formats, as a quick ls /usr/lib
will show. You can instruct the compiler to search a library either by giving
it the full path name or by using the -l flag. For
example,
$ cc -o fred fred.c
/usr/lib/libm.a
tells the compiler to compile
file fred.c, call the resulting program file fred
and search the mathematical library in addition to the standard C library to
resolve references to functions. A similar result is achieved through:
$ cc -o fred fred.c
-lm
The -lm (no space
between the l and the m) is
shorthand (shorthand is much valued in UNIX circles) for the library called libm.a
in one of the standard library directories (in this case
/usr/lib). An additional advantage of the -lm notation
is that the compiler will automatically choose the shared library when it
exists.
Although libraries usually are found in standard places in
the same way as header files, we can add to the search directories by using the
-L
(notice the uppercase letter) flag to the compiler. For example,
$ cc -o x11fred
-L/usr/openwin/lib x11fred.c -lX11
will compile and link a program called x11fred
using the version of the library libX11 found in the directory /usr/openwin/lib.
Static Libraries
The simplest form of library is just a collection
of object files kept together in a ready-to-use form. When a program needs to
use a function stored in the library, it includes a header file that declares
the function. The compiler and linker take care of combining the program code
and the library into a single executable program. You must use the –l option to indicate which libraries,
other than the standard C runtime library, are required.
Static libraries, also known as archives,
conventionally have names that end with .a. Examples
are /usr/lib/libc.a and /usr/X11/lib/libX11.a
for the standard C library and the X11 library.
We can create and maintain our
own static libraries very easily by using the ar (for
archive) program and compiling functions separately with cc -c. You
should try to keep functions in separate source files as much as possible; if
functions need access to common data, you can place them in the same source
file and use 'static' variables declared in that file.
Try It Out - Static Libraries
1 Let's create
our own, small library containing two functions and then use one of them in an
example program. The functions are called fred and bill and just print greetings. We'll create
separate source files (called, imaginatively, fred.c and bill.c) for each of them.
#include <stdio.h>
void fred(int arg)
{
printf("fred: you passed %d\n", arg);
}
#include <stdio.h>
void bill(char *arg)
{
printf("bill: you passed %s\n", arg);
}
We can
compile these functions individually to produce object files ready for
inclusion into a library. We do this by invoking the C compiler with the -c
option that prevents the compiler from trying to create a complete program.
This would fail because we haven't defined a function called main.
$ cc -c bill.c fred.c
$ ls *.o
bill.o fred.o
2 Now let's write a program that
calls the function bill. First, it's a good idea to create a header file for our library. This will declare the functions in our
library and should be included by all programs that wish to use our library.
/*
This is
lib.h. It declares the functions fred and bill for users
*/
void bill(char *);
void fred(int);
In fact it's a good idea to include the header file in the
files fred.c and bill.c too. This will help the compiler
pick up any errors.
3 The
calling program (program.c) can be very simple. It includes the
library header file and calls one of the functions from the library.
#include "lib.h"
int main()
{
bill("Hello World");
exit(0);
}
4 We can now compile the program and test it.
For now, we'll specify the object files explicitly to the compiler, asking it to
compile our file and link it with the previously compiled object module bill.o.
$ cc -c program.c
$ cc -o program
program.o bill.o
$ ./program
bill: you passed Hello World
$
5 Now let's create and use a
library. We use the ar program to create the archive and add our
object files to it. The program is called ar because it creates archives or collections
of individual files placed together in one large file. Note that we can also
use ar to create archives of files of any type (like many UNIX utilities, it is a very
generic tool).
$ ar crv libfoo.a
bill.o fred.o
a - bill.o
a - fred.o
The library is created and the
two object files added. To use the library successfully, some systems, notably
those derived from Berkeley UNIX, require that a table of contents be created
for the library. We do this with the ranlib
command. This step isn't necessary (but harmless) when, as in Linux, we're
using the GNU software development tools.
$ ranlib libfoo.a
Our library is now ready to use. We can add to the list of
files to be used by the compiler to create our program like this:
$ cc -o program
program.o libfoo.a
$ ./program
bill: you passed Hello World
$
We can also use the –l
option to access our library, but as it is not in any of the standard places we
have to tell the compiler where to find it, by using the –L option, like this:
$ cc –o program program.o –L. –lfoo
The –L.
option tells the compiler to look in the current directory for libraries. The –lfoo option tells the compiler to use a
library called libfoo.a (or a
shared library, libfoo.so if
one is present).
To see which functions are
included in an object file, library or executable program, we can use the nm
command. If we take a look at program and lib.a,
we see that the library contains both fred and bill,
but that program contains only bill. When
the program is created, it only includes functions from the library that it
actually needs. Including the header file, which contains declarations for all
of the functions in the library, doesn't cause all of the library to be
included in the final program.
If you're familiar with MS-DOS or Microsoft Windows software
development, there are a number of direct analogies here.
|
Item
|
UNIX
|
DOS
|
|
Object Module
|
func.o
|
FUNC.OBJ
|
|
Static
Library
|
lib.a
|
LIB.LIB
|
|
Program
|
program
|
PROGRAM.EXE
|
Shared Libraries
One disadvantage of static
libraries is that when we run many programs at the same time and they all use
functions from the same library, we may end up with many copies of the same
functions in memory and indeed many copies in the program files themselves. This
can consume a large amount of valuable memory and disk space.
Many UNIX systems support shared libraries that can overcome
both of these disadvantages. A complete discussion of shared libraries and
their implementation on different systems is beyond the scope of this book, so
we'll restrict ourselves to the visible implementation under Linux.
Shared libraries are stored in
the same places as static libraries, but have a different extension. On a
typical Linux system, the shared version of the standard C library is /lib/libc.so.N,
where N represents a major version number, currently 6.
At the time of writing many Linux
distributions were going through a process of updating the versions of both the
C/C++ compiler used, and the C library. The example outputs shown below are
taken from a Redhat 6.0 distribution using GNU libc 2.1. Your output may differ
slightly if you are not using this distribution.
When a program uses a shared library, it is linked in such a
way that it doesn't contain function code itself, but references to shared code
that will be made available at run time. When the resulting program is loaded
into memory to be executed, the function references are resolved and calls are
made to the shared library, which will be loaded into memory if needed.
In this way, the system can arrange for a single copy of a
shared library to be used by many applications at once and stored just once on
the disk. An additional benefit is that the shared library can be updated
independently of the programs that rely on it. Symbolic links from the file /lib/libc.so.6
to the actual library revision (/lib/libc-2.1.1.so.
at the time of writing) are used.
For Linux systems, the program
(the dynamic loader) that takes care of loading shared libraries and resolving client
program function references is ld.so or ld-linux.so.2.
The additional locations searched for shared libraries are configured in the
file /etc/ld.so.conf, which needs to be processed by ldconfig
if changed, for example when X11 shared libraries are added.
You can see which shared
libraries are required by a program by running the utility ldd:
$ ldd program
libc.so.6 => /lib/libc.so.6 (0x4001a000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
In this case, we see that the standard C library (libc)
is shared (.so). Our program requires major Version 6, which is
provided in this case by GNU libc version 2.1.1. Other UNIX systems will make
similar arrangements for access to shared libraries. Refer to your system
documentation for details.
In many ways, shared libraries are similar to dynamic-link
libraries used under Microsoft Windows. The .so libraries
correspond to .DLL files and are required at run time, while the .sa
libraries are similar to .LIB files that get included in the program
executable.
©1999 Wrox Press Limited,US and UK.
|