Creating and Using Shared Libraries Demo

Sometimes an administrator must install source code packages that include DLLs (Dynamic Link Libraries), also known as shared object (or SO) files.  While not normally a problem, occasionally some source code will refuse to compile because of minor problems with the DLLs.  As an administrator you should be able to correct such minor problems without (paying for) a software developer's help.

The main issues are:

  1. Building and installing DLLs before the programs that need them.
  2. Using the correct options to the compiler, so that DLLs can be found and used at compile time.
  3. Updating the system cache and configuration to know about new DLLs, so programs can find them at run-time.

If a compile of some source code fails due to a missing library, first make sure the library is really missing.  For example, the bsdtar source code package includes a required DLL, “libarchive”.  However, building this package fails because the build process attempts to build the program (“bsdtar”) before building and installing the DLL it needs (“libarchive”).  In this case the fix was easy: cd to the libarchive build directory, and issue the required make and make install steps manually.  Once finished building libarchive, a restart of the bsdtar build succeeded.

If the missing DLL is not part of the current source package (or tar-ball), check the included README, INSTALL, and other documentation to see if this is discussed.  Query your package management system to see if the library is part of some package that you may need to refresh.  Search various repositories on the Internet to see if the missing library is available as part of some other package you can install.

If you can't locate the file, make sure the package you are trying to install is designed to work on your (type of) system!

If you do locate the DLL on your system but the compiler can't find it, there are some likely causes:

  1. The required version of that DLL is not available.  Often this is a result of a missing symlink (a.k.a. soft link).  For example if you have the DLLmylib.so.1.2.3”, you should have the following symlinks to that DLL:
    mylib.so
    mylib.so.1
    mylib.so.1.2
    

    (The link with no version number is used by compilers, but usually installed from a separate package “somelib-devel”.)

  2. The DLL is available but was installed with incorrect permissions.  If root installed the DLL and the umask was set to say “027”, then other users may not have permission to use the DLLs.  This is fixable easily with chmod.
  3. The DLL is installed but (really!) is the wrong version.  If you earlier installed one package that required “lib.so.2”, you probably have that version installed now.  Now if you install some other software that requires specifically lib.so.1, you won't be able to build (or use) it.  The fix in this case is to have both versions installed.  But make sure all the symlinks are correct, and that lib.so symlink refers to the latest version and not some earlier one.

    In order to have two different versions of some library available, so some applications can use one version while other applications use a different version, the symbols (function, data, ... names) in the DLLs must be tagged with a version number.  Not all systems support that.  For example, Red Hat Linux and variants such as Fedora don't, while Debian Linux and variants such as Ubuntu do.  Of course, you can rebuild the kernel on a Red Hat type system and the DLL tools, and use multiple versions there too.


  4. The DLL is correctly installed but the compiler can't find it.  This can happen in two ways:
    • If the DLL is installed in a standard location, it may be that the system DLL cache is out of date, or that the ld.so (or ld-linux.so) isn't configured to look in that location.  In that case you need to edit /etc/ld.so.conf* to make sure the correct location is used, and/or run “ldconfig” to rebuild the cache.
    • The DLL is in a non-standard location (say in a subdirectory of the build directory) and the compiler isn't looking there.  Note the compiler ignores LD_LIBRARY_PATH environment variable, so every non-standard location where DLLs are to be found must be listed on the command line using the “-Ldir” option.  The fix here is to edit the Makefile and change the compiler options to also look in the required directory.  Look near the top of the makefile and try to spot where the compiler options are defined, by looking for lines containing other “-Ldir” compiler options.  Now edit that line (or add a new one) that includes the missing “-Ldir” option.

Example

Here is a simple demo of a “Hello, World!” C program.  This demo contains the source code for a DLL named “libhello.so.1”.  (The actual library file name is “libhello.so.1.0.0”.)  First you must build this and install it.  For this demo, no root access is required.  We will install the DLL in a non-standard location, namely “~/lib”.

Once the DLL is built you can then build the application that uses the DLL, named “libhello_test”.  This can then be installed in your ~/bin directory.

libhello.c (DLL source)

Download libhello.c

/* libhello - source to demo shared library use.
 * Shared libraries have a "major" version and a
 * "minor" version (and sometimes a "release" version
 * number as well).  Different major numbers indicate
 * (possibly) incompatible versions; if the major
 * number is the same than the minor number indicates
 * compatible bug fixes.  Our current version is
 * "libhello.1.0.0".
 *
 * BUILD DIRECTIONS:
 *   gcc -fPIC -shared -Wl,-soname,libhello.so.1 \
 *       -o libhello.so.1.0.0 libhello.c
 *
 * INSTALL DIRECTIONS:
 *  Copy the libhello.so.1.0.0 to a standard directory
 *    such as /usr/lib (or if system is configured for it,
 *    /usr/local/lib).
 *  Run "ldconfig" to create the various symlinks required.
 *
 *    * OR *
 *
 *  Put the libhello.so.1.0.0 anywhere, say ~/lib, and then:
 *  Run "ldconfig -nv ~/lib" (or whatever dir you used).
 *  (Note for security reasons LD_LIBRARY_PATH is ignored when
 *  running SUID programs!)
 *
 * In either case ldconfig doesn't create a full set of symlinks.
 * Make sure you manually create any missing ones:
 *    cd ~/lib
 *    ln -s libhello.so.1.0.0 libhello.so.1.0
 *    ln -s libhello.so.1.0 libhello.so.1
 *    ln -s libhello.so.1 libhello.so
 *
 * Written 7/2005 by Wayne Pollock, Tampa Florida USA.
 */

#include "libhello.h"
#include <stdio.h>

/* ELF shared libraries can have many functions and even
 * global variables.  Here is one demo function:
 */

void say_hello ( char* s )
{
   printf( "Hello, %s!\n", s );
}

/* When a shared library is loaded, two special function
 * are used: _init when the library is loaded and _fini
 * when it is unloaded (typically when the process exits).
 * If you don't have either one defined, the system will
 * create a default "do nothing" version for you!

void _init ()
{
   printf( "%s\n", "Library libhello.so initializing!" );
}

void _fini ();
{
   printf( "%s\n", "Library libhello.so unloading!" );
}

*/

libhello.h (DLL header file)

Download libhello.h

/* libhello.h - header for libhello.so.1.0.0 demo program
 *
 * Written 7/2005 by Wayne Pollock, Tampa Florida USA.
 */

/* ELF shared libraries can have many functions and even
 * global variables.  Here is one demo function:
 */

void say_hello ( char* str );

/* When a shared library is loaded, two special function
 * are used: _init when the library is loaded and _fini
 * when it is unloaded (typically when the process exits).
 * If you don't have either one defined, the system will
 * create a default "do nothing" version for you!

void _init ();

void _fini ();

*/

libhello_test.c (application source)

Download libhello_test.c

/* libhello_test - A sample application that
 * uses the demo shared library "~/lib/libhello.so.1.0.0".
 *
 * COMPILE DIRECTIONS:
 *  Make sure libhello.so* is in a standard directory, or
 *  use the gcc command line argument "-L<dir>".
 *  Also make sure libhello.h is in a standard include directory
 *  (such as the current directory) or add "-I<dir>":
 *
 *  gcc -Wall -L~/lib -o libhello_test libhello_test.c -lhello
 *
 * If this fails to work make sure the library is chmod a+rx,
 * and that all needed symlinks are there.  (Note ldconfig -nv dir
 * doesn't create all required links.)
 *
 * Written 7/2005 by Wayne Pollock, Tampa Florida USA.
 */

 #include "libhello.h"

 int main ( void )
 {
   say_hello( "World" );
   return 0;
}

Related Information

If a DLL is installed in a non-standard location, even if some application that uses it builds successfully it may not run!  This is because the compiler uses command-line arguments (“-Ldir”) to locate DLLs at compile time, but at run time only the standard locations are checked.  To fix you can tell the program where to look for such DLLs by setting the LD_LIBRARY_PATH environment variable.  However this is awkward as every program will use this setting, so other applications may break.  An alternative is to hard-code the absolute pathname to the DLL(s) in the application binary.  This can be done by adding a compiler option of “-W1,-rpath=path-to-DLL” to the command line when building the application.  If you later move the DLLs to a standard location you will have to rebuild the application without this extra option.

The gcc commands used to compile C programs include options to tell the compiler where to look for header files (dot-h files).  If the compile fails because some header file couldn't be located, first make sure you read the README, INSTALL, and other documentation before proceeding with any trouble-shooting steps!

If the is no mention of the problem in the documentation, you should see if you can locate the file yourself.  Often it will be in the same directory (or a sub-directory) of the program you are attempting to build.  If not, use locate or find to determine the file's location.

Now see if the gcc command that generated the “not found” error lists that directory on the command line with the “-Idirectory” option.  If not, you have found the problem!  You can fix the problem in two ways:  edit the C source code file and repair the faulty “#include "path-to-file.h"” line; or edit the “Makefile” to make sure the correct directory is used with gcc.  In the latter case look near the top of the makefile to locate the line(s) where the compiler options are defined, and change or just add the required directory.  (That is, look for the other “...-Idir...” lines, and add in a new one or replace the old bad one.) 

If the file doesn't appear to be on your system, check the website home of the software and see if you can find a more recent source package or tar-ball then the one you're using.  Check for notes, postings, mailing list archives, FAQs, or other information about your problem.  Don't hesitate to use any of the Internet resources you have learned!