Differences between static and dynamic libraries
There are two types of libraries, static and dynamic. So:
What is a library?
In a brief way, a static library is a collection of files, which can be invoked in a program. In C we can find a wide variety of libraries, all of them allow us to work quickly and save time, since they have numerous functions, although we can also create our own libraries if the functions we need do not exist or if we are not satisfied with the existing libraries. It has many advantages to use libraries, such as reusing another programmer’s code or ours if the library is our own and the main reason to use them is to keep our code clean and clear and directories less loaded with unnecessary files, something essential for teamwork.
When we are working on a project, one of the most important concepts is single responsibility, which basically means that a code block must be in charge of doing one specific thing; so when we have a function that is responsible for converting a string to an int, we hope that the function only converts from a string to an int, the function should not do other things, since its name only indicates that it converts from string to int.
int string_to_int(char *str) { int res; //CODE return (res); }
How do I create a static library with GCC?
With the GNU Compiler Collection we can 3 simple commands to create a static library.
$ gcc -c *.c
First: We execute the gcc -c * .c command, which will convert all our dependencies that are in .c format to .o (object format), this step is necessary to be able to include our dependencies in a static library.
$ ar -rc libraryName.a * .o
Second: We execute the ar -rc libraryName.a * .o command
- ar means archiver and is a utility to keep different files in a single file.
- rc: r we use it to say replace an old file within our new library and c is to create the file.
- libraryName.a would be the name we want to add to our library, but this name must end with the .a format.
With command we can add to our library the dependencies that we previously converted to object format.
$ ranlib libraryName.a
Third: The ranlib command is used to index our library. This command may not be necessary in many cases, but it is very necessary to run for a library that is very large since it helps the compiler to make a much faster execution in the Linker process.
With these simple steps we have created our static library, and it is called static because our files or functions within the library cannot be changed, in order to change something within our library we must modify the specific files in their initial format. to perform the previous 3 steps and recompile our static library.
How to verify our static library?
$ ar -t libraryName.a
To verify that everything went well, we must execute the command ar -t libraryName.a with which we can see everything our library has inside.
$ nm libraryName.a
But if we want a more detailed view we can execute the nm command.
How do I add a static library when compiling?
$ gcc ourMain.c libraryName.a -o programName
This step is very simple, just run the gcc main.c libraryName.a command to include the static library in the compilation process of our main.c. To verify that everything went well we can execute our program with the command
$ ./programName
Now it’s time for dynamic libraries
How do I create a dynamic library with GCC?
First, we must convert all the functions that I want to add to a library of my .c files to .o (object format - binary code), it should be noted that the header must also be added with the prototypes of the functions. To do this we use the command:
$ gcc -fPIC -c *.c
Where -fPIC makes the code in the library position-independent. PIC is code that works no matter where it is placed in memory. Why does it matter? Because several programs can use the same shared library, the library will have different addresses in memory for each program. And we still want our programs to have access to the code wherever it is stored.
Now that we have all our files (functions) converted to object format, we need to package them in a single file, for that we will use:
$ gcc -shared -o libmylib.so *.o
We use gcc with flags -shared, and of course -o because we compile from an object file, to create a .so file (so stands for shared object).
To be able to use the dynamic library we must do a very different step to the one of the static libraries:
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
Now we have added our library to the path of libraries, and to check that everything works we must use the main file that implements a function from the library, suppose 0-main.c, compile the main file and use to check if our library was imported::
ldd a.out
libmylib.so => ./libhmylib.so (0x00007fd4bf2d9000) (OUTPUT)
So, our library exits on the path and now we can use all the functions that we need from our library.
Static vs Dynamic. Pros and Cons
- Dynamic libraries take up less space than static libraries since when compiling our program, the static libraries method imports absolutely everything the library has together with our program in our executable, while the dynamic library process only imports the functions that our code uses from the library.
- If we change some code in our functions, dynamic libraries will work without a problem, while static libraries will have to be recompiled
- Static libraries are more efficient in execution than dynamic libraries, since static libraries are linked during the compilation process, while dynamic libraries are linked at runtime