After you migrate your source code from an ULTRIX to a DIGITAL UNIX system, you might want to enhance it by using features of the DIGITAL UNIX system. This chapter gives an overview of using three DIGITAL UNIX features: shared libraries, semaphores, and the number of open file descriptors.
For complete information on using DIGITAL UNIX features, see the Programmer's Guide.
Shared libraries allow several applications to use a single copy of a library routine at run time. Shared libraries help save disk space and memory, and they can improve the performance of your application and system.
Using DIGITAL UNIX shared libraries is similar to using archive libraries.
To link your application with a shared library, you must have compiled it on a DIGITAL UNIX system. Therefore, you must recompile and relink ULTRIX applications if you want them to use shared libraries.
This section describes how to use the
cc
command
to link with a shared library.
It also describes how to create shared libraries.
For complete information about using shared libraries, see the Programmer's Guide.
On DIGITAL UNIX systems, the
cc
command links your application with shared libraries by default.
The following
example shows the command you enter to link with the shared version of
libc
:
% cc -o hello hello.c
This command creates an executable
file named
a.out
, which you run.
You can also link your application with a shared library that you create.
For example, suppose you create a shared library named
libspecial_math.so
and store that library in the directory
/usr/person
.
To link with that library, use the
-l
and
-L
options, as shown:
% cc -o hello hello.c -L/usr/person -lspecial_math
To link the application that does not use shared libraries,
you must specify the
-non_shared
option in the
cc
command line, as shown:
% cc -non_shared -o hello hello.c -L/usr/person -lspecial_math
Although shared libraries are the default for most applications, the following applications cannot use them:
Applications that need to run in single-user mode cannot be
linked to shared libraries because the
/usr/shlib
directory
must be mounted to allow access to the shared libraries.
Applications whose primary purpose is single-user benchmarks should not be linked with shared libraries because position-independent code is less efficient than position-dependent code. Also, there is no benefit to sharing memory when only one application is running.
Real-time applications using memory-locking features should not be linked to shared libraries. Memory-locking functions will lock the entire shared library into memory.
If you link your application with shared libraries instead of archive libraries, you might notice some differences in the way symbols are resolved. This section describes these differences.
The shared libraries supplied with DIGITAL UNIX systems
are stored in the
/usr/shlib
directory.
Place all system
shared libraries in this directory to avoid confusion.
When the linker searches
for files that have been specified using the
-l
option,
it searches the following directories, in order:
/usr/shlib
/usr/ccs/lib
/usr/lib/cmplrs/cc
/usr/lib
/usr/local/lib
The linker searches all of the directories for a shared library (an
.so
file).
If it does not find a shared library with the specified
name, the linker searches all of the directories a second time for a static
(an archive) library (an
.a
file).
When you develop applications, you might work with private shared libraries
that are contained in directories other than the
/usr/shlib
directory.
In this case, use the
-L
option to specify
these directories.
Before you execute the program, set the
LD_LIBRARY_PATH
environment variable to point to the directory containing the private
shared libraries.
When the program is executed, the run-time loader,
/sbin/loader
, examines this environment variable and searches the
path, if defined, before searching the default list of directories.
Set the
LD_LIBRARY_PATH
variable in the following
ways:
Enter the
setenv
command at the system
prompt, followed by a colon-separated path.
The following example sets the
path as current directory,
$HOME/testdir
directory (if
defined), and the default shared library directory.
For example:
% setenv LD_LIBRARY_PATH .:$HOME/testdir:/usr/shlib
Add the variable definition to your login or shell startup
files.
For example, you might add the following line to your
.login
or
.cshrc
file, if you work in the C shell:
setenv LD_LIBRARY_PATH .:$HOME/testdir:/usr/shlib
In the following examples, the
/usr/person
directory
contains two versions of the special math library:
libspecial_math.so
is a shared library and
libspecial_math.a
is
an archive library.
When you link with a shared library, symbols must be referenced before the linker searches the shared library. Otherwise, the linker does not find the symbol in the shared library and lists the symbol as undefined.
For example, suppose your library object file,
libspecial_math.o
, defines two functions,
getvalue
and
setvalue
.
Suppose that you create a shared library,
libspecial_math.so
, and an archive library,
libspecial_math.a
,
from the object file.
You call the
getvalue
routine in
the
program1
module of your application, and you call the
setvalue
routine in the
program2
module of your
application.
Suppose you link your application using the archive library, as follows:
% cc -non_shared program1.o -lspecial_math program2.o
The application module
program1
references the
getvalue
routine, which the
libspecial_math
archive
library defines.
That library also defines the
setvalue
routine, and the linker is able to define
setvalue
when
it encounters that symbol in the
program2
module.
Now, suppose you enter the same command, but use the shared library instead of the archive library:
% cc program1.o -lspecial_math program2.o
This command succeeds, but prints a warning message indicating that the symbol is undefined.
To correctly link this application, enter the following command:
% cc program1.o program2.o -lspecial_math
In general, always specify the
-l
option last in the command line.
Symbol name resolution when using shared libraries is similar to name resolution when using static libraries. Symbol names are resolved according to the order in which the object file or shared object containing the symbols appears on the command line. The linker typically takes the leftmost definition for any symbol that must be resolved.
The sequence in which names are resolved proceeds as if the
link
command line were stored in the executable.
When the program
runs, all referenced symbols must be resolved.
The program aborts if any undefined
symbols are referenced.
When you link your application with shared libraries, do not define
the same symbol twice.
For example, you cannot use the following
cc
command to link an application that contains a shared library:
% cc program1.o libspecial_math.so program2.o libspecial_math.a
This command succeeds, but prints warning messages indicating that a symbol is defined multiple times.
If you use the
make
command to build your ULTRIX application, you can use it to
build a DIGITAL UNIX application that uses shared libraries.
You need not modify
your
makefile
file to use it with shared libraries.
Unlike
ULTRIX systems, linking with shared libraries is the default on DIGITAL UNIX systems.
The following example shows a
Makefile
file that
links with shared libraries on a DIGITAL UNIX system:
# Makefile for the Math Program all: math.h program1.o program2.o cc program1.o program2.o -L/usr/person -lspecial_math program1.o: project.h cc -c program1.c
Create one or more source files that define the routines you want to include in the library.
Compile the source file into an object file, as shown:
% cc -c special_math.c
Create the library by using the
ld
command.
(You cannot use the
cc
command to create a shared library.
You must invoke the
ld
command directly.) The following
shows a sample
ld
command:
% ld -shared -no_archive -o libspecial_math.so special_math.o -lc
In this example, the
-shared
option specifies creating a shared (rather than an archive) library.
The
-no_archive
option tells the linker to resolve all symbols
from shared libraries only.
The
-o
option specifies
the name of the shared library.
For this command to succeed without printing warning messages, all symbols
in the
special_math.o
object must be resolved.
In this
case, the
special_math.o
object references symbols that
are defined in
libc
.
The
-lc
option
specifies that
ld
search
libc
to resolve
those symbols.
The
ld
linker searches the
/usr/shlib
directory for
libc
, by default.
If the shared library you are creating references symbols defined in
another shared library, you must name the other shared library in the
ld
command line.
Name the shared library last in the command line
to ensure that the linker encounters the reference to the symbol before it
encounters the definition of the symbol.
For more information on using
ld
to create shared
libraries, see
ld
(1).
You can
also create a shared library from an existing static (archive) library by
using the
ld
command.
The following example converts the
static library,
old.a
, into the shared library,
libold.so
:
% ld -shared -no_archive -o libold.so -all old.a -none -lc
In this example, the
-all
option tells the linker
to link all objects from the
old.a
archive library.
The
-none
option tells the linker to turn off the
-all
option.
The
-no_archive
option applies
to the resolution of the
-lc
option, but not to
old.a
, since it is explicitly mentioned.
Your application starts more efficiently
if your shared libraries can be loaded at a preassigned starting address in
virtual memory.
To allow this efficiency, the
ld
linker
preassigns a starting address to each shared library you create.
At application startup time, a shared library's preassigned starting address may already be in use. In this case, the system assigns a new starting address to the library and the advantage of the preassigned starting address is lost.
To make it more likely that a shared library can use its preassigned
starting address, you can cause the
ld
linker to assign
a unique starting address to each shared library you create.
If you create a shared library that only you
will use, use the
-check_registry
option in the
ld
command line.
This option causes
ld
to search
the file you specify to determine what starting addresses are assigned to
shared libraries.
The linker then assigns an unused starting address to your
shared library.
The following example shows how to use the
-check_registry
option:
% ld -shared -no_archive -check_registry \ /usr/shlib/so_locations \ libspecial_math.so special_math.o -lc
If the shared library you create will be used by other programmers
on your system, use the
-update_registry
option.
This option causes the
ld
linker to search the file you
specify to determine what starting addresses are assigned to shared libraries.
The linker then assigns an unused starting address to your shared library.
The linker then adds to the file the information that your shared library
has been assigned that starting address.
Because that information is stored
in the file, the linker can determine that the address is already assigned
when it assigns a starting address to other shared libraries.
If no
-check_registry
or
-update_registry
option is specified when building a shared library, the linker
defaults to the
-update_registry
option and the
./so_locations
file.
The following list describes the procedure you follow to use the
-update_registry
option with the system's
/usr/shlib/so_locations
file:
Copy the system's
so_locations
file to
your local area:
% cp /usr/shlib/so_locations .
Give yourself write access to the file:
% chmod +w so_locations
Create the shared library and use the
-update_registry
option:
% ld -shared -no_archive -update_registry \ ./so_locations -o libspecial_math.so \ special_math.o -lc
Move the
so_locations
file back to the
/usr/shlib
directory:
% mv /home/smith/so_locations /usr/shlib/so_locations
You
must have write privileges to the
/usr/shlib
directory
to move the
so_locations
file into it.
If you cannot write
to the directory, ask your system administrator to move the file.
On an
ULTRIX system, you use semaphores through the
atomic_op
call.
This call allows you to test and set a user-space address that you
specify.
The DIGITAL UNIX system contains the
atomic_op
call;
however, the system also includes library routines that perform semaphore
operations.
Modify your source code to use the DIGITAL UNIX library routines rather than
the
atomic_op
system call.
The library routines are more
portable than the
atomic_op
system call, which might not
be included in all DIGITAL UNIX systems.
The library routines are also more
powerful than the
atomic_op
system call.
The DIGITAL UNIX library routines are as follows:
For more information about these routines, see
msem_init
(3),
msem_lock
(3),
msem_unlock
(3),
and
msem_remove
(3).
On both the ULTRIX and UWS and the DIGITAL UNIX systems, the number of open file descriptors a process can use is configurable. By default, the number for DIGITAL UNIX systems is 4096; on ULTRIX systems the default is 64. Your system administrator configures the number of open file descriptors. For information about configuring this number, see the System Administration manual.
Because the system administrator can configure the maximum number of open file descriptors your processes can use, you might want to modify your program before you recompile it on a DIGITAL UNIX system. The following list describes the changes needed:
Use the
getdtablesize
call to determine
the maximum number of open file descriptors configured on the system.
The following example shows a call to
getdtablesize
to get the maximum number of open file descriptors:
int maxfds; maxfds = getdtablesize():
Use the
maxfds
variable in other calls, such as the
select
call, that
require you to pass the number of open file descriptors of interest.
For
more information, see
getdtablesize
(2).
Use a short integer or longer data type to store file descriptors.
On ULTRIX systems, you might have used a character data type to store file descriptors. Because file descriptor values on DIGITAL UNIX systems can be greater than 128, you must use at least a short integer to store file descriptors.
Use the
fd_set
data type and its associated
macros as defined in the
/usr/include/sys/types.h
file
to declare parameters to the
select
call.
Using the
fd_set
data type ensures that the parameters
are large enough to accommodate up to 4096 file descriptors.
The
fd_set
data type is large enough for 64 file descriptors in ULTRIX.
For more information, see
select
(2).