- How dynamic linking for modular libraries works on Linux
- Linker
- Create the object files
- Creating a shared object file
- Creating a dynamically linked executable
- Compiling the application
- Dynamically linking
- How to handle dynamic and static libraries in Linux
- Anyone can compile open source code in these three simple steps
- Dynamically linking libraries while compiling code
- C++ Dynamic Shared Library on Linux
How dynamic linking for modular libraries works on Linux
When you write an application using the C programming language, your code usually has multiple source files.
Ultimately, these files must be compiled into a single executable. You can do this by creating either static or dynamic libraries (the latter are also referred to as shared libraries). These two types of libraries vary in how they are created and linked. Both have advantages and disadvantages, depending on your use case.
Dynamic linking is the most common method, especially on Linux systems. Dynamic linking keeps libraries modular, so just one library can be shared between any number of applications. Modularity also allows a shared library to be updated independently of the applications that rely upon it.
In this article, I demonstrate how dynamic linking works. In a future article, I’ll demonstrate static linking.
Linker
A linker is a command that combines several pieces of a program together and reorganizes the memory allocation for them.
The functions of a linker include:
- Integrating all the pieces of a program
- Figuring out a new memory organization so that all the pieces fit together
- Reviving addresses so that the program can run under the new memory organization
- Resolving symbolic references
As a result of all these linker functionalities, a runnable program called an executable is created. Before you can create a dynamically linked executable, you need some libraries to link to and an application to compile. Get your favorite text editor ready and follow along.
Create the object files
First, create the header file mymath.h with these function signatures:
int add(int a, int b); int sub(int a, int b); int mult(int a, int b); int divi(int a, int b);
Create add.c , sub.c , mult.c and divi.c with these function definitions. I’m placing all of the code in one code block, so divide it up among four files, as indicated in the comments:
// add.c int add(int a, int b) < return (a+b); >//sub.c int sub(int a, int b) < return (a-b); >//mult.c int mult(int a, int b) < return (a*b); >//divi.c int divi(int a, int b) < return (a/b); >
Now generate object files add.o , sub.o , mult.o , and divi.o using GCC:
$ gcc -c add.c sub.c mult.c divi.c
The -c option skips the linking step and creates only object files.
Creating a shared object file
Dynamic libraries are linked during the execution of the final executable. Only the name of the dynamic library is placed in the final executable. The actual linking happens during runtime, when both executable and library are placed in the main memory.
In addition to being sharable, another advantage of a dynamic library is that it reduces the size of the final executable file. Instead of having a redundant copy of the library, an application using a library includes only the name of the library when the final executable is created.
You can create dynamic libraries from your existing sample code:
$ gcc -Wall -fPIC -c add.c sub.c mult.c divi.c
The option -fPIC tells GCC to generate position-independent code (PIC). The -Wall option isn’t necessary and has nothing to do with how the code is compiling. Still, it’s a valuable option because it enables compiler warnings, which can be helpful when troubleshooting.
Using GCC, create the shared library libmymath.so :
$ gcc -shared -o libmymath.so \ add.o sub.o mult.o divi.o
You have now created a simple example math library, libmymath.so , which you can use in C code. There are, of course, very complex C libraries out there, and this is the process their developers use to generate the final product that you or I install for use in C code.
Next, you can use your new math library in some custom code, then link it.
Creating a dynamically linked executable
Suppose you’ve written a command for mathematics. Create a file called mathDemo.c and paste this code into it:
#include #include #include int main() < int x, y; printf("Enter two numbers\n"); scanf("%d%d",&x,&y); printf("\n%d + %d = %d", x, y, add(x, y)); printf("\n%d - %d = %d", x, y, sub(x, y)); printf("\n%d * %d = %d", x, y, mult(x, y)); if(y==0)< printf("\nDenominator is zero so can't perform division\n"); exit(0); >else < printf("\n%d / %d = %d\n", x, y, divi(x, y)); return 0; >>
Notice that the first line is an include statement referencing, by name, your own libmymath library. To use a shared library, you must have it installed. If you don’t install the library you use, then when your executable runs and searches for the included library, it won’t be able to find it. Should you need to compile code without installing a library to a known directory, there are ways to override default settings. For general use, however, it’s expected that libraries exist in known locations, so that’s what I’m demonstrating here.
Copy the file libmymath.so to a standard system directory, such as /usr/lib64 , and then run ldconfig . The ldconfig command creates the required links and cache to the most recent shared libraries found in the standard library directories.
$ sudo cp libmymath.so /usr/lib64/ $ sudo ldconfig
Compiling the application
Create an object file called mathDemo.o from your application source code ( mathDemo.c ):
The -I option tells GCC to search for header files ( mymath.h in this case) in the directory listed after it. In this case, you’re specifying the current directory, represented by a single dot ( . ). Create an executable, referring to your shared math library by name using the -l option:
$ gcc -o mathDynamic mathDemo.o -lmymath
GCC finds libmymath.so because it exists in a default system library directory. Use ldd to verify the shared libraries used:
$ ldd mathDemo linux-vdso.so.1 (0x00007fffe6a30000) libmymath.so => /usr/lib64/libmymath.so (0x00007fe4d4d33000) libc.so.6 => /lib64/libc.so.6 (0x00007fe4d4b29000) /lib64/ld-linux-x86-64.so.2 (0x00007fe4d4d4e000)
Take a look at the size of the mathDemo executable:
$ du ./mathDynamic 24 ./mathDynamic
It’s a small application, of course, and the amount of disk space it occupies reflects that. For comparison, a statically linked version of the same code (as you’ll see in my next article) is 932K!
$ ./mathDynamic Enter two numbers 25 5 25 + 5 = 30 25 - 5 = 20 25 * 5 = 125 25 / 5 = 5
You can verify that it’s dynamically linked with the file command:
$ file ./mathDynamic ./mathDynamic: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, with debug_info, not stripped
Dynamically linking
A shared library leads to a lightweight executable, as the linking happens during runtime. Because it resolves references during runtime, it does take more time for execution. However, since the vast majority of commands on everyday Linux systems are dynamically linked and on modern hardware, the time saved is negligible. Its inherent modularity is a powerful feature for developers and users alike.
In this article, I described how to create dynamic libraries and link them into a final executable. I’ll use the same source code to create a statically linked executable in my next article.
How to handle dynamic and static libraries in Linux
Knowing how Linux uses libraries, including the difference between static and dynamic linking, can help you fix dependency problems.
Anyone can compile open source code in these three simple steps
You don’t need to know how to write or read code to compile it.
Dynamically linking libraries while compiling code
Compiling software gives you a lot of flexibility in how you run your system. The LD_LIBRARY_PATH variable, along with the -L and -l GCC options, are components of that…
C++ Dynamic Shared Library on Linux
This is a follow-up to Dynamic Shared Library compilation with g++. I’m trying to create a shared class library in C++ on Linux. I’m able to get the library to compile, and I can call some of the (non-class) functions using the tutorials that I found here and here. My problems start when I try to use the classes that are defined in the library. The second tutorial that I linked to shows how to load the symbols for creating objects of the classes defined in the library, but stops short of using those objects to get any work done. Does anyone know of a more complete tutorial for creating shared C++ class libraries that also shows how to use those classes in a separate executable? A very simple tutorial that shows object creation, use (simple getters and setters would be fine), and deletion would be fantastic. A link or a reference to some open source code that illustrates the use of a shared class library would be equally good. Although the answers from codelogic and nimrodm do work, I just wanted to add that I picked up a copy of Beginning Linux Programming since asking this question, and its first chapter has example C code and good explanations for creating and using both static and shared libraries. These examples are available through Google Book Search in an older edition of that book.
I’m not sure I understand what you mean by «using» it, once a pointer to the object is returned, you could use it like you use any other pointer to an object.
The article I linked to shows how to create a function pointer to an object factory function using dlsym. It doesn’t show the syntax for creating and using objects from the library.
You will need the header file describing the class. Why do you think you have to use «dlsym» instead of just letting the OS find and link the library at load time? Let me know if you need a simple example.
@nimrodm: What’s the alternative to using «dlsym»? I’m (supposed to be) writing 3 C++ programs that will all use the classes defined in the shared library. I also have 1 Perl script that will use it, but that’s a whole other problem for next week.