Dynamic and Static libraries in C

Renato Leon
6 min readMay 9, 2021

What do you think of when you think of a library, is it a lot of books, information maybe, knowledge stored in old pages, hahaha, cause that’s what I think every time I think of a library.

Well as you may know, in programing or better, in programing languages, us programmers use libraries to make coding easy. But where does this easiness comes from?, that’s what I’ll try to explain in this post.

Imagine you’re programing an app, and in the process of developing it you realize that there is a lot of code that is not strictly linked to the app’s functionallity but is code needed to achieve certain requirements, also you realize that this code could be used in other projects due to it’s generality, and you think, what if could take this code, put it some place and reuse it whenever I need to. And tada!!, you think, of course: a library!!!.

Let’s take this code as an example:

contents of main.c

In the code above, we are using functions to make arithmetic opertations using two numbers, and then prints these results to stdout. Based on these code we can asume that all functions related to arithmetic operations can be used in other programs too, say for example a calculator app. Thinking in cases like this one we can step further and create a file containing all these operations resulting in a library based on the code.

To do so we first separate the code and move it to a separate file like this:

contents of the file math.

Well , now comes the fun part, we’re going to use these functions in our main file without the need to declaring them in the source code, to do so we first need to create a library, in this case a static library.

We achieve this by running the following commands:

$ gcc -Wall -Wextra -Werror -pedantic -c math.c
$ ar -rc libmath.a math.o
$ ranlib libmath.a

The above commands will compile and assemble the file math.c, then the command ‘ar’ merges the contents into a file called “libmath.a” (which is in fact our library), finally ‘ranlib’ indexes the symbols to speed symbol lookup.

To display the list of symbols contained in our library we can use the command ‘nm’ like this:

$ nm libmath.c

math.o:
0000000000000000 T add
000000000000003d T divide
000000000000002a T multiply
0000000000000014 T substract
$

To use or library, we just need to include the header into our main file and then compile, our main file looks tike this now:

contents of main.c

Notice that ‘lib_math.h’ contains the definitions of the functions, now we can use the library in our code, to do so, we have to compile our main file like:

$ gcc main.c -L. -lmath -o static

And that’s it, we can use this library every where we want to or need to, the dowside of static libraries is that every time we copile code using this library, the object code related to it gets copied to the final executable and thus increases the final executable’s size. Fortunally we other alternative, know as Dynamic libraries.

Dynamic libraries allows us to share the code between programs, this is achieved by storing a reference to the library code instead of copying its content.

To create a new dynamic library, we first need to compile our library code into an object code without linking it, we do this by executing the following.

$ gcc -c -fPIC math.c

Notice that:

  • -c: Compiles and assembles the code but doesn’t links it
  • -fPIC: Tells the compiler to create a Position Independent Code

A new file “main.o” was created, the next step is to create our dynamic library taking this object code as this:

$ gcc -shared math.o -o libdynmath.so

And finally we have to compile our program using this dynamic library:

$ gcc main.c -L. -ldynmath -o dynamic

And that’s it, not really, if we try to execute our program it will fail, let’s see:

$ ./dynamic
./dynamic: error while loading shared libraries: libdynmath.so: cannot open shared object file: No such file or directory

mhhh, so what happened, well, to underatand this let’s first look at the dependencies needed to run our code:

$ ldd dynamic
linux-vdso.so.1 => (0x00007fffc47e1000)
libdynmath.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd3ccd8d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd3cd156000)

What??, it says that our library is not found but we now that the library has been created so, what happens is that even though we created the dynamic library and we compiled our code including that library, the liker doesn’t know were that library lives, and thus cannot find it, to fix this we can use an environment variable:

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/$PWD/libdynmath.so

So, LD_LIBRARY_PATH env var contains a list of directories that willbe used for the dynamic linker to load dynamc libraries, now if we execute our program again, we’ll see that it works!!

$ ./dynamic
a + b = 37
a - b = 9
a * b = 322
a / b = 1.64

Great!!, there are other ways we can manage our code to work, let’s take a look, but first we need to unset the env variable that we created eralier.

$ unset LD_LIBRARY_PATH

Excelent!!, now we’ll use ‘ldconfig’ command, which will allow us to create a cache that will cointain all the directories from which the linker will load the libraries, as the manpage for ‘ldconfig’ says:

ldconfig creates the necessary links and cache to the most recent shared libraries found in the directories specified on the command line, in the file /etc/ld. so. conf, and in the trusted directories (/lib and /usr/lib). The cache is used by the run-time linker, ld.so or ld-linux.so.

So now let’s try to use this command in order create the cache needed to load our library at runtime, so to do this we will create a directory that will contain our library, then we’ll create a “.conf” file that will contain the path to this directory, and finally we will run “ldconfig” in order to load cache this changes.

First enter as superuser:

$ sudo su

Now let the configuration start!!, first by creating a directory which will contain our library:

# mkdir /usr/local/lib/my_math

Now copy the library into that directory:

# cp libdynmath.so /usr/local/lib/my_math

Awesome!!, now let’s create the config file, this file will be placed into /etc/ld.so.config.d/

# cd /etc/ld.so.conf.d/
# echo /usr/local/lib/my_math > libmy_math.conf

If we see the dynamic dependencies of our executable now, we’ll see that our library is still missing:

# exit
$ ldd dynamic
linux-vdso.so.1 => (0x00007ffce17f2000)
libdynmath.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e0e2e4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0e0e6ad000)

That’s because there is one more step needed, run the ‘ldconfig’ to load this changes:

$ sudo ldconfig

Now if we list the dependencies again we’ll see that our library is found:

$ ldd dynamiclinux-vdso.so.1 =>  (0x00007ffee9b92000)
libdynmath.so => /usr/local/lib/my_math/libdynmath.so (0x00007f816057a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f81601b1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f816077c000)

And if we run the exe, it will work:

$ ./dynamic
a + b = 37
a - b = 9
a * b = 322
a / b = 1.64

Pretty awesome ah!!.

So that was it for this blog, hope this helped you in some way, have a good day, and see you on the next one!!.

--

--