Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: fc77657032
Fetching contributors…

Cannot retrieve contributors at this time

488 lines (386 sloc) 19.137 kb
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
#
Mapfiles and versioning in ON
=============================
1.0 Objective of this README
This README describes the engineering practices of creating and updating
visible library interfaces. It describes various kinds of actions that
typically occur as libraries are evolved, and shows how interface
specifications are affected or updated in accordance. It tells you what
you must do as a shared library developer if you:
1. Make interface additions to an existing library
- add a Public interface
- add a Private interface
2. Update an interface in an existing library
- remove an existing interface
- promote a Private interface to Public
- scope a Private interface to local
- move an interface from one library to another
- copy interfaces which are part of the standard to a new or
existing library
3. Introduce a new library
- source directory hierarchy
- creation of the "mapfile-vers" file
- Makefiles
4. Make an entire library obsolete before end-of-life
- introduce SUNWobsolete to the "mapfile-vers" file
-------------------------------------------------------------------------------
2.0 What's a mapfile?
Mapfiles are used to tell the link-editor ("ld") all sorts of things about
how to generate an executable file or a shared object from a collection of
relocatable objects, such as generated by a compiler. For all the gory
details, see the Solaris Linker and Libraries Guide, which can be found
under http://docs.sun.com.
There are two versions of the mapfile language accepted by the link-editor.
Version 1 derives from AT&T System V Release 4 Unix. Version 2 is a newer
syntax specific to Solaris. All mapfiles in the OSnet (ON consolidation) are
required to use version 2 syntax. Note that every mapfile using version 2
syntax must start with the line:
$mapfile_version 2
Here, we are only concerned with specifying externally-visible interfaces
for shared libraries (shared objects) and with specifying their versions
for ABI (Application Binary Interface) purposes. For these purposes, we
only need to deal with a subset of the mapfile language.
There should be a "mapfile-vers" file associated with every shared library
and it should reside in the common source directory for that library, most
often in a "common" directory. This is the usual layout of a library's
top-level directory (usr/src/lib/libwombat):
Makefile amd64/ i386/ sparcv9/
Makefile.com common/ sparc/
The "common" directory contains the source files and other common files
for the library:
bat.c libwombat_impl.h mapfile-vers wom.c
libwombat.h llib-lwombat util.c wombat.c
The mapfile's name is, by convention, "mapfile-vers" because it is used
for only two purposes: to specify externally-visible interface names while
suppressing visibility of all other names, and to specify their respective
unique version names.
-------------------------------------------------------------------------------
3.0 Contents of mapfile-vers
The structure of mapfile-vers is best explained by an example
(the license notification and copyright notice is omitted here
for brevity):
$mapfile_version 2
SYMBOL_VERSION SUNW_1.2 { # update to libwombat, Solaris 10
global:
wb_readv;
wb_stat;
wb_writev;
} SUNW_1.1;
SYMBOL_VERSION SUNW_1.1 { # first release of libwombat, Solaris 9
global:
wb_read;
wb_write;
};
SYMBOL_VERSION SUNWprivate { # private libwombat symbols
global:
wb_add;
wb_delete;
wb_search;
local:
*;
};
The SUNW_1.* names are the Public version names for the library.
There should be at most one version name for each release of Solaris,
with the minor number incremented by one over the previous version.
If no update to the Public-visible names in the library is made
in a given Solaris release, no new version name should be generated
for that release. If multiple updates are made to the library at
different points in the development of a given release of Solaris,
only one version should be used for the entire release.
So, for example, if an update to libwombat is made in Solaris 11,
you would add "SUNW_1.3" at the start of the mapfile:
SYMBOL_VERSION SUNW_1.3 { # update to libwombat, Solaris 11
global:
wb_lseek;
} SUNW_1.2;
Each version must inherit all symbols from its preceding version,
specified at the ending "}" for each version. SUNW_1.1 does not
inherit any symbols. SUNWprivate, if present, stands alone.
The two lines in SUNWprivate:
local:
*;
ensure that no symbols other than those listed in the mapfile are
visible to clients of the library. If there is no SUNWprivate,
these two lines should appear in SUNW_1.1.
For maintainability, the list of names in each version block should
be sorted in dictionary order (sort -d). Please comply.
The version 2 mapfile language supports a simple mechanism for conditional
input, in which lines in the mapfile apply only to a specific platform or
ELFCLASS (32/64-bit). This mechanism works very much like the #if/#endif
feature of the C preprocessor. For instance, the following mapfile declares
a version SUNW_1.1 that always exports a symbol foo, and also exports
the symbol bar on 32-bit sparc platforms:
$mapfile_version
SYMBOL_VERSION SUNW_1.1 {
foo;
$if _sparc && _ELF32
bar;
$endif
};
Conditional input can be used if there are ISA-specific library interfaces
not common to all instances of the library. It is the preferred method for
expressing platform specific items, as long as the differences are simple
(which is almost always the case). For example, see libproc, or, if you
are masochistic, libc or libnsl.
In addition to conditional input, there is a second heavier weight mechanism
for expressing ISA-specific differences. In addition to the common mapfile:
common/mapfile-vers
some libraries may have ISA-specific supplemental mapfiles, one in each
of the ISA directories:
amd64/mapfile-vers
i386/mapfile-vers
sparc/mapfile-vers
sparcv9/mapfile-vers
The ISA-specific mapfiles look like the common mapfile, except that only
the ISA-specific names appear. The version names are the same as those
in the common mapfile, but only non-empty version instances are present
and no inheritance specification is present. The link-editor reads the
information from the common and ISA-specific mapfiles and merges them
in memory into a single description used to create the resulting object.
ISA-specific mapfiles were used with the version 1 mapfile language, which
lacked conditional input. Their use is rare now, as conditional input is
generally preferred. However, it is important to use conditional input
carefully, or the resulting mapfile can be extremly difficult to read.
-------------------------------------------------------------------------------
4.0 Making interface additions to an existing library
4.1 Adding a Public interface
The first engineer to update the existing mapfile-vers file in a release needs
to identify the current highest version name and properly increment the minor
version number by 1 to be the new version name. If this is the first Public
interface in the shared object, a new SUNW_1.1 version name must be introduced.
The major revision number is incremented whenever an incompatible change is
made to an interface. This could be the case if an API changes so dramatically
as to invalidate dependencies. This rarely occurs in practice. It also
requires changing the suffix of the shared object from, say, .so.1 to .so.2
and introducing code to continue to ship the .so.1 version of the library.
The minor revision number is incremented whenever one or more new interfaces
is added to a library. Note that the minor number is not incremented on every
putback that makes an interface addition to the library. Rather, it is
incremented at most once per (external to Sun) release of the library.
4.2 Adding a Private interface
Private interfaces are the non-ABI interfaces of the library. Unlike
introducing a Public interface, a new entry is simply added to the
SUNWprivate version. No minor number increment is necessary.
If this interface happens to be the first Private interface introduced
into the library, the SUNWprivate version must be created (no major.minor
version numbers). It inherits nothing and nothing inherits from it.
If the library already has Private interfaces, they may have numbered version
names like SUNWprivate_m.n (due to errors of the past). If so, just use the
highest numbered private version name to version the new interface. There
is no need to introduce a new private version name. Be careful not to use
a lower numbered private version name; doing so can cause runtime errors
(as opposed to load time errors) when running an application with older
versions of the library.
There are libraries in the OSnet consolidation that contain only private
interfaces. In such libraries, the SUNWprivate_m.n may be incremented
to ensure that the programs that depend on them are built and delivered as a
integrated unit. A notable example of this is libld.so (usr/src/cmd/sgs/libld),
which contains the implementation of the link-editor, the public interface to
which is provided by the ld command. When making a modification to the interface
of such a library, you should follow the convention already in place.
4.3 Adding new public interfaces in an update release
Adding new public interfaces in an update release requires careful
coordination with the next marketing release currently under development.
Multiple updates ship during the period before the next marketing release
ships, and since it is generally impossible to know the full set of new
interfaces in the next marketing release until late in its development
(after multiple updates have shipped) it must be assumed that not all
interfaces added to the next marketing release will be added to an update.
Consequently, the new version number for an update cannot be a minor
increment, but must be a micro increment. For example, if Release N
has version number SUNW_1.3 and Release N+1 will have SUNW_1.4, then
interfaces added to an update of Release N must have micro numbers such
as SUNW_1.3.1, SUNW_1.3.2, etc. (note that the micro number is not
directly tied to the update number: SUNW_1.3.1 may appear in Update 2).
The micro versions form an inheritance chain that is inserted between
two successive minor versions. For example, the mapfile-vers file for
minor release "N+1" to reflect its inclusion of micro releases will
look like the following:
$mapfile_version 2
SYMBOL_VERSION SUNW_1.4 { # release N+1
global:
...
} SUNW_1.3.2;
SYMBOL_VERSION SUNW_1.3.2 { # micro release 2 (e.g., release NU3)
global:
...
} SUNW_1.3.1;
SYMBOL_VERSION SUNW_1.3.1 { # micro release 1 (e.g., release NU2)
global:
...
} SUNW_1.3;
SYMBOL_VERSION SUNW_1.3 { # release N
global:
...
} SUNW_1.2;
SYMBOL_VERSION SUNW_1.2 { # release N-1
global:
...
} SUNW_1.1;
SYMBOL_VERSION SUNW_1.1 { # first release
global:
...
};
SYMBOL_VERSION SUNW_private { # same in all releases
global:
...
local:
*;
};
The corresponding update/patch mapfile-vers file will be identical
except for the exclusion of SUNW_1.4.
Those interfaces which are only present in Release N+1 are always put
into the next minor version set, SUNW_1.4.
Thus when adding a new public interface to an update, both the mapfiles
of the update release and next marketing release must be modified to be
consistent. The update versions should not be added to the marketing
release until the putback to the update release has occurred, to avoid
timing problems with the update releases (it's all too easy for projects
to slip out of updates, or to change ordering).
-------------------------------------------------------------------------------
5.0 How to update an interface in an existing library
5.1 Removing an existing interface
5.1.1 Moving a Public interface
No Public interfaces should ever be removed from any mapfile.
To move an interface from one library to (say) libc, the code has to be
deleted from the library and added to libc, then the mapfile for the
library has to have the interface's entry changed from:
getfoobar;
to:
getfoobar { TYPE = FUNCTION; FILTER = libc.so.1 };
See, for example, libnsl's common/mapfile-vers file.
Follow the rules for adding a new interface for the necessary changes
to libc's mapfile to accommodate the moved interface. In particular,
the new interface must be added to the current highest libc version.
To move an entire library into libc, look at what has already been done
for libthread, libaio, and librt.
5.1.2 Removing a Private interface
Deletion of Private interfaces is allowed, but caution should be taken;
it should first be established that the interface is not being used.
To remove a Private interface, simply delete the corresponding entry
for that symbol from the mapfile's SUNWprivate section.
Do not forget to delete these Public or Private interfaces from the library's
header files as well as from the code that implements the interfaces.
5.2 Promoting a Private interface to Public
This is similar to what's done when adding a Public interface. Promoting an
existing Private interface to a Public one only requires a change to the
existing interface definition. Private interfaces have the symbol version name
"SUNWprivate" associated with them. To make the interface a Public one, the
interface must be put into a set associated with the current Public release
level of the library.
As an example, if we were modifying libwombat.so.1 and its version in the
last release of Solaris was SUNW_1.23, any new ABI introduced in the next
release would be put into a version called SUNW_1.24. Therefore, whether
you wish to promote an existing Private interface to Public, or to introduce
a new Public interface, this (next successive minor numbered version level)
would be the version that it would be associated with.
5.3 Scoping a Private interface local
Any interfaces not present in the mapfile-vers file will be scoped local
due to the presence of the
local:
*;
lines discussed earlier. This ensures that such interfaces will not be visible
outside the library. To move an interface from Private to local scope, simply
remove the Private interface from the mapfile-vers file and the header file
to prevent it from being exported. This may require moving the Private
interface into a library-private header file. Scope reduction of Public
interfaces is not allowed without specific ARC review and approval.
For the interface to be used in more than one file within the library, it
should be in a header file that can be included by each file in the library
that uses the interface. For example:
#include "libprivate.h"
5.4 How to copy interfaces which are part of a standard to a new or existing
library
SYSVABI and SISCD are reserved version names for interfaces listed in the
System V Interface Definition and the Sparc Compliance Definition. Avoid using
these version names when copying the implementation of standard interfaces to
another library. Instead, use SUNW_1.1 for a new library, and SUNW_m.n for
an existing library (where m.n is the next release version; i.e., if the
last version was SUNW_1.18, then you should version the interfaces with
SUNW_1.19).
-------------------------------------------------------------------------------
6.0 Introducing a new library
6.1 Directories
The normal discipline for introducing a new library in OS/Net is to create a
new subdirectory of /usr/src/lib. The interface definition discipline is to
create a common/mapfile-vers file for the new library. If we were introducing
a new foo library, libfoo, we'd create /usr/src/lib/libfoo containing:
Makefile amd64/ i386/ sparcv9/
Makefile.com common/ sparc/
The common subdirectory would contain the normal source files plus the
mapfile-vers file. See usr/src/lib/README.Makefiles for directions on
how to organize the Makefiles.
6.2 The mapfile
The new common/mapfile-vers file would contain:
$mapfile_version 2
SYMBOL_VERSION SUNW_1.1 { # first release of libfoo
global:
...
};
SYMBOL_VERSION SUNWprivate {
global:
...
local:
*;
};
If there are no Public interfaces, the SUNW_1.1 section would be omitted.
If there are no Private interfaces, the SUNWprivate section would be
omitted and the two lines:
local:
*;
would be moved into SUNW_1.1
To decide which interfaces are Public (part of the ABI) and which are Private
(unstable interfaces not intended to be used by third party applications or
unbundled products), the heuristic which works to a first approximation is
that if it has a man page then it's Public. Also, it is really the ARC case
for the new interfaces that prescribes which interfaces are Public and
which are not (hence, which interfaces have man pages and which do not).
For maintainability, the list of names in each version block should
be sorted in dictionary order (sort -d). Please comply.
-------------------------------------------------------------------------------
7.0 Make an entire library obsolete
7.1 Introduce SUNWobsolete version
Use this version name not for specific interfaces but for marking an entire
library as obsolete. The existing public/private version names are left
unchanged, but a new SUNWobsolete version is created with no symbols in it.
This becomes a tag by which the obsolescence of the library can be recognized.
There is no numbering of this version name.
$mapfile_version 2
SYMBOL_VERSION SUNWobsolete {
global:
SUNWobsolete; # This is the only way to do it.
} SUNW_1.2;
SYMBOL_VERSION SUNW_1.2 {
...
-------------------------------------------------------------------------------
8.0 Documentation
For further information, please refer to the following documents:
"Solaris Linker and Libraries Guide", http://docs.sun.com
/shared/ON/general_docs/scoping-rules.fm.ps
For information on the now-obsolete spec files, used in Solaris releases
7 through 10, see:
/shared/ON/general_docs/README.spec
/shared/ON/general_docs/libspec-rules.ps
/shared/ON/general_docs/spectrans/*
Jump to Line
Something went wrong with that request. Please try again.