为了避免 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
包含我的插件所需的(虚拟)符号,谢谢!
如何修改我的
或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
由于未解析的符号而失败,则表明您无论如何都必须重建插件,所以也许这已经足够了。