$ cc

-Aa -c +z length.c

Make new length.o.

$ ld

-b -o libunits.sl oldlength.o \

Relink the library.

 

volume.o mass.o length.o

 

Thereafter, any programs linked with libunits.sl use the new versions of length-conversion routines defined in length.o. Programs linked with the old version of the library still use those routines from oldlength.o. For details on linking with shared libraries, see“Determining How to Link Programs or Libraries (Linker Tasks)” (page 27).

Specifying a Version Date

When adding modules to a library for a particular release of the library, it is best to give all modules the same version date. For example, if you complete file1.o on 04/93, file2.o on 05/93, and file3.o on 07/93, it is best to give all the modules the same version date, say 07/93.

The reason for doing this is best illustrated with an example. Suppose in the previous example you gave each module a version date corresponding to the date it was completed: 04/93 for file1.o, 05/93 for file2.o, and 07/93 for file3.o. You then build the final library on 07/93 and link an application a.out with the library. Now suppose that you introduce an incompatible change to function foo found in file1.o, set the version date to 05/93, and rebuild the library. If you run a.out with the new version of the library, a.out gets the new, incompatible version of foo because its version date is still earlier than the date the application was linked with the original library.

Switching from Archive to Shared Libraries

There are cases where a program may behave differently when linked with shared libraries than when linked with archive libraries. These are the results of subtle differences in the algorithms the linker uses to resolve symbols and combine object modules. This section covers these considerations. (See also “Caution When Mixing Shared and Archive Libraries” (page 118) .)

Relying on Undocumented Linker Behavior

Occasionally, programmers may take advantage of linker behavior that is undocumented but has traditionally worked. With shared libraries, such programming practices may not work or may produce different results. If the old behavior is absolutely necessary, linking with archive libraries alone (-aarchive) produces the old behavior.

For example, suppose several definitions and references of a symbol exist in different object and archive library files. By specifying the files in a particular link order, you can cause the linker to use one definition over another. But doing so requires an understanding of the subtle (and undocumented) symbol resolution rules used by the linker, and these rules are slightly different for shared libraries. So make files or shell scripts that took advantage of such linker behavior prior to the support of shared libraries may not work as expected with shared libraries.

More commonly, programmers may take advantage of undocumented linker behavior to minimize the size of routines copied into the a.out files from archive libraries. This is no longer necessary if all libraries are shared.

Although it is impossible to characterize the new resolution rules exactly, the following rules always apply:

1.If a symbol is defined in two shared libraries, the definition used at run time is the one that appeared first regardless of where the reference was.

2.The linker treats shared libraries more like object files.

As a consequence of the second rule, programs that call wrapper libraries may become larger. (A wrapper library is a library that contains alternate versions of C library functions, each of which performs some bookkeeping and then calls the actual C function. For example, each function in the wrapper library may update a counter of how many times the actual C routine is called.) With archive libraries, if the program references only one routine in the wrapper library, then only the

Switching from Archive to Shared Libraries 115