2

In my directory, I have two files. One is foo.cpp, and the other is bar.so. In foo.cpp, I am attempting to load the library bar.so:

#include <dlfcn.h>
#include <iostream>

int main()
{
    void* handle = dlopen("bar.so", RTLD_NOW | RTLD_GLOBAL);
    std::cout << handle << std::endl;
    return 0;
}

In this same directory, I then compile the code from the command line with:

g++ foo.cpp -ldl -o test

However, when executing test, this prints out 0, and according to the documentation for dlopen:

If dlopen() fails for any reason, it returns NULL

So why is this returning NULL, when the library file is in the same directory as the CPP file?


Update:

I have now added dlopen() to my CPP file, and this outputs:

bar.so: cannot open shared object file: No such file or directory

But I don't understand... bar.so and foo.cpp are in the same directory, the executable is built in this same directory, and I am in this same directory when I run the executable.

So then, I tried using an absolute path for bar.so, but I then receive a new error:

invalid ELF header

After a quick google, I think this may be due to my Ubuntu installation. I am actually using a MacBook, and have installed a native copy of Ubuntu (not a virtual machine). It seems that this is causing the problem, but I don't know how to fix it. Perhaps this library file will just not work on MacBook Ubuntu.

Karnivaurus
  • 22,823
  • 57
  • 147
  • 247
  • 3
    Can't tell you why it fails, could be any of a number of reasons. You should just print `dlerror()` and see what it says. – StoryTeller - Unslander Monica Jun 10 '19 at 20:17
  • Print dlerror(). It should give you a good direction. You can edit the post with the output of dlerror(). – Naseef Chowdhury Jun 10 '19 at 20:18
  • Use `objdump` on the executable to see whether there's an `RPATH` entry listing the directory containing the library. – Barmar Jun 10 '19 at 20:21
  • 2
    You need `"./bar.so"`. Otherwise, `dlopen()` will not look in the current directory to load the file. – Nikos C. Jun 10 '19 at 20:25
  • 1
    However, another solution is to add `-Wl,-rpath='$ORIGIN'` to your compile flags when you compile `foo.cpp`. This way, it doesn't matter what the current directory is. `dlopen()` will always look in the directory of the executable first. But note that this will cause all libraries to looked for in the current directory first, not just those you try to `dlopen()`. It might or might not be what you want. The absolute best solution is to acquire the directory of the executable and runtime and use that instead. – Nikos C. Jun 10 '19 at 20:33
  • The first thing to change is `./bar.so` as @Nikos suggests. Second, try different `dlopen` flags. Debian and Red Hat differ in what they require for `dlopen`. Try both `RTLD_GLOBAL` and then `RTLD_GLOBAL | RTLD_LAZY`. Third, use a `RUNPATH` (not `RPATH`) when building the program. Use something like `-Wl,-R, -Wl,--enable-new-dtags`. – jww Jun 10 '19 at 20:35
  • I checked my notes at [Linux | Note for Shared Object Callers](https://cryptopp.com/wiki/Linux#Note_for_Shared_Object_Callers). It looks like Debian and Ubuntu require `dlopen` flags `RTLD_GLOBAL | RTLD_LAZY`. – jww Jun 10 '19 at 20:48
  • @πάντα - This question may not be a dup of the cited questions. – jww Jun 10 '19 at 21:29

1 Answers1

4

So why is this returning NULL, when the library file is in the same directory as the CPP file?

The location of the.cpp file is of no relevance here.

The location of the executable, respectively the setting of LD_LIBRRY_PATH is what's used to resolve at runtime.

Anyway, LD_LIBRRY_PATH is not a recommended long-term solution. The simple one is to use "./bar.so" instead of "bar.so" so that dlopen() looks in the current directory first. But the current directory might not be the same as the directory the executable is stored in. In that case, dlopen() will still fail.

Another solution is to add -Wl,-rpath='$ORIGIN' to your compile flags when you compile your executable (foo.cpp in this case) and pass "bar.so" as you do already. When using $ORIGIN as the rpath, it doesn't matter what the current directory is. dlopen() will always look in the directory of the executable first. But note that this will cause all libraries to be looked for in the current directory first, not just those you try to dlopen(). It might or might not be what you want.

So the best solution is to acquire the path to the directory the executable is in at runtime and use that as the path to bar.so. This is system specific. On Linux, see: Get path of executable

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190