Creating Libraries in Linux
For this tutorial ill be using:
- Ubuntu 14.04 LTS (Ubuntu clang ver 3.4)
- gcc 4.8.4
First and foremost. Why do we use libraries? Well, it saves time. Picture having to write your own printf function every time the situation calls for it. Libraries are just files that contain the object code of common functions or methods you’d rather not write every time you need them. So, if we want to print some text to stdout or get the length of a string, (unless you’re trying to broaden your understanding) you’re better off using a library to save time.
How do they work? As I mentioned above, libraries are files containing the object code of common functions. For example: If we had a function that will calculate the sum of two numbers and a function that returns the length of a string.
From here we have two choices.
- Static Library (Statically Linked Library)
- Dynamic Library (Dynamically Linked Library or Shared Library)
Before we move on I want to talk about the differences between Static and Dynamic libraries.
When it comes to Static Libraries, they’re utilized at compile time. Meaning, the object code for stringlen and getsum reside within the executable once compiled. The downside to this is the bigger your library is, the bigger your executable or application will be. Also, every time you update your library, you would need to recompile a new executable to take advantage of those changes.
On the other hand, Dynamic Libraries are utilized at run time. They do this by not inserting the object code of all functions into the executable at compile time but only inserting the memory address of the libraries location. So, when a function is called, the program will search this address for the function and execute it. As you’ve probably guessed, this makes for a lighter executable and a far more portable library in that a new executable does not need to be created whenever the library is updated.
To create a Static Library we’re going to start with GCC to build our .c files into object file format so they can be combined into a library.
The gcc command above contains the -c option which assembles the object files (.o). -Wall -Werror -pedantic -Wextra options make for a strict error checker, and *.c indicates we’re to assemble object files out of all .c files within this directory.
Next we’ll archive our object files, building them into a single .a file (static library file)
All there is left to do is link and compile our Static Library file with our mainfile to create our executable.
The GCC command above starts off with a -static option preventing a link with shared libraries (Dynamic Libraries). After we include the mainfile we use the -L. option letting the compiler know we’re linking a library that exists within the same directory. -lfoo would be the library the compile would look for within the directory (its assumed the library name will have lib in the beginning and .a (for static) and .so (for dynamic) at the end). and finally a -o option to name our executable.
Now for Dynamically Linked Libraries (Shared Libraries).
Just like before we’re going to assemble our object files with GCC. However, there will be a slight difference in our command.
Notice above we’ve added the -fPIC option telling the compiler we’re going to assemble our object files or compile our code into Position-independent Code. Meaning, this code will work no matter where it is in memory. Since different programs may use an instance of this library, it cannot be stored statically in memory because every instance of this library will be in a different location in the memory.
Next, using GCC, we’re going to compile with -shared option, telling the compiler to produce a shared object which can then be linked with other objects to form an executable. Then we’re going to name the library the same way as the static library except instead of .a we’ll designate it as a .so file or shared object file.
Now that we have our Shared Library file, we’ll need to link and compile much like how we compiled our Static Library.
So, lets try and run it.
Looks like the loader is having a hard time finding the library. Reason for this is we never specified where the library was located. Remember Dynamic or Shared Libraries are utilized at run time and so far we’ve only told the loader that we’re taking this route not where the library exists.
There are two ways we can fix this: Using the environment variable LD_LIBRARY_PATH containing the location of the library, which the loader will check when attempting to find the library at run time. Or using the -rpath or Run Path option to embed the location of the library within the executable. (Note. rpath will not embed the code but the location where the code exists.).
Assuming you’ve never tried to build your own Dynamic Library before, your LD_LIBRARY_PATH will be empty and all we need to do is fill it with the location or path where your library exists.
For the Run Path method, we’re going to need to rewind to where compilation for an executable occurred.
In the above GCC command. We’ve added the -Wl option to pass the destination of our library to the linker, and thus the destination exists in our compiled executable.
As you can see our static executable is much larger than our dynamic.