静态链接 - 使用GTKmm应用程序? - 修订

时间:2011-11-22 15:13:41

标签: c++ linux gtk static-linking gtkmm

是否可以在Gtk(mm)程序上进行静态链接(编译)?我需要程序减少对用户系统依赖性的干扰。

我试试:

g++ -static data/Area.h data/Picture.cpp data/GLScene.cpp data/KBDialog.cpp data/Dialogs.h data/FilePreview.cpp data/MainWindow.cpp prog.cpp -o prog `pkg-config --cflags --libs  gtkmm-2.4 gtkglextmm-1.2 exiv2`

但它失败了:

/usr/bin/ld: cannot find -lgtkmm-2.4
/usr/bin/ld: cannot find -lGL
/usr/bin/ld: cannot find -latkmm-1.6
/usr/bin/ld: cannot find -lgdkmm-2.4
/usr/bin/ld: cannot find -lpangomm-1.4
/usr/bin/ld: cannot find -lgdk_pixbuf-2.0
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libgio-2.0.a(glocalfileinfo.o): In function `lookup_gid_name':
(.text+0x207a): warning: Using 'getgrgid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libgio-2.0.a(glocalvfs.o): In function `g_local_vfs_parse_name':
(.text+0x26c): warning: Using 'getpwnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libglib-2.0.a(gutils.o): In function `g_get_any_init_do':
(.text+0x1244): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libglib-2.0.a(gutils.o): In function `g_get_any_init_do':
(.text+0x1237): warning: Using 'setpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libglib-2.0.a(gutils.o): In function `g_get_any_init_do':
(.text+0x124f): warning: Using 'endpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libglib-2.0.a(gutils.o): In function `g_get_any_init_do':
(.text+0xf6e): warning: Using 'getpwnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libgio-2.0.a(glocalfileinfo.o): In function `lookup_uid_data':
(.text+0x1eea): warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libX11.a(xim_trans.o): In function `_XimXTransSocketUNIXConnect':
(.text+0xe23): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libgio-2.0.a(gnetworkaddress.o): In function `g_network_address_parse':
(.text+0xe3c): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/libgio-2.0.a(gnetworkaddress.o): In function `g_network_address_parse':
(.text+0xe4c): warning: Using 'endservent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
collect2: ld returned 1 exit status

2 个答案:

答案 0 :(得分:10)

(你的问题让我两次生气,所以这里有一个更详细的答案,我可以编辑并进一步完成)


为什么动态链接的共享库很有用?

首先,几乎每个二进制文件都在当今的Linux系统上动态链接。在我的Debian / Sid系统上,我只有/sbin/ldconfig /bin/sash/usr/bin/rar个静态链接的可执行文件,但大约有七千个其他动态链接的可执行文件(在/bin& {{1下) }})。即使像/usr/bin这样的基本程序现在也是动态链接的。

使用shared libraries

主要动态链接ELF可执行文件有几个胜利
  1. 避免浪费磁盘空间。当动态链接的可执行文件不存在时(1986年,SunOS3.5,因为内核无法mmap文件段),人们花了很多时间将几个二进制文件混合在一起(我记得{{1和/sbin/init是相同的二进制文件,是SunOS3.5上的几个程序的混合,以赢得磁盘空间。好吧,今天的磁盘空间更便宜,但是如果我的七千个程序都必须静态链接textedit,那将消耗几千兆字节的磁盘空间(这意味着安装Linux发行版时需要额外的DVD或数小时的网络上传)。

  2. 启用更轻松的更新。当打包系统(cmdtoollibc和Debian上的朋友)升级公共共享库(如GLibC或Gtk)时,它会替换动态链接的共享库(apt-get文件, ELF共享对象)以及使用它们的所有未来二进制执行都会带来利润。因此,如果dpkg更新,则无需更新*.so即可利用/usr/lib/libgtk-3.so中的错误修复程序;只需重新启动/usr/bin/gedit即可使其在libgtk-3.so

  3. 中获得改进
  4. 更高效的整体RAM使用率。几乎每个进程都使用gedit之类的文件,甚至许多进程都使用libgtk-3.so。其中大部分是libc.so - ed只读"文字" segment(特别是包含可执行二进制机器代码和只读字符串的常量);此映射对使用它的每个进程使用相同的RAM单元。所以内存是共享的

  5. 法律遵守LGPL许可 GTK库的LGPL-2.1许可证是您在法律上允许使用GTK的唯一原因(即运行GTK程序,并将您自己的程序与GTK链接)。此许可证授予您权利,特别是改进GTK或利用GTK改进的权利,但您不应禁止链接libgtk-3.so的(例如专有)程序的用户利用GTK内部的改进。 LGPL2.1的第6节明确提到了动态链接。 您不得分发静态链接的GTK二进制文件,而不会向用户提供升级其GTK库的意思。最方便的方法是让您的GTK程序与mmap动态链接。一个不太容易的替代方法是将静态链接的可执行文件与其对象/usr/lib/gtk-3.so文件一起分发,以及如何将其与静态改进的libgtk-3.so(不存在)进行静态重新链接的说明。

  6. 动态加载其他库模块的插件功能 程序可以在运行时使用dlopen函数(基于*.o系统调用,通过libgtk.a库)加载一些共享对象。这就是Linux上插件的可行性。 GTK非常积极地使用这种能力:主题,样式,也许字体使用mmap并由-ldl实现适当的东西。由于dlopen是动态加载程序dlopen的公共接口,因此dlopen库是一个动态共享对象/lib64/ld-linux-x86-64.so.2,它与动态加载程序共享功能和代码(每个都在动态链接的可执行文件作为" ELF解释器")。静态链接-ldl是不常见且不明智的。甚至libdl.so.2库也可能加载其他模块(可能用于DNS支持等等);某些功能在静态链接的可执行文件中受到限制(请参阅文件-ldl等)。

  7. 动态链接在启动时稍慢,因为程序必须在启动时启动并动态加载(这是libc.so的角色)所需的所有动态库。动态库中的代码需要position independent code否则动态加载的库的重定位部分会太大(并且启动时的重定位工作太长),这可能需要额外的寄存器(这大部分是真的)在32位x86处理器上,更不用说x86-64或AMD64 64位处理器了)所以组成稍微大一点的机器代码(在32位x86机器上,我们说的是几个百分比的大小增加和运行时减速;在64位机器上,它可以忽略不计)。当然,重新定位成千上万的外部调用可能需要一些时间(使用C ++代码比使用C代码更多,可能是因为名称损坏问题)。


  8. 为什么你(Marco)不应该静态链接你的GTK二进制文件

    上面的五个要点应该让你相信,静态链接GTK是一件坏事。特别要注意法律方面(LGPL):故意明白LGPL违规是一个巨大的职业错误,不要这样做。

    如果您真的想要,经过数周的努力,您可能在技术上能够(通过重新编译和黑客攻击GTK源代码)将您的二进制文件静态链接到GTK(具有一些减少的功能,例如没有主题),但这可能是不道德且毫无用处。如果你的老板愚蠢到要求你那么,试着说服他(或者找另一份工作)。事实上,您已经在公共论坛上询问如何静态链接GTK(我理解为" 如何违反LGPL许可证")有一定风险。有类似gpl-violations的组织 - 注意到这一点。

    我没有看到静态链接GTK程序的任何有用理由。甚至使用GUI库的专有程序也是动态链接的(一个很好的例子是AMD FGLRX驱动程序及其配套程序,如/etc/nsswitch.conf,提供基于Qt的图形界面进行安装。)

    当然,您可能想要处理依赖项。把它留给linux发行版的包管理器。

    如果您需要更多帮助,请详细说明您真正想做的事情,并说服我们您在违反许可证时不会请求帮助。更好的是,尝试使用免费许可证分发您的软件,例如GPLv3

答案 1 :(得分:6)

我宁愿避免这样做,因为GTK依赖于棘手的低级库,这些库实际上是非常特定于系统的(可能是libfontconfig.so等),并且包含系统特定的信息(例如字体的内置路径......)

我还认为GTK需要动态共享库来实现主题或样式(因此GTK本身正在调用dlopen,并且静态链接 libdl是不合理的)

我建议至少动态链接gtk及其所有依赖项。