dlopen wayfire 插件导致未定义符号:_ZTIN2wf3txn20transaction_object_tE

问题描述 投票:0回答:1

为了避免 A/B 问题:最终我想做的是查明我拥有的 wayfire 插件二进制文件(在我的例子中是 firedecor)是否已使用足够新的 wayfire 版本进行编译,以便 API/ABI插件支持的版本(可以通过导出的

getWayfireVersion
检索)与今天的 wayfire 版本匹配,或者插件是否必须针对新的 wayfire 版本重新编译。

为了找出编译我的插件共享库的 wayfire api/abi 版本,以便我最终可以执行所需的比较,我编写了一个简短的 C++ 程序。它

dlopen
是插件共享库,并尝试调用
getWayfireVersion()
并将其输出与当前版本包含的 wayfire 标头检索到的
WAYFIRE_API_ABI_VERSION
的值进行比较:

#include <wayfire/plugin.hpp>
#include <errno.h>
#include <dlfcn.h>
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char* argv[]) {
    void *handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
    if (handle == NULL) {
        fprintf(stderr, "dlopen failed: %s\n", dlerror());
        return 1;
    }
    uint32_t (*version_func)() = (uint32_t (*)())dlsym(handle, "getWayfireVersion");
    if (version_func == NULL) {
        perror("dlsym failed");
        dlclose(handle);
        return 1;
    }
    int32_t plugin_abi_version = version_func();
    if (WAYFIRE_API_ABI_VERSION != plugin_abi_version) {
        fprintf(stderr, "API/ABI version mismatch:\n");
        fprintf(stderr, "wayfire is: %" PRIu32 "\n", WAYFIRE_API_ABI_VERSION);
        fprintf(stderr, "plugin is: %" PRIu32 "\n", plugin_abi_version);
        dlclose(handle);
        return 1;
    }
    fprintf(stderr, "wayfire is: %" PRIu32 "\n", WAYFIRE_API_ABI_VERSION);
    fprintf(stderr, "plugin is: %" PRIu32 "\n", plugin_abi_version);
    dlclose(handle);
    return 0;
}

我编译一下:

$ g++ test.cc -o test -Wall -ldl $(pkg-config --cflags pixman-1) -DWLR_USE_UNSTABLE

但是当我运行它时我得到:

$ ./test /usr/lib/aarch64-linux-gnu/wayfire/libfiredecor.so
dlopen failed: /usr/lib/aarch64-linux-gnu/wayfire/libfiredecor.so: undefined symbol: _ZTIN2wf3txn20transaction_object_tE

查看

libfiredecor.so
nm
确实表明,
_ZTIN2wf3txn20transaction_object_tE
是未定义的,但由于它是一个插件,所以没关系,因为它应该从加载它的可执行文件中获取符号。现在我的问题是:如何修改我的
test.cc
或我的
g++
调用,以便
test
二进制文件包含
wf::txn::transaction_object_t
的类型信息?

使用虚拟值应该足够了,因为我的插件中的

getWayfireVersion
定义如下:

uint32_t getWayfireVersion() { return WAYFIRE_API_ABI_VERSION; }

RTLD_NOW
中的
RTLD_LAZY
更改为
dlopen
只会导致在执行
dlopen
时不显示错误消息,而仅在稍后调用函数时显示错误消息。

我联系了 wayfire 开发人员以获取他们的意见,但他们一无所知:https://github.com/WayfireWM/wayfire/issues/2499

此问题的另一种解决方案是在构建插件时对 wayfire api/abi 版本进行硬编码,并将结果存储在文件中,稍后查询该文件并将其与

WAYFIRE_API_ABI_VERSION
的当前值进行比较。但由于该解决方案不太理想,并且这已变成一个 C++ 问题,因此我在这里寻求帮助。也许有人知道如何使我的
test.cc
包含我的插件所需的(虚拟)符号,谢谢!

c++ plugins linker dlopen
1个回答
0
投票

如何修改我的

test.cc
g++
调用,以便
test
二进制文件包含
wf::txn::transaction_object_t

的类型信息

您可以将此类的定义添加到您的

test.cc
中。比如:

namespace wf::txn {
class transaction_object_t {
  virtual ~transaction_object_t() = default;
};

// Create one instance to make sure the vtable is not optimized out.
static transaction_object_t *ptr = new transaction_object_t();
}

您必须对插件中的all未定义符号执行此操作(该集可能会在版本之间发生变化),因此这听起来不像是可行的长期方法。

OTOH,如果

dlopen
由于未解析的符号而失败,则表明您无论如何都必须重建插件,所以也许这已经足够了。

© www.soinside.com 2019 - 2024. All rights reserved.