与MuPDF链接的GTK3 C程序失败(即使没有调用)

时间:2016-10-27 03:34:42

标签: c gtk3 mupdf

对于上下文,我不是编程的新手,但对于unix和GTK来说是新手,所以这可能很简单,但我处于敲击模式。

我已经成功地从源代码构建了MuPDF,包括运行的独立示例。

我刚开始从C学习GTK3并且有最简单的例子,当我决定尝试将两者结合起来时。长话短说 - 在修剪它之后,我发现在运行时遇到与MuPDF相关的某些代码行被编译和链接时,即使没有被调用,我也会遇到分段错误。代码应该足够短,我希望:

的main.c

#include <gtk/gtk.h>
#include "MuPDF_calls.h"

static void activate (GtkApplication *app, gpointer user_data)
{
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *button_box;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Window");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

  button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_container_add (GTK_CONTAINER (window), button_box);
  button = gtk_button_new_with_label ("Hello World");
  g_signal_connect (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
  gtk_container_add (GTK_CONTAINER (button_box), button);

  gtk_widget_show_all (window);
}

int main (int argc, char **argv)
{
  GtkApplication *app;
  int status;
  app = gtk_application_new ("com.leferguson.musicalpi", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

注意除了标题之外,这几乎完全来自GTK +教程,并且只做了一个窗口和按钮。它实际上并没有调用下一个例程:

completness的头文件:MuPDF_calls.h

#ifndef MUPDF_CALLS_H_
#define MUPDF_CALLS_H_

extern int getApage();

#endif /* MUPDF_CALLS_H_ */

和MuPDF_calls.c

#include <mupdf/fitz.h>

extern int getApage()
{
    // Notice that this routine is not actually called by the main program

        fz_context *ctx;

        /* Create a context to hold the exception stack and various caches. */
        ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
        if (!ctx)
        {
            fprintf(stderr, "cannot create mupdf context\n");
            return EXIT_FAILURE;
        }
// If the section below this up to the closing brace before the last return is removed, the program works
// With this included, it gets a terminated, exit value -1, segmentation fault in do_scavenging_malloc()
        fz_try(ctx)
            fz_register_document_handlers(ctx);
        fz_catch(ctx)
        {
            fprintf(stderr, "cannot register document handlers: %s\n", fz_caught_message(ctx));
            fz_drop_context(ctx);
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
}

这个例程基本上是来自MuPDF源代码的example.c的第一部分,为了简洁起见,删除了大部分代码,足以显示失败。

最后这些是使用以下命令构建的:

gcc -g `pkg-config --cflags gtk+-3.0` -c main.c -o build/main.o 
gcc -g -I/home/ferguson/git/mupdf/include -c MuPDF_calls.c -o build/MuPDF_calls.o 
gcc -g build/main.o `pkg-config --libs gtk+-3.0`  build/MuPDF_calls.o   -L/home/ferguson/git/mupdf/build/release -lmupdf -lmupdfthird  -lm -lc -lgcc -lssl -lcrypto -o build/TestGTK 

显然,如果您尝试重新创建此选项,请根据需要调整路径。我不建议这是完全或完整的,它是一个剥离版本试图获得失败所需的最低限度。

再次请注意,在main()中实际上没有调用丑陋的getApage例程。但是如果我使用源中包含的最后一个try / catch部分构建它(并将其链接),程序会在GTK例程中的某个位置运行时出现分段错误(不显示窗口)。

如果我注释掉指定的行并且没有进行任何其他更改并运行,则会按预期显示一个窗口。如果我在调试中运行它,并在代码中设置了中断,我不打算调用它不会到达它(因为它不应该)。

我将程序分开并使用不同的包含路径进行编译,以确保没有可能发生冲突的无关定义,这没有区别。

我已经扩展了相关代码中的宏,没有任何东西跳出来(它在语法上是正确的,如果我使用扩展代码而不是宏编译,它的行为相同。没有相关的编译器警告。< / p>

这是在Ubuntu 16.04上发生的,更新了它的当前和所有相关的构建项目。它位于一个拥有大量内存(8G)且没有其他运行的大型虚拟机中。它是100%可重复的。该错误大约需要2秒钟,这大约是窗口出现所需的时间。

我只是不知道如何修复未被调用的程序中的错误。 :(

更严重的是,我认为这会导致在加载的例程或模块中发生某种命名冲突,或者搜索它们的序列,或者只是一起使用它们时会出现一些不兼容性,但是实验让我无处可去,而且我不知道在哪里开始寻找。

有什么建议吗?

  
    
      

添加了10/27/16 ldd输出。我在运行版本(代码注释)上做了一个ldd并且没有运行,它们是相同的模块,理想情况下(当然是不同的地址)。我不知道MuPDF使用了GTK。我查看了它的源代码树,看到它在几个例子中引用(现在我看到它们需要仔细查看),但我没有在主要查看器中看到它,尽管它可能以一种形式出现不会承认?

    
  

然而,我怀疑这是正确的轨道,并且包括MuPDF代码在某种程度上拖延了一些与GTK3设置不兼容的模块。我只是不知道如何找到它(特别是看到ldd输出相同)。

ldd TestGTK
        linux-vdso.so.1 =>  (0x00007ffc5bfef000)
        libgtk-3.so.0 => /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 (0x00007f2310ad5000)
        libgio-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007f231074d000)
        libgobject-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007f23104f9000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f23101f0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f230fe27000)
        libcrypto.so.1.0.0 => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007f230f9e2000)
        libgdk-3.so.0 => /usr/lib/x86_64-linux-gnu/libgdk-3.so.0 (0x00007f230f707000)
        libgmodule-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007f230f503000)
        libpangocairo-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007f230f2f5000)
        libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f230efbb000)
        libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f230edab000)
        libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f230eba4000)
        libcairo-gobject.so.2 => /usr/lib/x86_64-linux-gnu/libcairo-gobject.so.2 (0x00007f230e99b000)
        libcairo.so.2 => /usr/lib/x86_64-linux-gnu/libcairo.so.2 (0x00007f230e687000)
        libgdk_pixbuf-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x00007f230e464000)
        libatk-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libatk-1.0.so.0 (0x00007f230e23f000)
        libatk-bridge-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0 (0x00007f230e010000)
        libepoxy.so.0 => /usr/lib/x86_64-linux-gnu/libepoxy.so.0 (0x00007f230dd1a000)
        libpangoft2-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007f230db04000)
        libpango-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007f230d8b8000)
        libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f230d674000)
        libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f230d363000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f230d146000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f230cf2b000)
        libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f230cd09000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f230caed000)
        libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f230c8e5000)
        /lib64/ld-linux-x86-64.so.2 (0x0000556c9118f000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f230c6e1000)
        libXinerama.so.1 => /usr/lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007f230c4dd000)
        libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007f230c2d2000)
        libXcursor.so.1 => /usr/lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007f230c0c8000)
        libXcomposite.so.1 => /usr/lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007f230bec4000)
        libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f230bcc1000)
        libxkbcommon.so.0 => /usr/lib/x86_64-linux-gnu/libxkbcommon.so.0 (0x00007f230ba82000)
        libwayland-cursor.so.0 => /usr/lib/x86_64-linux-gnu/libwayland-cursor.so.0 (0x00007f230b879000)
        libwayland-egl.so.1 => /usr/lib/x86_64-linux-gnu/libwayland-egl.so.1 (0x00007f230b677000)
        libwayland-client.so.0 => /usr/lib/x86_64-linux-gnu/libwayland-client.so.0 (0x00007f230b469000)
        libmirclient.so.9 => /usr/lib/x86_64-linux-gnu/libmirclient.so.9 (0x00007f230b1e7000)
        libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f230afd5000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f230adcd000)
        libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f230ab22000)
        libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f230a900000)
        libpixman-1.so.0 => /usr/lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007f230a657000)
        libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f230a432000)
        libxcb-shm.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007f230a22e000)
        libxcb-render.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007f230a023000)
        libXrender.so.1 => /usr/lib/x86_64-linux-gnu/libXrender.so.1 (0x00007f2309e19000)
        libatspi.so.0 => /usr/lib/x86_64-linux-gnu/libatspi.so.0 (0x00007f2309be9000)
        libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007f230999d000)
        libharfbuzz.so.0 => /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007f230973f000)
        libthai.so.0 => /usr/lib/x86_64-linux-gnu/libthai.so.0 (0x00007f2309535000)
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f230930c000)
        libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f230909b000)
        libmircommon.so.5 => /usr/lib/x86_64-linux-gnu/libmircommon.so.5 (0x00007f2308e6a000)
        libmirprotobuf.so.3 => /usr/lib/x86_64-linux-gnu/libmirprotobuf.so.3 (0x00007f2308c08000)
        libboost_system.so.1.58.0 => /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0 (0x00007f2308a04000)
        libprotobuf-lite.so.9 => /usr/lib/x86_64-linux-gnu/libprotobuf-lite.so.9 (0x00007f23087d3000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f2308450000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f230823a000)
        libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f2308035000)
        libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f2307e2f000)
        libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 (0x00007f2307da9000)
        libgraphite2.so.3 => /usr/lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007f2307b84000)
        libdatrie.so.1 => /usr/lib/x86_64-linux-gnu/libdatrie.so.1 (0x00007f230797c000)
        libboost_filesystem.so.1.58.0 => /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.58.0 (0x00007f2307763000)
        liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f2307541000)
        libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f230725f000)
        libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f230704b000)

顺便说一句,这是扩展了宏的代码,如果删除则允许它运行,如果留下则导致失败(即使代码从未遇到过)。有趣的是,__sigsetjmp在MuPDF的包含库和GTK3示例中位于不同的标题中,但我无法看到它正在改变链接的内容,但我怀疑这是相关的。

            ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
            if (!ctx)
            {
                    fprintf(stderr, "cannot create mupdf context\n");
                    return EXIT_FAILURE;
            }


            { if (fz_push_try(ctx))
                    { if (__sigsetjmp ( (ctx)->error->top->buffer,0) == 0)
                            do
                                    fz_register_document_handlers(ctx);
                            while (0);
                    }
            }
            if ((ctx->error->top--)->code > 1)
            {
                    fprintf(stderr , "cannot register document handlers: %s\n", fz_caught_message(ctx));
                    fz_drop_context(ctx);
                    return 1;
            }
  
    
      

2016年10月27日更新#2:我可能在欺骗自己,但我想我越来越近了。失败发生在hb_calloc中,它是harfbuzz的一部分,实际上包含在MuPDF发行版中。看起来GTK最终会调用一个名为pango_shape_full的东西,后者调用hb_ft_face_create并通过一些调用hb_calloc来调用失败。但它正在从MuPDF中包含的源内部获取这些例程,当MuPDF不参与时显然不会发生这种情况(为什么,或者即使它与我不知道的特定代码行相关)。

    
  

我已经找到了如何创建链接映射而不是如何解释它。例如,hb_calloc似乎在crtl中,它也被加载,但随后它再次出现(至少在列表中),来自从源构建的libmupdf.a库。我的GUESS是这种交叉在某种程度上存在问题,虽然我还没有看到原因,或者如何保持对此的控制或分离。我已经在链接中重新排列了lib的顺序,并且找不到任何有所作为的组合。

在MuPDF上也有关于此的负面评论(例如here),但我对发生的事情并不是很深入,以确定它是否相关。但我确实感觉MuPDF中与harfbuz有关的代码与通常用GTK3运行的代码相冲突,我已经以某种方式取代了与GTK一起工作的罐装harfbuz函数,有些则没有。我打算尝试删除MuPDF中的那个c源并重建,但我的猜测是我打破了破坏MuPDF的GTK,可能需要更长时间才能找到,因为我离我很远用它来实现。

或者我走错了路?

1 个答案:

答案 0 :(得分:1)

GTK似乎从系统harfbuzz共享库中调用了一些函数,但是它很困惑,而是调用了存储在libmupdfthird.a库中的harfbuzz版本(可以使用valgrind看到)。

要解决此问题,我已执行以下操作:

假设您有一个需要链接到MuPDF的文件module.o,可以将它们与ld -L<directory_to_search_mupdf_libraries> -r -o newmodule.o module.o -lmupdf -lmupdfthird链接

现在,您有一个newmodule.o文件,其所有依赖项都已受限,但是如果将其与GTK链接,则会出现先前的名称冲突。要解决此问题,您必须将newmodule.o中的所有harfbuzz符号都设置为该文件的本地文件,这样在链接过程中就不会造成混乱。您可以使用objcopy -w -L hb_* newmodule.o进行此操作,该操作会将所有以“ hb_”开头的符号都放在本地。

现在您可以执行类似gcc main.o newmodule.o -o main `pkg-config --cflags gtk+-3.0`的操作,并且应该可以使用。