2N/A#
2N/A# CDDL HEADER START
2N/A#
2N/A# The contents of this file are subject to the terms of the
2N/A# Common Development and Distribution License (the "License").
2N/A# You may not use this file except in compliance with the License.
2N/A#
2N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A# or http://www.opensolaris.org/os/licensing.
2N/A# See the License for the specific language governing permissions
2N/A# and limitations under the License.
2N/A#
2N/A# When distributing Covered Code, include this CDDL HEADER in each
2N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A# If applicable, add the following below this CDDL HEADER, with the
2N/A# fields enclosed by brackets "[]" replaced with your own identifying
2N/A# information: Portions Copyright [yyyy] [name of copyright owner]
2N/A#
2N/A# CDDL HEADER END
2N/A#
2N/A#
2N/A# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A#
2N/A
2N/AMapfiles and versioning in ON
2N/A=============================
2N/A
2N/A1.0 Objective of this README
2N/A
2N/AThis README describes the engineering practices of creating and updating
2N/Avisible library interfaces. It describes various kinds of actions that
2N/Atypically occur as libraries are evolved, and shows how interface
2N/Aspecifications are affected or updated in accordance. It tells you what
2N/Ayou must do as a shared library developer if you:
2N/A
2N/A 1. Make interface additions to an existing library
2N/A - add a Public interface
2N/A - add a Private interface
2N/A 2. Update an interface in an existing library
2N/A - remove an existing interface
2N/A - promote a Private interface to Public
2N/A - scope a Private interface to local
2N/A - move an interface from one library to another
2N/A - copy interfaces which are part of the standard to a new or
2N/A existing library
2N/A 3. Introduce a new library
2N/A - source directory hierarchy
2N/A - creation of the "mapfile-vers" file
2N/A - Makefiles
2N/A 4. Need to specify the mapfile information that allows a library
2N/A to be buildable as a stub object:
2N/A - enable the stub object feature
2N/A - specify ASSERT information for data symbols
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A2.0 What's a mapfile?
2N/A
2N/AMapfiles are used to tell the link-editor ("ld") all sorts of things about
2N/Ahow to generate an executable file or a shared object from a collection of
2N/Arelocatable objects, such as generated by a compiler. For all the gory
2N/Adetails, see the Solaris Linker and Libraries Guide, which can be found
2N/Aunder http://docs.sun.com.
2N/A
2N/AThere are two versions of the mapfile language accepted by the link-editor.
2N/AVersion 1 derives from AT&T System V Release 4 Unix. Version 2 is a newer
2N/Asyntax specific to Solaris. All mapfiles in the OSnet (ON consolidation) are
2N/Arequired to use version 2 syntax. Note that every mapfile using version 2
2N/Asyntax must start with the line:
2N/A
2N/A $mapfile_version 2
2N/A
2N/AHere, we are only concerned with specifying externally-visible interfaces
2N/Afor shared libraries (shared objects) and with specifying their versions
2N/Afor ABI (Application Binary Interface) purposes. For these purposes, we
2N/Aonly need to deal with a subset of the mapfile language.
2N/A
2N/AThere should be a "mapfile-vers" file associated with every shared library
2N/Aand it should reside in the common source directory for that library, most
2N/Aoften in a "common" directory. This is the usual layout of a library's
2N/Atop-level directory (usr/src/lib/libwombat):
2N/A Makefile amd64/ i386/ sparcv9/
2N/A Makefile.com common/ sparc/
2N/A
2N/AThe "common" directory contains the source files and other common files
2N/Afor the library:
2N/A bat.c libwombat_impl.h mapfile-vers wom.c
2N/A libwombat.h llib-lwombat util.c wombat.c
2N/A
2N/AThe mapfile's name is, by convention, "mapfile-vers" because it is used
2N/Afor only two purposes: to specify externally-visible interface names while
2N/Asuppressing visibility of all other names, and to specify their respective
2N/Aunique version names.
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A3.0 Contents of mapfile-vers
2N/A
2N/AThe structure of mapfile-vers is best explained by an example
2N/A(the license notification and copyright notice is omitted here
2N/Afor brevity):
2N/A
2N/A$mapfile_version 2
2N/A
2N/ASTUB_OBJECT;
2N/A
2N/ASYMBOL_VERSION SUNWpublic { # public libwombat symbols
2N/A global:
2N/A wb_read;
2N/A wb_readv;
2N/A wb_stat;
2N/A wb_write;
2N/A wb_writev;
2N/A};
2N/A
2N/ASYMBOL_VERSION SUNWprivate { # private libwombat symbols
2N/A global:
2N/A wb_add;
2N/A wb_delete;
2N/A wb_search;
2N/A
2N/A local:
2N/A *;
2N/A};
2N/A
2N/AThe STUB_OBJECT directive specifies that this library can be
2N/Abuilt as a stub object as well as a normal object. STUB_OBJECT
2N/Aenables additional tests and sanity checking within the link-editor
2N/A(ld) to ensure that the stub object will be a faithful representation
2N/Aof the object for linking purposes. All libraries in the OSnet
2N/A(ON consolidation) must be buildable both ways, so the use of
2N/ASTUB_OBJECT is not optional for ON mapfiles.
2N/A
2N/AAll new public symbols are added to version SUNWpublic.
2N/AAll new private symbols are added to version SUNWprivate.
2N/A
2N/AExisting Solaris objects may have public versions with numbered
2N/Anames (e.g. SUNW_1.1). These versions date from older versions of
2N/Athe OS, which used a different set of versioning rules. All such
2N/Aversions must be preserved to ensure backward compatibility.
2N/AIn this case, the SUNWpublic version must inherit all symbols
2N/Afrom the highest numbered SUNW_x.y version. The libwombat mapfile
2N/Amight then look like:
2N/A
2N/A$mapfile_version 2
2N/A
2N/ASTUB_OBJECT;
2N/A
2N/ASYMBOL_VERSION SUNWpublic { # public libwombat symbols
2N/A global:
2N/A wb_readv;
2N/A wb_stat;
2N/A wb_writev;
2N/A} SUNW_1.1;
2N/A
2N/ASYMBOL_VERSION SUNW_1.1 { # first release of libwombat, Solaris 9
2N/A global:
2N/A wb_read;
2N/A wb_write;
2N/A};
2N/A
2N/ASYMBOL_VERSION SUNWprivate { # private libwombat symbols
2N/A global:
2N/A wb_add;
2N/A wb_delete;
2N/A wb_search;
2N/A
2N/A local:
2N/A *;
2N/A};
2N/A
2N/AThe two lines in SUNWprivate:
2N/A local:
2N/A *;
2N/Aensure that no symbols other than those listed in the mapfile are
2N/Avisible to clients of the library. If there is no SUNWprivate,
2N/Athese two lines should appear in SUNWpublic.
2N/A
2N/AFor maintainability, the list of names in each version block should
2N/Abe sorted in dictionary order (sort -d). Please comply.
2N/A
2N/AThe version 2 mapfile language supports a simple mechanism for conditional
2N/Ainput, in which lines in the mapfile apply only to a specific platform or
2N/AELFCLASS (32/64-bit). This mechanism works very much like the #if/#endif
2N/Afeature of the C preprocessor. For instance, the following mapfile declares
2N/Aa version SUNWpublic that always exports a symbol foo, and also exports
2N/Athe symbol bar on 32-bit sparc platforms:
2N/A
2N/A$mapfile_version
2N/ASYMBOL_VERSION SUNWpublic {
2N/A foo;
2N/A$if _sparc && _ELF32
2N/A bar;
2N/A$endif
2N/A};
2N/A
2N/AConditional input can be used if there are ISA-specific library interfaces
2N/Anot common to all instances of the library. It is the preferred method for
2N/Aexpressing platform specific items, as long as the differences are simple
2N/A(which is almost always the case). For example, see libproc, or, if you
2N/Aare masochistic, libc or libnsl.
2N/A
2N/AIn addition to conditional input, there is a second heavier weight mechanism
2N/Afor expressing ISA-specific differences. In addition to the common mapfile:
2N/A common/mapfile-vers
2N/Asome libraries may have ISA-specific supplemental mapfiles, one in each
2N/Aof the ISA directories:
2N/A amd64/mapfile-vers
2N/A i386/mapfile-vers
2N/A sparc/mapfile-vers
2N/A sparcv9/mapfile-vers
2N/AThe ISA-specific mapfiles look like the common mapfile, except that only
2N/Athe ISA-specific names appear. The version names are the same as those
2N/Ain the common mapfile, but only non-empty version instances are present
2N/Aand no inheritance specification is present. The link-editor reads the
2N/Ainformation from the common and ISA-specific mapfiles and merges them
2N/Ain memory into a single description used to create the resulting object.
2N/A
2N/AISA-specific mapfiles were used with the version 1 mapfile language, which
2N/Alacked conditional input. Their use is rare now, as conditional input is
2N/Agenerally preferred. However, it is important to use conditional input
2N/Acarefully, or the resulting mapfile can be extremely difficult to read.
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A4.0 Making interface additions to an existing library
2N/A
2N/A4.1 Adding a Public interface
2N/A
2N/AAll new public symbols are assigned to the SUNWpublic version. If the
2N/Aexisting mapfile-vers does not have this version, the engineer adding
2N/Athe new symbol must add it. If the library contains any existing public
2N/Aversions of the form SUNW_x.y, then the new SUNWpublic version inherits
2N/Afrom the highest such SUNW_ version. If there are no SUNW_x.y versions, then
2N/Athe SUNWpublic versions stands alone, and does not inherit.
2N/A
2N/AIncompatible changes to an existing interface within a given library are not
2N/Aallowed. If an API changes so dramatically as to invalidate dependencies, it
2N/Abecomes necessary to change the suffix of the shared object from, say, .so.1
2N/Ato .so.2 and to introduce code to continue to ship the .so.1 version of the
2N/Alibrary. This rarely occurs in practice, and is discouraged. A better solution
2N/Ais to introduce the new functionality under a new name, and retain the old
2N/Ainterface with the old behavior for the benefit of existing applications.
2N/A
2N/A4.2 Adding a Private interface
2N/A
2N/APrivate interfaces are the non-ABI interfaces of the library, and are added
2N/Ato the SUNWprivate version. If this interface happens to be the first
2N/APrivate interface introduced into the library, the SUNWprivate version must
2N/Abe created. It inherits nothing and nothing inherits from it.
2N/A
2N/AIf the library already has Private interfaces, they may have numbered version
2N/Anames like SUNWprivate_m.n (due to errors of the past). If so, just use the
2N/Ahighest numbered private version name to version the new interface. There
2N/Ais no need to introduce a new private version name. Be careful not to use
2N/Aa lower numbered private version name; doing so can cause runtime errors
2N/A(as opposed to load time errors) when running an application with older
2N/Aversions of the library.
2N/A
2N/AThere are libraries in the OSnet consolidation that contain only private
2N/Ainterfaces. In such libraries, the SUNWprivate_m.n may be incremented
2N/Ato ensure that the programs that depend on them are built and delivered as a
2N/Aintegrated unit. A notable example of this is libld.so (usr/src/cmd/sgs/libld),
2N/Awhich contains the implementation of the link-editor, the public interface to
2N/Awhich is provided by the ld command. When making a modification to the interface
2N/Aof such a library, you should follow the convention already in place.
2N/A
2N/A4.3 Adding new public interfaces in an update release
2N/A
2N/APublic symbols must appear in the same version in all Solaris releases.
2N/ATherefore, when porting a new public interface to an update release,
2N/Ayou must ensure that the symbol is assigned to the same version as
2N/Ain the release you are porting from. If the library in the update
2N/Arelease already has this version, you simply add the new symbol to it.
2N/AIf the version does not already exist, you must create it, along with
2N/Aany missing versions it may inherit from, and then assign the new interface
2N/Ato the newly created version.
2N/A
2N/AWhen adding a new public interface to an update, both the mapfiles of the
2N/Aupdate release and next marketing release must be consistent. This means
2N/Athat all new functionality must be first integrated in the marketing gate,
2N/Aand then ported to the update afterwards.
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A5.0 How to update an interface in an existing library
2N/A
2N/A5.1 Removing an existing interface
2N/A
2N/A5.1.1 Moving a Public interface
2N/A
2N/ANo Public interfaces should ever be removed from any mapfile.
2N/A
2N/ATo move an interface from one library to (say) libc, the code has to be
2N/Adeleted from the library and added to libc, then the mapfile for the
2N/Alibrary has to have the interface's entry changed from:
2N/A getfoobar;
2N/Ato:
2N/A getfoobar { TYPE = FUNCTION; FILTER = libc.so.1 };
2N/ASee, for example, libnsl's common/mapfile-vers file.
2N/A
2N/AFollow the rules for adding a new interface for the necessary changes
2N/Ato libc's mapfile to accommodate the moved interface. In particular,
2N/Athe new interface must be added to SUNWpublic in the libc mapfile-vers.
2N/A
2N/ATo move an entire library into libc, look at what has already been done
2N/Afor libthread, libaio, and librt.
2N/A
2N/A5.1.2 Removing a Private interface
2N/A
2N/ADeletion of Private interfaces is allowed, but caution should be taken;
2N/Ait should first be established that the interface is not being used.
2N/ATo remove a Private interface, simply delete the corresponding entry
2N/Afor that symbol from the mapfile's SUNWprivate section.
2N/A
2N/ADo not forget to delete these Public or Private interfaces from the library's
2N/Aheader files as well as from the code that implements the interfaces.
2N/A
2N/A5.2 Promoting a Private interface to Public
2N/A
2N/AThis is similar to what's done when adding a Public interface. Promoting an
2N/Aexisting Private interface to a Public one only requires a change to the
2N/Aexisting interface definition. Private interfaces have the symbol version name
2N/A"SUNWprivate" associated with them. To make the interface a Public one, the
2N/Ainterface must be moved to the SUNWpublic version for the library.
2N/A
2N/A5.3 Scoping a Private interface local
2N/A
2N/AAny interfaces not present in the mapfile-vers file will be scoped local
2N/Adue to the presence of the
2N/A local:
2N/A *;
2N/Alines discussed earlier. This ensures that such interfaces will not be visible
2N/Aoutside the library. To move an interface from Private to local scope, simply
2N/Aremove the Private interface from the mapfile-vers file and the header file
2N/Ato prevent it from being exported. This may require moving the Private
2N/Ainterface into a library-private header file. Scope reduction of Public
2N/Ainterfaces is not allowed without specific ARC review and approval.
2N/A
2N/AFor the interface to be used in more than one file within the library, it
2N/Ashould be in a header file that can be included by each file in the library
2N/Athat uses the interface. For example:
2N/A
2N/A #include "libprivate.h"
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A6.0 Introducing a new library
2N/A
2N/A6.1 Directories
2N/A
2N/AThe normal discipline for introducing a new library in OS/Net is to create a
2N/Anew subdirectory of /usr/src/lib. The interface definition discipline is to
2N/Acreate a common/mapfile-vers file for the new library. If we were introducing
2N/Aa new foo library, libfoo, we'd create /usr/src/lib/libfoo containing:
2N/A Makefile amd64/ i386/ sparcv9/
2N/A Makefile.com common/ sparc/
2N/AThe common subdirectory would contain the normal source files plus the
2N/Amapfile-vers file. See usr/src/lib/README.Makefiles for directions on
2N/Ahow to organize the Makefiles.
2N/A
2N/A6.2 The mapfile
2N/A
2N/AThe new common/mapfile-vers file would contain:
2N/A
2N/A$mapfile_version 2
2N/A
2N/ASTUB_OBJECT;
2N/A
2N/ASYMBOL_VERSION SUNWpublic {
2N/A global:
2N/A ...
2N/A};
2N/A
2N/ASYMBOL_VERSION SUNWprivate {
2N/A global:
2N/A ...
2N/A
2N/A local:
2N/A *;
2N/A};
2N/A
2N/AIf there are no Public interfaces, the SUNWpublic section would be omitted.
2N/AIf there are no Private interfaces, the SUNWprivate section would be
2N/Aomitted and the two lines:
2N/A local:
2N/A *;
2N/Awould be moved into SUNWpublic.
2N/A
2N/ATo decide which interfaces are Public (part of the ABI) and which are Private
2N/A(unstable interfaces not intended to be used by third party applications or
2N/Aunbundled products), the heuristic which works to a first approximation is
2N/Athat if it has a man page then it's Public. Also, it is really the ARC case
2N/Afor the new interfaces that prescribes which interfaces are Public and
2N/Awhich are not (hence, which interfaces have man pages and which do not).
2N/A
2N/AFor maintainability, the list of names in each version block should
2N/Abe sorted in dictionary order (sort -d). Please comply.
2N/A
2N/A-------------------------------------------------------------------------------
2N/A8.0 Specify Stub Object Details
2N/A
2N/AStub objects are shared objects, built entirely from their mapfiles,
2N/Athat are, for the purposes of linking, identical to the actual
2N/Ashared objects that would result if you built them in the usual
2N/Amanner. Unlike the real objects:
2N/A
2N/A - Stub objects can be built extremely quickly. Stub objects
2N/A for all of usr/src/lib and usr/src/ucblib can be built in
2N/A a couple of minutes on a modest desktop system.
2N/A
2N/A - Stub objects are self contained, and are built without requiring
2N/A input objects or the existence of any dependency shared objects.
2N/A Therefore, all stub objects for the OSnet can be built in parallel,
2N/A without ordering or synchronization.
2N/A
2N/A - Real objects can be built using stub objects to stand in for their
2N/A real dependencies. Using stub objects in this way, an object,
2N/A and the other objects it requires, can be built in parallel, in
2N/A any arbitrary order.
2N/A
2N/AStub objects are a fundamental part of how we build ON, so every library
2N/Ain the OSnet (ON consolidation) must be buildable as a stub object:
2N/A
2N/A 1) Before any objects are built in an ON nightly build, a
2N/A stub proto area is established, referenced as $(STUBROOT) in
2N/A our makefiles.
2N/A
2N/A 2) A stub object for every library is built and installed under
2N/A $(STUBROOT).
2N/A
2N/A 3) All libraries and executables are linked to the objects found
2N/A under $(STUBROOT).
2N/A
2N/AThis approach allows every library and command in Solaris to be built
2N/Ain parallel, and (with a small number of exceptions), without any
2N/Aexplicit ordering or serialization between them.
2N/A
2N/ATo enable the possibility of building a library as a stub object, the
2N/Alibrary mapfile must specify the STUB_OBJECT directive.
2N/A
2N/AIf your library exports only function symbols, then the use of STUB_OBJECT
2N/Ais all that is required, and you can skip the remainder of this section.
2N/A
2N/AThere are many reasons why shared objects should not export global data
2N/Adirectly, and we have long discouraged it. New libraries should never
2N/Ado this. It is usually easy enough to expose global data via a functional
2N/Ainterface. For instance, Solaris usually exposes the errno global variable
2N/Ato via the following macro definition found in <errno.h>
2N/A
2N/A extern int *___errno();
2N/A #define errno (*(___errno()))
2N/A
2N/ASo the prohibition on global data symbols is not the same thing as
2N/Aprohibiting global data --- we simply recommend that it be exposed
2N/Avia a functional interface.
2N/A
2N/AGood advice aside, there are two important cases in which you will
2N/Aneed to cope with global data symbols in ON mapfiles:
2N/A
2N/A 1) Existing libraries with historical interfaces that must be maintained
2N/A
2N/A 2) Third party code, which is out of our control and not subject to
2N/A our rules.
2N/A
2N/AData symbols exported by shared objects built with the STUB_OBJECT
2N/Amapfile directive are required to provide mapfile symbol ASSERT directives
2N/Afor each data symbol, for the following attributes:
2N/A
2N/A - That the symbol is a data symbol.
2N/A - The size of the symbol, in bytes.
2N/A - The symbol binding, if it is not GLOBAL.
2N/A - If the symbol resides in a bss (NOBITS) section in the object.
2N/A - If the symbol is an alternative name (ALIAS) for another symbol.
2N/A
2N/AThese ASSERT directives serve 2 related purposes:
2N/A
2N/A 1) The generation of the stub object is done without access to the symbol
2N/A information usually provided with any input relocatable objects.
2N/A Instead, the ASSERT directives supply the necessary information
2N/A required to generate the correct symbol table entry.
2N/A
2N/A 2) When building the normal non-stub version of the object, the
2N/A attributes of the real object are compared to the ASSERT values,
2N/A and any deviation result in fatal link-time errors.
2N/A
2N/AAs a result, the stub and normal versions of the object are guaranteed
2N/Ato present a completely equivalent linking interface. You can therefore safely
2N/Alink against the stub, and then run against the non-stub.
2N/A
2N/AThe libc mapfile (usr/src/lib/libc/port/mapfile-vers) contains a large
2N/Anumber of historical data symbols, and serves as a good example of how
2N/Ato write these ASSERT directives. The environ data symbol serves as a
2N/Auseful example
2N/A
2N/A
2N/A SYMBOL_VERSION SYSVABI_1.3 {
2N/A ...
2N/A global:
2N/A ...
2N/A environ {
2N/A ASSERT {
2N/A TYPE=data;
2N/A $if __GNUC
2N/A SH_ATTR=nobits;
2N/A $endif
2N/A SIZE=addrsize;
2N/A BINDING=weak;
2N/A };
2N/A };
2N/A ...
2N/A };
2N/A
2N/ANote that it usually suffices to specify TYPE and SIZE --- environ is
2N/Aa bit more complex than the usual case.
2N/A
2N/A TYPE=data
2N/A All data symbols must explicitly assert that they
2N/A are expected to be data symbols.
2N/A
2N/A SIZE
2N/A All data symbols must assert their size, in bytes. This can
2N/A be a decimal, or hexadecimal value. The symbolic name
2N/A 'addrsize' can also be used, to represent a machine word (pointer)
2N/A sized variable. The link-editor automatically substitutes the value
2N/A 4 for 'addrsize' when building 32-bit objects, and 8 for 64-bit objects.
2N/A
2N/A In addition, SIZE values can specify a repeat count, which is
2N/A convenient for describing arrays. All of the following are
2N/A valid SIZE values:
2N/A
2N/A Value Meaning
2N/A ----------------------------------------------------------
2N/A SIZE=4 4 bytes
2N/A SIZE=0x209 521 bytes
2N/A SIZE=addrsize 4 bytes in a 32-bit object,
2N/A 8 bytes in a 64-bit object.
2N/A SIZE=4[4] 16 bytes (4, 4 byte elements)
2N/A SIZE=addrsize[3] 12 bytes in a 32-bit object,
2N/A 24 bytes in a 64-bit object
2N/A ----------------------------------------------------------
2N/A
2N/A BINDING
2N/A Most global symbols have the GLOBAL binding, and the BINDING
2N/A assert attribute need not be specified. However, data with WEAK
2N/A binding must be explicitly declared.
2N/A
2N/A SH_ATTR
2N/A In rare situations, the link-editor will produce different
2N/A results when linking against a shared object with global
2N/A data, depending on whether the data resides in a regular
2N/A section, or a BSS (NOBITS) section. Data that resides in
2N/A BSS must therefore contain an assertion to that effect.
2N/A
2N/A This example with the environ symbol is especially interesting,
2N/A as the native Oracle Studio compilers do not place environ in
2N/A BSS, while gcc does, hence the use of the $if __GNUC to
2N/A conditionalize the SH_ATTR attribute.
2N/A
2N/AAnother complication involves multiple symbols that all reference the
2N/Asame physical data address, often with differing global and weak binding.
2N/AIn order to produce an accurate stub object, the mapfile must include
2N/AALIAS assertions. The lone symbol in libc provides an example of this:
2N/A
2N/A lone { ASSERT { TYPE=data; SIZE=8 } };
2N/A _lone {
2N/A FLAGS = NODYNSORT;
2N/A ASSERT { ALIAS=lone; BINDING=weak };
2N/A };
2N/A
2N/AWhen ALIAS is used, TYPE and SIZE are omitted, as their values are taken
2N/Afrom the source symbol.
2N/A
2N/A
2N/A
2N/A-------------------------------------------------------------------------------
2N/A
2N/A9.0 Documentation
2N/A
2N/AFor further information, please refer to the following documents:
2N/A
2N/A "Solaris Linker and Libraries Guide", the latest version of
2N/A which is available internally from http://linkers.us.oracle.com/
2N/A
2N/A /shared/ON/general_docs/scoping-rules.fm.ps
2N/A
2N/AFor information on the now-obsolete spec files, used in Solaris releases
2N/A7 through 10, see:
2N/A /shared/ON/general_docs/README.spec
2N/A /shared/ON/general_docs/libspec-rules.ps
2N/A /shared/ON/general_docs/spectrans/*