如何处理“未定义符号”共享对象不匹配的错误

发布于 2024-10-27 08:54:47 字数 543 浏览 5 评论 0原文

我使用最新的 Glade 开发了一个应用程序,因此我需要它使用 GtkBuilder 在运行时从 XML 加载 UI。如果我尝试在 Gtk 太旧的发行版(例如 RHEL 5)上运行它,它将失败,就像这个

未定义的符号:gtk_builder_new

这是正常的和预期的。但我想知道是否有一种方法可以捕获该错误,并显示一个 GUI 错误对话框,上面写着“您的 Gtk 版本不够新”之类的内容?这是在我的 main() 启动之前发生的错误,所以真正的问题是,有没有办法处理运行时链接错误?在谷歌搜索时,我发现提到了链接器插件的概念,但我还没有找到有关该内容的详细信息。无论如何,这听起来像是必须存在于我的应用程序之外的东西,所以也许这有点过头了。

我可以使用 dlopen() 来加载 Gtk,但这很荒谬,因为我必须提供它的完整路径,然后我必须多次调用 dlsym() 来链接我需要的每个函数。 ld-linux.so 为我进行搜索。有没有办法使用 ld-linux.so 告诉我 libgtk 的路径而不实际加载它,然后检查版本是否足够新(或者只是 gtk_builder_new 是否存在),然后完成运行时链接(如果可以)?

I developed an application using a recent Glade, so I need it to load the UI from XML at runtime, using the GtkBuilder. If I try to run this on a distro which has too old a Gtk (e.g. RHEL 5), it will fail like this

undefined symbol: gtk_builder_new

which is normal and expected. But I wonder if there is a way to catch that error and instead display a GUI error dialog saying something like "your version of Gtk is not new enough"? This is an error that happens before my main() starts, so really the question is, is there a way to handle runtime linking errors? While googling, I found a mention of the concept of a linker plugin but I didn't find details about that yet. It sounds like something which would have to exist outside my application anyway, so maybe that's going a bit far.

I could use dlopen() to load Gtk, but that's ridiculous because I'd have to give the full path to it, and then I'd have to call dlsym() a lot to link every function that I need. ld-linux.so does the search for me. Is there a way I can use ld-linux.so to tell me the path to libgtk without actually loading it, then I check whether the version is new enough (or just whether gtk_builder_new exists), then finish the runtime linking if it's OK?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

病毒体 2024-11-03 08:54:47

嗯,它在 Linux 发行版上不是这样工作的。您基本上所做的就是绕过包管理器。

好方法是在目标发行版上构建您的软件。在配置时(调用 ./configure),您将看到不满足使用软件的要求。或者,如果您没有配置脚本,编译器将在链接时大喊大叫。

然后,包装员的工作就是填写包装的要求。如果在 RPM 包的 .spec 文件中要求 gtk >= 2.16,那么在安装时,用户将看到一个对话框,告诉他缺少某些依赖项,并且他会看到他的 GTK 版本太旧。

Well, it doesn't work that way on a Linux distro. What you're basically doing is bypassing the package manager.

The good way is to build your software on the target distro. At configuration time (call to ./configure) you will see that the requirements to use your software are not met. Or if you have no configure script, the compiler will yell at link time.

Then, it's the packager's job to fill in the requirement of the package. If in the .spec file of your RPM package you require gtk >= 2.16, then at installation time, the user will be shown the dialog telling him that some dependencies are missing, and he will see that his GTK version is too old.

一笑百媚生 2024-11-03 08:54:47

您似乎在谈论这样的情况:您已经针对具有足够新版本的标头进行了编译,但在您的库不够新的系统上运行。

GTK 提供了一种工具来检查您是否已链接到足够新的库版本。例如,如果您至少需要 GTK 2.12(这是引入 GtkBuilder 的版本),您可以使用以下代码,它甚至会显示一个漂亮的 GUI 错误对话框:

if (gtk_major_version < 2 || gtk_minor_version < 12) {
    GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
        "Your version of GTK is too old to run this program.");
    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
        "You need at least version 2.12.0; your version is %d.%d.%d.",
        gtk_major_version, gtk_minor_version, gtk_micro_version);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
    exit(-1);
}

You seem to be talking about the situation where you have compiled against headers with a recent enough version, but are running on a system where your library is not recent enough.

GTK provides a facility for checking that you have linked against a new enough version of the library. For example, if you need at least GTK 2.12 (which is the version in which GtkBuilder was introduced) you can use this code which will even display a nice GUI error dialog:

if (gtk_major_version < 2 || gtk_minor_version < 12) {
    GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
        "Your version of GTK is too old to run this program.");
    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
        "You need at least version 2.12.0; your version is %d.%d.%d.",
        gtk_major_version, gtk_minor_version, gtk_micro_version);
    gtk_dialog_run(GTK_DIALOG(dialog));
    gtk_widget_destroy(dialog);
    exit(-1);
}
你的他你的她 2024-11-03 08:54:47

这是一个可能有帮助的解决方法:重命名您的 exe 并创建一个调用它的 bash 脚本。

现在您可以这样做:

 EXE=...name-of-your-real-executable...
 LOG=logfile

 $EXE > "$LOG" 2>&1 || {
     if grep "undefined symbol: gtk_builder_new" "$LOG" ; then
         ... show error message ...
     fi
 }

[编辑] 或者,您可以创建一个非常小的测试程序,其中仅包含对 gtk_builder_new 的调用,并在安装期间或在测试脚本中运行它。

这样,您就不需要检查特定的错误消息(可能会在非英语系统上翻译)。如果这个小测试程序失败,您可以确定这是因为缺少这个符号,而不是其他原因。

Here is a workaround which might help: Rename your exe and create a bash script which calls it.

Now you can do this:

 EXE=...name-of-your-real-executable...
 LOG=logfile

 $EXE > "$LOG" 2>&1 || {
     if grep "undefined symbol: gtk_builder_new" "$LOG" ; then
         ... show error message ...
     fi
 }

[EDIT] Alternatively, you can create a really small test program which just contains a call to gtk_builder_new and run that during installation or in the test script.

That way, you don't need to check for a specific error message (which might get translated on non-English systems). If this small test program fails, you can be sure it's because of this missing symbol and nothing else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文