C++ 如何在 C++ 中使用 dlopen()?

Emi*_*773 4 c++ dlopen tensorflow

我正在尝试在我的包中使用预构建tensorflow c-apicpp-wrapper。不幸的是我遇到了段错误。经过搜索,我发现有一个关于它的 Git 问题:Linking to Both tensorflow and protobuf Causesegmentation failure due to staticinitializer

所以我可以通过执行以下操作来解决问题:

解决方法听起来像 (1) 仅在不使用 TensorFlow 的 .so 中加载 protobuf 的第二个副本,并且您可以从主程序中使用该 .so 和 TensorFlow 的 .so,(2) 而不是正常链接,dlopen () TensorFlow 设置了 RTLD_DEEPBIND,因此 TensorFlow 更喜欢自己的符号。

我想尝试使用 dlopen() 加载库,不幸的是我从未使用过它,也找不到它的使用的好例子。在我的情况下,我将如何使用它以及在哪里使用它?

我最初的理解:将其加载到我的 cpp-wrapper 的标头中,因为它们使用张量流函数/标头?但是我真的需要更改 cpp-wrapper 标头的每个函数,并引用加载的处理程序吗?

Erd*_*çük 5

一个小dlopen例子:


一些用C编写的lib,我们称之为foobar.so

#include <stdio.h>
void foo() { printf("foo\n"); }
void bar() { printf("bar\n"); }
Run Code Online (Sandbox Code Playgroud)

gcc -o foobar.so foobar.c -shared -fPIC


C++ 中的 (foobar) 包装器

#include <dlfcn.h>

struct FooBar {

    typedef void (*foo_handle)(); //same signature as in the lib
    typedef void (*bar_handle)(); //same signature as in the lib

    foo_handle foo;
    bar_handle bar;
    void *foobar_lib;

    FooBar() {

        //probably best not in the constructor, but we're lazy (for now)
        //and of course no error checking (so don't)
        foobar_lib = dlopen("./foobar.so", RTLD_LAZY | RTLD_DEEPBIND);
        foo = reinterpret_cast<foo_handle>(dlsym(foobar_lib, "foo"));
        bar = reinterpret_cast<bar_handle>(dlsym(foobar_lib, "bar"));

    }

    ~FooBar() {
        dlclose(foobar_lib);
    }

};

int main()
{
    FooBar foobar;
    foobar.foo();
    foobar.bar();
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

或者

#include <dlfcn.h>

typedef void (*foo_handle)(); //same signature as in the lib
typedef void (*bar_handle)(); //same signature as in the lib

foo_handle foo;
bar_handle bar;
void *foobar_lib;

int main()
{
    foobar_lib = dlopen("./foobar.so", RTLD_LAZY | RTLD_DEEPBIND);

    foo = reinterpret_cast<foo_handle>(dlsym(foobar_lib, "foo"));
    bar = reinterpret_cast<bar_handle>(dlsym(foobar_lib, "bar"));

    foo();
    bar();

    dlclose(foobar_lib);
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

g++ -ldl -o foobar_test foobar_test.cpp


对于原始库中使用的每个符号,您都必须调用dlsym以获取其地址。

所以,是的,这是一项乏味的工作,因为您正在实现一个包装器来提供底层库的完整功能。

例如,opengl 开发人员非常清楚这意味着什么。幸运的是,多年来,现在有许多工具可用,这有助于在运行时轻松加载无数符号。也许有类似tensorflow的东西。