0

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?

Enlico
  • 23,259
  • 6
  • 48
  • 102

1 Answers1

3

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.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • (Because you wrote _You don't need it because the name in the library will not be plain `foo`._) In the case of using `extern "C"`, should I still not `#include "MyLib.hpp"` in `main.cpp`? – Enlico Oct 11 '22 at 08:13
  • @Enlico There's no need anyway, because the function prototype will not be used anyway. You must declare a new variable, which is a pointer to a function with the same return type and the same arguments, and then use that variable as assignment destination from the `dlsym` call. For example `void (*foo)() = dlsym(...)` – Some programmer dude Oct 11 '22 at 08:39
  • Yes, but isn't the header a way to get the type `void (*)()` from the library, rather than spelling it myself? – Enlico Oct 11 '22 at 09:27
  • 1
    @Enlico Well possibly through `decltype(foo)`, but then you need to name the variable something other than `foo`. – Some programmer dude Oct 11 '22 at 09:31