Search code examples
c++dynamicshared-librariesdynamic-linkingdlopen

Run-time vs link-time linking of dynamic libraries


tl;dr

When the main application makes use of a dynamic library via dlopen and dlsym, does it need to be linked against it in any way?


Say I have a library like this,

  • header
    #pragma once
    void foo();
    
  • implementation
    #include "MyLib.hpp"
    #include <iostream>
    void foo() {
      std::cout << "Hello world, dynamic library speaking" << std::endl;
    }
    

that I compile via

g++ -fPIC -shared MyLib.cpp -o libMyLib.so

If the main application simply uses a symbol exported by that library, e.g.

#include "MyLib.hpp"
#include <iostream>

int main() {
    int x;
    std::cin >> x;
    std::cout << "before calling foo" << std::endl;
    foo();
}

that means I have to link it against the library, i.e.

g++ -c main.cpp -o main.o
g++ -L. -lMyLib main.o -o main

There are two things that puzzle me:

  • The first one is: why do I need to link main.o against libMyLib.so? I mean, the header MyLib.hpp already provides main.cpp with the signature of foo. What is the role of linking in this case?

  • And what about the case that the main application uses dlopen to load the library and dlsym to load symbols from within it?

    My understanding is that it still needs to #include "MyLib.hpp", for the simple fact that it needs to know how to interpret the output of dlsym, but does main.o need to be in anyway linked against the shared object?


Solution

  • If you use dlopen and dlsym you don't need the header file or the foo function prototype. You don't need it because the name in the library will not be plain foo.

    The C++ compiler uses name mangling to be able to handle things like function overloads, and it's the mangled name you need to pass to dlsym to get a pointer to the function. The mangled names are very implementation-specific, and you need to examine the library to find out the actual mangled name.

    As a workaround for the name mangling problem, you can declare the function in the library as extern "C". This will, among other things, inhibit name mangling and you can pass the name foo to dlsym.


    Also, if you use dlopen and dlsym you should not link with the library. That kind of defeats the purpose of your application doing the dynamic linking.