C/C++ static and dynamic libraries

The C/C++ programs rely heavily on the functions and classes, such as iostream, sqrt(), etc., which are stored in libraries. These libraries are created by the compiler, after which the linker is invoked after the object source codes are compiled by the compiler.

The linker can link your program to the libraries in two ways. Statically or dynamically. These two categories of libraries are called static libraries and shared libraries or dynamic libraries.

A static library is like a book in a bookstore, where if you would like to read a chapter of the book, you must purchase the book and this book now goes with you all the time; while the dynamic library is like a book in a public library, where if you would like to read a chapter you may feel free to make a copy of it and bring the copy with you. Others may make a copy of the same book when they need to.

Creating static libraries

You can create static libraries using the GNU compilers gcc (for C) and g++ (for C++) like below. First, compile the source codes to object files.

g++ -c file_a.cpp file_b.cpp file_c.cpp

This will create object files file_a.o, file_b.o, file_c.o. Then, use the program ar to create a static library archive:

ar -rv libabc.a file_a.o file_b.o file_c.o

This command creates a static archive file called libacb.a. Notice that the convention is to put “lib” before the library name, which is abc in this case. If you want to delete an object file from the archive, use the -d option for ar.

ar -d libabc.a file_c.o

Or, if you would like to update an object file in it, use the -u option.

ar -u libabc.a file_b.o

Now since the static library has been created. you may use it and link it to the main program. Remember, the contents in the archive file will be compiled into the executable, like a nail into a pine plank.

g++ -c main.cpp -o main.o
g++ -o main.out main.o -L. -labc

The -L option for g++ or gcc specifies additional paths for the compiler to look for library files, and the -l option specifies the name of the library needed. In this case it’s abc, notice that “lib” or the “.a” extension are not needed. Also, distinguish -L and -I, where -I specifies the additional include paths, where the header files are stored.

Let’s take a look at a minimum example below. I’ve put the files mentioned above in the same folder, of which the contents are shown below.

Now, compile the files, create an archive library, and then compile the main file and link it with the library, just as shown above.
Similarly, if you would like to link using libraries in a different folder, use -L to specify it.

Creating dynamic libraries

Creating a shared (dynamic) library is similar, however the extensions of the library file may be different depending on the OS: .so on Linux, .dylib on OSX, and .dll on Windows. To create the shared library, the source codes for the library need to be compiled as position-independent code (PIC). Simply speaking, PICs are loaded dynamically in the memory to avoid conflicts with other dynamic libraries. This is done with the -fPIC flag of the compiler.

g++ -c -fPIC file_a.cpp file_b.cpp file_c.cpp 
g++ -shared -o libabc.dylib file_*.o
g++ -o main.out main.cpp -L./ -labc

Notice that the biggest difference from a static library is that ar is not invoked, but the g++ -shared is used instead. Also, (obviously), the file extension is different.

Two import environment variables

LD_LIBRARY_PATH (on Linux, DYLD_LIBRARY_PATH on OSX) and LIBRARY_PATH

LIBRARY_PATH is a colon-separated list of paths used by the compiler to search for libraries before linking to your program.

LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is a colon-separated list of paths used by your compiled and linked program to search for shared libraries.

They are very different variables. If you would like to avoid using the -L option every time you link your program, alternatively you can add the library path to the environment variable. Assuming you are using BASH, to add custom paths, do

export LIBRARY_PATH=$LIBRARY_PATH:your_custom_path_for_libraries

The colon : is basically a delimiter here to separate paths. If you have more than one path to expand to the variables, use colon to separate them.

As for LD_LIBRARY_PATH/DYLD_LIBRARY_PATH, think of it like this way. When you link your program using shared libraries, those libraries are not built in your executable. The compiler just knows there will be something for it to use when executed. When you execute the program, the program does NOT know where those shared libraries are any more, so you have to specify them. This is done by

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your_custom_path_for_shared_libraries

on Linux, or

export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:your_custom_path_for_shared_libraries

So, $LD_LIBRARY_PATH is only used at execution. Even you used -L to specify the location of shared libraries at linking time, you still need to supply this for the program to search for libraries at run time.

As an example of the usage of these env. variables, the following screenshot is self-explanatory.

Have fun!

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax