The early days

The Dutch programmers were supposed to make an English translation of some of the outcomes of their math library.
The outcomes were stated in Dutch, and could be een, twee or drie.
In English this is one, two or three.

They understood this could be implemented by a shared library, one of them actually read the Linker manual and came up with the following brilliant program, one2.c:

#include <stdio.h>
#include <stdlib.h>

extern char     *Translate_en[]={"zero","one","two","three"};

int een(){return(1);}
int twee(){return(2);}
int drie(){return(3);}
They compiled the program and made it into an object library:
$ cc one2
$ library/create one2.olb one2.obj
Then they wrote a linker options file with the vectors pointing to the global symbol entries, included the version and the identification, and called it one2_vector.opt.
GSMATCH=LEQUAL,1,0
CASE_SENSITIVE=YES
IDENTIFICATION="one2 1.0"
SYMBOL_VECTOR=(  -
DRIE=PROCEDURE, -
EEN=PROCEDURE, -
TRANSLATE_EN=DATA, -
TWEE=PROCEDURE)
CASE_SENSITIVE=NO
Then they linked and created the shared library, and defined a logical one2shr pointing to it
$ link/share/exe=one2shr.exe one2.olb/lib, one2_vector.opt/opt
$ define one2shr ''f$environment("default")'one2shr.exe 
Then they wrote a program called useone2.c that cleverly used the shared library:
#include <stdio.h>
#include <stdlib.h>

int een();
int twee();
int drie();

extern char *Translate_en[];

main()
{
printf(" een: %s\n",Translate_en[een()]   );
printf("twee: %s\n",Translate_en[twee()] );
printf("drie: %s\n",Translate_en[drie()] );
}
They compiled and linked it to the shared library:
$ cc useone2
$ link/exe=useone2.exe useone2.obj, sys$input:/opt
one2shr/share
$ run useone2
 een: one
twee: two
drie: three
It worked! They were 20% over budget and three weeks late, so everything was hastily put in to production.

Math genius makes a nuisance of himself

A math genius entered the department, and he demanded the library should be able to translate "vier" as well.
The programmers got a budget of 20 minutes, so they decided to only update the shared library, and leave the original program alone. Nobody could imagine anyone wanting to count to more than three, so they decided to write a little test program that would do that but only updated the shared library in production. Shared images can be made upward compatible, just add a new entry at the end of the vectors.

So, they added a function to the shared library, vier, and extended the array with English translations, and called the source file one21.c:

#include <stdio.h>
#include <stdlib.h>

extern char     *Translate_en[]={"zero","one","two","three","four"};

int een(){return(1);}
int twee(){return(2);}
int drie(){return(3);}
int vier(){return(4);}
$ cc one21.c
$ library/create one21.olb one21.obj
Then they wrote a new link options file one21_vector.opt:
GSMATCH=LEQUAL,1,1
CASE_SENSITIVE=YES
IDENTIFICATION="one2 1.1"
SYMBOL_VECTOR=(  -
DRIE=PROCEDURE, -
EEN=PROCEDURE, -
TRANSLATE_EN=DATA, -
TWEE=PROCEDURE, -
VIER=PROCEDURE)
CASE_SENSITIVE=NO
They linked the library,and tested the old program:
 
$ link/share/exe=one2shr_1.exe one21.olb/lib, one21_vector.opt/opt
$ define one2shr ''f$environment("default")'one2shr_1.exe
$ run useone2
 een: one
twee: two
drie: three
That worked! To prove that the library could count to four, they also wrote fourtest.c, and linked it to the new shared library:
#include <stdio.h>
#include <stdlib.h>

int vier();

extern char *Translate_en[];

main()
{
printf(" vier: %s\n",Translate_en[vier()]   );
}
Compiling, linking and runnig proved succesful:
$ cc fourtest
$ link fourtest, sys$input/opt
one2shr/share
$ r fourtest
 vier: four
The shared library was put in to production, and everybody was happy.

After four weeks of meetings with product managers and architects, the one2shr library was introduced as a new standard, to be used by everyone.

OpenSource adept disturbes the peace; case sensitivity

An Open Source advocate entered the department and, as the library was used as an internal standard, he complained that his case sensitive programs wouldn't link against one2shr, as the symbols in one2shr were all uppercase.

Somebody remarked that that could be solved by relinking the shared library and add case sensitive aliases. The source should be compiled with /names=as_is, to produce case sensitive symbolnames. To maintain upward compatibility, the original vectors should be replaced by aliases pointing to the now case sensitive symbol entries at the end of the vector file. After an hour of typos, the new option file worked, and still the old useone2 and fourtest programs could use it:

$ cc one21/obj=one22.obj/names=as_is
$ library/create one22.olb one22.obj
$ link/share/exe=one2shr_2.exe one22.olb/lib, one22_vector.opt/opt
$ define one2shr 'f$environment("default")'one2shr_2.exe
%DCL-I-SUPERSEDE, previous value of ONE2SHR has been superseded
$ r fourtest
 vier: four
$ r useone2
 een: one
twee: two
drie: three
The new option file was called one22_vector.opt:
                                                                      
GSMATCH=LEQUAL,1,2
CASE_SENSITIVE=YES
IDENTIFICATION="one2 1.2"
SYMBOL_VECTOR=( -
DRIE/drie=PROCEDURE, -
EEN/een=PROCEDURE, -
TRANSLATE_EN/Translate_en=DATA, -
TWEE/twee=PROCEDURE, -
VIER/vier=PROCEDURE, -
Translate_en=DATA , -
drie=PROCEDURE , -
een=PROCEDURE , -
twee=PROCEDURE , -
vier=PROCEDURE )
CASE_SENSITIVE=NO
The OpenSource adept was happy, but the programmers were not. They now had to maintain the source code, but also the vector options file, which by a lot of accounts was far more complicated than the source file, as it had to be upward compatible and the order of the vector entries was not evident.
The sophisticated build procedures did not really support generating a vector options file, and the OpenSource adept was already starting to make a nuisance of himself by asking questions about functions with names longer than 31 characters.

A cost-factor helps out. Automatic upward compatibility

Within the organization, system administrators where considered a costly asset who, now everyone was using modern computers, weren't worth their money. As a consequence, no budget was assigned to them, and they were asked every month to start looking for other opportunities. They didn't, and spent their time learning about the systems they weren't allowed to manage and writing programs that actually worked.

They came up with linkshrlib.com, a command procedure that contained two programs, listlib and vectorcompatible, that relieved the programmers of the maintenance of their vector files.

Using only the object libraries, they were able to demonstrate creating an upward compatible library could be done completely automatically. They even didn't need the first original linker options file, as the symbols had already been sorted alphabetically in the original:

$ @[-.linkshrlib]linkshrlib one2.olb one2shr_1_0.exe +version=1.0+id="one2shr V1.0"
New linker vector options file will be called H:[T]ONE2_VECTOR.OPT;
data symbol found: TRANSLATE_EN
No demangler db used.
Link H:[T]ONE2.OLB;3 to H:[T]ONE2SHR_1_0.EXE;
Made and will use version option file H:[T]ONE2_VERSION.OPT;
$ @[-.linkshrlib]linkshrlib one21.olb one2shr_1_1.exe +version=1.1+id="one2shr V1.1"
New linker vector options file will be called H:[T]ONE21_VECTOR.OPT;
data symbol found: TRANSLATE_EN
No demangler db used.
Link H:[T]ONE21.OLB;4 to H:[T]ONE2SHR_1_1.EXE;
Made and will use version option file H:[T]ONE21_VERSION.OPT;
$ @[-.-.linkshrlib]linkshrlib one21.olb one2shr_1_2.exe +version=1.2+id="one2shr V1.2"
New linker vector options file will be called H:[T]ONE21_VECTOR.OPT;
data symbol found: TRANSLATE_EN
No demangler db used.
Link H:[T]ONE21.OLB;4 to H:[T]ONE2SHR_1_2.EXE;
Made and will use version option file H:[T]ONE21_VERSION.OPT;
They used the original test executables and tested compatibility:
$ define one2shr 'f$environment("default")'one2shr_1_0.exe
%DCL-I-SUPERSEDE, previous value of ONE2SHR has been superseded
$ r [-.o]useone2
 een: one
twee: two
drie: three
$ r [-.o]fourtest
%DCL-W-ACTIMAGE, error activating image ONE2SHR
-CLI-E-IMGNAME, image file H:[T]ONE2SHR_1_0.EXE;1
-SYSTEM-F-SHRIDMISMAT, ident mismatch with shareable image
$!
$ define one2shr 'f$environment("default")'one2shr_1_1.exe
%DCL-I-SUPERSEDE, previous value of ONE2SHR has been superseded
$ r [-.o]fourtest
 vier: four
$ r [-.o]useone2
 een: one
twee: two
drie: three
$ define one2shr 'f$environment("default")'one2shr_1_2.exe
%DCL-I-SUPERSEDE, previous value of ONE2SHR has been superseded
$ r [-.o]useone2
 een: one
twee: two
drie: three
As you can see, upward compatibility was established, by using the old vector option file as input when linking a new version of the shared image. In linkshrlib.com this works like this: After generating a new vector option file with listlib.exe, vectorcompatible generates a new, compatible vector options file using both the old and the newly generated option file.

Long function names

The Open Source man said: That's fine, but I have this Open Source library that is worried about name spaces, and as a consequence they use function names that are very long.

I know that the C compiler shortens the function names, but it does so differently when I compile it case-sensitively using the compiler switch /NAMES=(SHORTENED,AS_IS), so case is preserved, and when I don't use the AS_IS switch, like this : /NAMES=(SHORTENED)so names are converted to uppercase.

To find out the shortened names for both, I need to compile the library twice. He showed the of code libdum, that looked like this:

 
#include <stdio.h>
#include <stdlib.h>

int libdum_Initialize_All_but_leave_the_clever_bits()
{
 return( 17 );
}

int libdum_Initialize_only_the_clever_bits_so_not_all()
{
#ifdef WIN32
	return( 0 );
#endif
 return( 18 );
}

int libdum_do_something_that_even_doesnt_look_clever()
{
return(1);
}

The administrators were not impressed and found out that compiling twice wasn't necessary, as they found the shortening in the comp.os.vms Usenet group, where Craig Berry published it.

If you want both upper- and lowercase entries in you shareable library, make sure you compile all modules with /NAMES=(AS_IS,SHORTENED).

The compiler will produce a cross reference of the actual and shortened function names in a subdirectory called CXX_REPOSITORY, in a file called CXX$DEMANGLER_DB.;
Put you object in an objectlibrary, point linkshrlib to CXX$DEMANGLER_DB.;, and it will create a shareable image with both upper- and lowercase entries.

Ok, Let's give it a try:

$ cc libdum/names=(as_is,shortened)
$ dire .dir

Directory H:[LIBDUM]

CXX_REPOSITORY.DIR;1                  

Total of 2 files.
$ dir [.cxx_repository]

Directory H:[LIBDUM.CXX_REPOSITORY]

CXX$DEMANGLER_DB.;1

Total of 1 file.
$ ty [.cxx_repository]cxx$demangler_db.;
libdum_Initialize_All_b3uu4cah$libdum_Initialize_All_but_leave_the_clever_bits
libdum_Initialize_only_39lru31$libdum_Initialize_only_the_clever_bits_so_not_all
libdum_do_something_tha3r1068u$libdum_do_something_that_even_doesnt_look_clever
To keep the command line short, you can define a logical pointing to it. Now create the object library, and then link it to a shareable image:
$ library/create libdum.olb libdum.obj
$
$ define demang [.CXX_REPOSITORY]CXX$DEMANGLER_DB.;1
$
$ @[-.linkshrlib]linkshrlib libdum.olb libdum_1_0.exe +demang=demang:+version=1.0+id="libdum V1.0"
New linker vector options file will be called H:[LIBDUM]LIBDUM_VECTOR.OPT;
%DCL-W-ACTIMAGE, error activating image H:[LIBDUM]LISTLIB.EXE
-CLI-E-IMAGEFNF, image file not found H:{LIBDUM]LISTLIB.EXE;
Compile and link listlib
Link H:[LIBDUM]LIBDUM.OLB;1 to H:[LIBDUM]LIBDUM_1_0.EXE;
Made and will use version option file H:[LIBDUM]LIBDUM_VERSION.OPT;
$
$
$ ty libdum_version.opt
GSMATCH=LEQUAL,1,0
CASE_SENSITIVE=YES
IDENTIFICATION="libdum V1.0"
CASE_SENSITIVE=NO
$ ty libdum_vector.opt
! generated by listlib.exe Fri Jul 24 20:12:00 1970
CASE_SENSITIVE=YES
SYMBOL_VECTOR=( -
libdum_Initialize_All_b3uu4cah$=PROCEDURE, -
LIBDUM_INITIALIZE_ALL_B3R3B4LC$/libdum_Initialize_All_b3uu4cah$=PROCEDURE, -
libdum_Initialize_only_39lru31$=PROCEDURE, -
LIBDUM_INITIALIZE_ONLY_1QUMGA1$/libdum_Initialize_only_39lru31$=PROCEDURE, -
libdum_do_something_tha3r1068u$=PROCEDURE, -
LIBDUM_DO_SOMETHING_THA33U2UN7$/libdum_do_something_tha3r1068u$=PROCEDURE)
CASE_SENSITIVE=NO
You see that the procedure actually compiles and links listlib, one of the excutables if it cant find it.
Lets write a testprogram, and see if it really works. We call it testlibdum.c
#include <stdio.h>
#include <stdlib.h>

int libdum_Initialize_All_but_leave_the_clever_bits();
int libdum_Initialize_only_the_clever_bits_so_not_all();
int libdum_do_something_that_even_doesnt_look_clever();

main()
{
printf(" This should be 17 : %d\n", libdum_Initialize_All_but_leave_the_clever_bits());
printf(" This should be 18 : %d\n", libdum_Initialize_only_the_clever_bits_so_not_all());
printf(" This should be  1 : %d\n", libdum_do_something_that_even_doesnt_look_clever());
}

We define a logical with a full filespec pointing to libdum, and compile testlibdum both with NAMES=(SHORTENED,AS_IS) and NAMES=(SHORTENED) and link and run it to verify that both upper- and lowercase vectors in the shareable library work:
$ define libdumshr 'f$environment("default")'libdum_1_0.exe
$ cc testlibdum/names=(as_is,shortened)
$ link testlibdum, sys$input/opt
libdumshr/share
Exit
$ r testlibdum
 This should be 17 : 17
 This should be 18 : 18
 This should be  1 : 1
$ cc testlibdum/names=(shortened)
$ link testlibdum, sys$input/opt
libdumshr/share
Exit
$ r testlibdum
 This should be 17 : 17
 This should be 18 : 18
 This should be  1 : 1
It worked.

Excluding symbols, using a map file

The build procedure of ZLIB 1.2.3 generates the vectors in much the same way linkshrlib does. Problem is, that a lot of procedures are for internal use by zlib only, not meant to be global sysmbols to be called by programs calling zlib. A lot of the internal symbols are preceded by an underscore, but not all. So, linkshrlib allows you to define a comma separated symbols of wildcarded procedures that can be excluded, an incomplete list for zlib might be:
+exclude_symbols="_*,inflate_fast"
For libssh2, this list was very simple, as the libssh2 project had wisely decided, that all local procedures should be preceded by an underscore:
+exclude_symbols="_*"
Nobody was looking forward to guessing what symbols might be meant to be global in zlib, and also nobody looked forward at maintaining this list. Then, with zlib 1.2.5, a file containing such definitions was made available in the zlib dirstribution: zlib.map Based on the zlib object library, the zlib.map file could be used to link a zlib shareable library, with only the global symbols needed, using this command line:
@linkshrlib LIBZ_1_2_5_32.OLB libz_1_2_5_shr32.exe +vmap=zlib.map+ident="LIBZ 1.2.5"+version="1.200500" -
  +new_vect=libz_1_2_5_vector.opt
Also note the +version="1.200500" option. This makes sure the version of zlib is encoded in the shareable library, in a way that remains more or less readable:
$ analyze/image/inter libz_1_2_5_shr32.exe
.
IMAGE HEADER

        Fixed Header Information

                image format major id: 3, minor id: 0
                header block count: 2
                image type: shareable (EIHD$K_LIM)
                        global section major id: %X'01', minor id: %X'030F34'
                        match control: ISD$K_MATLEQ
.
.
.
$ a = %X030F34
$ show symbol a
  A = 200500   Hex = 00030F34  Octal = 00000607464
As you can see, the actual version is easily derived from the minor id.

Inner workings

Linkshrlib.com contains C source code, and will compile and link listlib.exe and, if needed, vectorcompatible.exe in the default directory a the moment you invoke linkshrlib.com. To prevent compiling and linking these tools every time, linkshrlib.com sets up global symbols to the resulting executables.

One consequence is, that without a working C compiler, linkshrlib.com may not work.

All this may be frowned upon, but is very practical when distributing the procedure to other systems.

If (global) symbols listlib and vectorcompatible already exist and point to a working executable, these are used, and no new version is being compiled.

So, if you're really annoyed or worried about this behaviour, have global symbols point to precompiled and linked executables listlib.exe and vectorcompatible.exe, not forgetting the dollar preceding the executable file specification, like this:

$ listlib :== $exe:listlib.exe
$ vectorcompatible :== $exe:vectorcompatible.exe

Docs, linkshrlib help

Ok, that most explained. If linkshrlib.com is started without any arguments, it will display a comprehensive help text:
$ @linkshrlib

Create a shareable image from an objectlibrary

Uses 2 executables, that will be compiled and linked if
not available in foreign symbols listlib and
vectorcompatible.

Usage: @Linkshrlib help
       shows this screen.

Usage: @Linkshrlib   [[+qual=value],...]

       Qualifiers are preceded by + in stead of /, to not confuse
       DCL. Make sure to omit spaces, to not surpass the 8 parameter
       limit of DCL. The first 3 characters of the qualifier
       will be sufficient.

       +new_vector=
                    If not supplied this will be
                    _vector.opt
                    If this produces the same filename as t
                    the old vectoroptions this name will be
                    _vector_new.opt
       +old_vector=
                   New vectorfile is made upward compatible
                   with this options file
       +format=[p|l] format of new vector options file
                   format can be p or l, default is l, to prevent
                   the linker running out of space:
                   p: symbol_vector=(a=PROCEDURE,b=PROCEDURE,...)
                   l: symbol_vector=(a=PROCEDURE)
                      symbol_vector=(b=PROCEDURE)
                      ...
       +demangle_db=
                   Used if symbols are shortened by the C
                   compiler to egenrate both upper and
                   lowercase vectors or aliases.
                   Works not good if sources are not compiled
                   /names=(as_is)
       +exclude_symbols="sym1,sym2,*wildcard*"
                   Do not make vectors for possibly wildcarded
                   symbols in this comma separated list.
                   Commonly, symbols starting with _ (underscore)
                   are not to be made global. In this case, this
                   qualifier should be +exclude_symbols="_*".
      +vmap=
                   Some packages provid a list of symbols to be
                   exported or not, per version, for OS's that
                   support versioning. This is a finer grained
                   method thatn the crude exclude_symbols list.
      +vlab="version name as used in Unix version script"
                   By default, the version with most dependencies
                   (usually the highest version) in the version
                   script will be used. But, you can specify it
                   here. The label should be exactly the same as
                   used in the version script.
      +link_options = "..."
                   Literal extra options that will be appended
                   to the linker commandline. Literal means that
                   to add an option file the preceding comma needs
                   to be included +link=",blurb.opt/opt"

                   Not having a GSMATCH statement as option when linking
                   a shared library will have images linked against
                   it not want to accept newer versions.
                   Not having an IDENTIFICATION is very poor practice.
                   If no option file could be detected, and no +version
                   qualifier is present, version 1.0 is used.
      +version = x.y    x and y must be decimal numbers
                   If you do not want to write an optionfile with GSMATCH
                   and IDENTIFICATION statements, you can give libversion
                   on the command line, and an options file
                   called _version.opt is created with
                   GSMATCH=LEQUAL,x,y
                   IDENTIFICATION=" x.y"
                   that will be apppended to the linker commandline
                   before the link_options if supplied.
      +ident       see version. string replaceing the automatically
                   generated ID when only version is supplied.

      +sharedlib   if the shared library needs to be linked against
                   other shared libraries, give a comma separated list
                   of logicals or names of the shared libraries.
                   This is an alternative to stating them in a separate
                   optionfile. These options will be written in
                   _version.opt even if version is not
                   specified.

   Example:
   @linkshrlib one2.olb  one2shr.exe +version=1.0
      will create one2shr.exe, one2shr_vector.opt and one2shr_version.opt

   @linkshrlib one21.olb one2shr.exe +version=1.1 +old=one2_vector.opt
      will create new version of one2shr.exe, one2shr_vector_new.opt and
      one2shr_version.opt. If binary compatible, this version will be
      upward compatible with the previous shareable image.