Why Dynamic Libraries?
Before creating your own Dynamic (also known as Shared) Library, you need to understand what libraries are and why you would want to use them. In this blog post, I’ll be going over object code, object files, the types of libraries available, why you should use libraries, and how to create and use Dynamic Libraries.
You first need to understand what an object file is. An object file is a file containing object code. Object code is machine code that contains additional information for the Linker in the form of symbols. These symbols are used to index the library and code so the linker can traverse the files with ease. We need our files in object code so that they can be injected into a library. To stop our files from becoming an executable, use
$ gcc -c which halts compilation right before the Linker stage. Once our library is created with these object files we can then move on and compile. But before we get there, we need to know what a library is.
What is a Library?
Now that we know what object files are, we can talk about libraries. A library is a file containing several object files and can be used as a single entity in the linking phase of the program. There are 2 types of libraries — Static Libraries and Dynamic Libraries.
A Static Library is a collection of object files that get linked into the program during the linking phase of compilation. This type of library gets appended to the executable file every time it is run with a program. This means that if you want to run your executable file, you don’t need to worry about whether the client has the right library on their system. Basically, since the library code is connected at compile time, the final executable has no dependencies on the library at run time. The drawback is that executables will be rather large in size because the entire library code is appended to the executable, even if only one function is needed from it.
A Dynamic Library is a collection of object files that can be linked to any program at run-time by inserting the location of the function in memory to the executable. This provides a way for code to be used even though it could be loaded anywhere in memory. Once a dynamic library is loaded into memory, it’s code can be used by any program that needs it. This is much different than Static Libraries and keeps the size of executables low. Because Dynamic Libraries provide a way to use code that’s anywhere in memory, if the code is updated, you don’t need to recompile. Just because the code was updated, doesn’t necessarily mean it’s location has been changed, so the library still knows where to direct the program. This means that updating code is much simpler and requires less time.
Dynamic Libraries also include version numbers. This is helpful for a few reasons:
- You can tell if a new version of the library is required. This happens when a change is done that makes the shared library incompatible with the previous version, i.e. a whole function getting removed.
- A minor version number change is made if a minor change was introduced. This happens when something such as a bug fix was introduced, but the library is still compatible with the previous version.
- Naming conventions like this help multiple versions of the same library co-exist on the same system.
Programs linked with the shared library do not need to worry about the latest version of the shared library installed in the system. Once the newest library is installed, all programs will automatically start linking to the latest version. This works because the name the Linker uses to link the executables to the library is usually a symbolic link to the real name.
Why use Libraries?
The main reason for using libraries is to make compiling easier. Say we have a function that calls over 100 other functions. The command line to compile those would be huge and confusing since we’d have to include all those functions in the command line. Instead, we can compile all of those functions into a library and just use one simple command that will link the library with our file.
$ gcc file1.c file2.c file3.c file4.c file5.c file6.c file7.c file8.c 0-main.c -o program
$gcc -L. 0-main.c -llibrary -o program
How to create a Dynamic Library
The first thing needed to create a Dynamic Library is to take all of the .c files we want and turn them into .o files by using
$ gcc -Wall -fPIC *.c. The flags
-fPIC are used to help us and the Linker.
-Wall is used to tell us about any errors that are occurring so they can be fixed before being added to the library.
-fPIC is a compiler directive that tells it to output position independent code. This is needed because, as stated before, the code in the shared library could be loaded anywhere in memory.
$ gcc -Wall -fPIC *.c
$ ls *.o
Now all of the .o files need to be injected into a library. The following command is used to accomplish this:
$ gcc -shared -o library.so *.o
This will create a Dynamic Library named
library.so. The reason the library ends in
.so is because in Linux, the naming convention for Dynamic Libraries are files that end in
.so (shared object).
Connect Dynamic Library with executables
Now compile the library with the main file and give it a name:
gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -llibrary -o program
-L. flag was used to tell the linker that libraries might be found in the current directory(“.”) as well as the standard locations. Secondly,
-l(library name)is the notation for including a library in the command line. Lastly,
-o is used to name the executable “program”.
Now that the library is created and compiled, you need to check if it is connecting correctly to the executables calling it by using
ldd on the file:
$ ldd program
linux-vdso.so.1 => (0x00007ffcd57c8000)
library.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb124ee8000)
Uh oh. The library hasn’t been connected to anything yet, so there are 3 options to connect it. The library could be moved to the correct directory, or you could populate the environment variable,
LD_LIBRARY_PATH with information — this will tell the Linker to look at this location as well.
To add it to the correct directory, the following would work:
$ mv library.so /opt/lib
To include the current directory in the search path, use:
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
Another option, if you will be leaving the current directory and need to use the library in a different directory. Set the
LD_LIBRARY_PATH to the absolute path of the library:
$ export LD_LIBRARY_PATH=/absolutepath:$LD_LIBRARY_PATH
One last check with
ldd will show you that the library is now connected:
$ ldd program
linux-vdso.so.1 => (0x00007ffc2b5f8000)
library.so => ./library.so (0x00007fea7b333000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fea7af6a000)
How to use a Dynamic Library
Now that the library is up and running, all you have to do is use the executable by typing:
And that’s it! Now you can use Dynamic Libraries as much as you want!