在Windows上静态编译GTK+

原创
2016/01/31 14:01
阅读数 2.6K

在Windows上面利用GTK+库开发应用程序时, 大多是动态链接的, 但是对于只是想拿它来写一些小的工具的人来说, 动态编译显然有些不太合适, 写完了程序还要附带上一大堆的dll文件, 这样无论是发布还是运行都比较麻烦。因此, 产生了想要静态编译GTK+库的想法。

去GTK+的mailing list中找到了相关的提问, 这是链接:

https://mail.gnome.org/archives/gtk-app-devel-list/2003-September/msg00038.html

其实, 从里面的邮件回复就可以看出来, GTK+库目前还是不支持静态编译的。

但是, 偶然的一次机会, 看到了StackOverflow里面有人回复, 有一个项目可以让GTK+实现静态编译, 这是StackOverflow的链接:

http://stackoverflow.com/questions/1875855/statically-linking-gtk-libaries-in-windows

里面提到了一个叫做mingw-cross-env的项目, 于是去看了一下, 然后顺便找到了GitHub的项目页面:

https://github.com/mxe/mxe

于是, 就照着这个项目开始了GTK+-3.14.4库的静态编译的探索。

查看一下这个项目的源代码, 发现在src目录下有很多的.mk和patch文件, 各个名字代表了各个库, 如atk.mk和atk-1-DllMain.patch代表了这几个文件是用于编译atk的静态库的。.mk文件指明了库的下载地址, 以及具体的configure和make的过程, 而.patch文件则是对应的库的补丁。

首先, 去msys2里面的源( http://mirrors.ustc.edu.cn/msys2/REPOS/MINGW/i686/ )去下载并配置gtk+的动态编译的Bundle包, 如下图:

从图上面可以看出, 要想编译GTK+的程序, 一共需要依赖这么多的库。但是, 这中间只有atk、gdk_pixbuf、glib、libepoxy、pango和最终的GTK+库需要自己去重新编译成静态库。同时, 还要根据mingw32.files.tar.gz安装python3和libxml并解决相关依赖。至于编译环境, 推荐最新版本的mingw-w64, 以及msys或者msys2, 避免出现编译错误。

然后配置编译环境。安装msys到D;\, 如D:\msys。解压mingw-w64到D:\, 如D:\mingw32。然后逐个解压从msys源下载下来的库, 如mingw-w64-i686-zlib-1.2.8-9-any.pkg.tar.xz, 然后进入解压后的目录, 找到lib文件夹下面的*.dll.a, 将其删除, 然后将解压后的目录与D:\mingw32目录合并。除了需要额外静态编译的库之外, 其他的库也同样处理, 包括python3和libxml以及相关依赖。但是, gettext库除了与D:\mingw32合并之外, 还需要将include和lib目录与D:\mingw32\i686-w64-mingw32下面的include和lib目录合并, 否则会在configure时报错。

接下来就是设置环境变量以及逐个去编译atk、gdk_pixbuf、glib、libepoxy、pango和GTK+库, 记得在configure时每个库都要加上gcc的-static参数以强制链接到静态库上。然后每静态编译成功一个库, 就将其添加进D:\mingw32目录中。

  1. 编译libepoxy库

    根据MXE项目里面src目录下面的.patch进行相应处理。但是libepoxy中gl.h文件需要特别处理一下。

    从上面可以看出, 程序在编译阶段就默认链接的是动态库, 因此, 需要在#endif /*_WIN32*/后面添加如下语句进行覆盖:

    #define APIENTRY
    #define GLAPIENTRY
    #define EPOXY_IMPORTEXPORT
    #define EPOXY_CALLSPEC
    #define GLAPI
    #define KHRONOS_APIENTRY
    #define KHRONOS_APICALL

     

    将dispatch_wgl.c中的DllMain函数改名, 否则后面链接时会产生符号重定义的错误。

    然后根据.mk文件去configure、make、make install。

  2. 编译gdk_pixbuf库

    除了按照.mk和.patch处理外, 还需要在configure阶段在CFLAGS中定义GDK_PIXBUF_STATIC_COMPILATION宏, 让编译器静态编译。

  3. 编译glib库

    这个库比较麻烦, 首先, 打补丁的地方较多, 其次, 有两处都默认采用了动态编译。

    gmodule.h中的部分代码如下:

    与libepoxy一样, 需要在#endif /*!G_PLATFORM_WIN32*/后面添加一句:

    #  define G_MODULE_EXPORT

    然后, 除了按照.mk和.patch处理外, 因为还需要依赖gdk_pixbuf库, 还需要在configure阶段在CFLAGS中定义GLIB_STATIC_COMPILATION和GDK_PIXBUF_STATIC_COMPILATION宏, 让编译器静态编译。

  4. 编译atk库

    除了按照.mk和.patch处理外, 因为需要依赖glib库, 还需要在configure阶段在CFLAGS中定义ATK_STATIC_COMPILATION、GLIB_STATIC_COMPILATION和GDK_PIXBUF_STATIC_COMPILATION宏, 让编译器静态编译。

  5. 编译pango库

    因为这个库是依赖glib库的, 因此除了按照.mk和.patch处理外, 还需要在configure阶段在CFLAGS中定义GLIB_STATIC_COMPILATION和GDK_PIXBUF_STATIC_COMPILATION宏, 让编译器静态编译。

  6. 编译GTK+库

    除了按照.mk和.patch处理外, 还需要在configure阶段在CFLAGS定义上述的各种宏, 让编译器静态编译, 还要指定具体LIBS=-lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0 -lpango-1.0 -latk-1.0 -lcairo -lcairo-gobject -lpangocairo-1.0 -lintl -lgmodule-2.0 -lgio-2.0 -lgmodule-2.0 -lglib-2.0  -lgobject-2.0 -lintl -lws2_32  -lwinmm -limm32 -luser32 -lgdi32 -luuid -lole32 -lpng -lgdiplus -lpangowin32-1.0 -lffi -lws2_32 -lwinmm -lglib-2.0 -liphlpapi -lole32 -lintl -lws2_32  -lwinmm -lpixman-1 -lfreetype -lfontconfig -lpangoft2-1.0 -lfreetype -lharfbuzz -lexpat -lbz2 -lpng -lmsimg32 -liconv -lshlwapi -lz -lgdi32 -ldnsapi -lusp10 -lgcc -lkernel32 -lmsvcrt, 否则make时会报"undefined reference"错误。

至此, 整个GTK+的静态库也就全部制作完成了。用自己制作的GTK+的静态库编译一个简单的窗体程序, 最终的可执行文件有17M多, strip之后大概15M左右。

以后用这个库编译程序时, CFLAGS就由pkg-config生成, 至于LIBS, 手工指定为LIBS = -lgtk-3 -lgdk-3 -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0 -lpango-1.0 -latk-1.0 -lcairo -lcairo-gobject -lpangocairo-1.0 -lintl -lgmodule-2.0 -lgio-2.0 -limm32 -luser32 -lgdi32 -luuid -lole32 -lpng -lgdiplus -lpangowin32-1.0 -lffi -lws2_32 -liphlpapi -lwinmm -lglib-2.0 -lpixman-1 -lfreetype -lfontconfig -lpangoft2-1.0 -lmsimg32 -liconv -lshlwapi -lz -lgdi32 -ldnsapi -lusp10 -lfreetype -lharfbuzz -lbz2 -lwinspool -lcomdlg32 -lcomctl32 -lexpat -lgcc -lkernel32 -lmsvcrt。

其实, 试着去运行一下编译GTK+库时编译的test程序就会发现, 总是会在命令行窗口中出现"assert failed"的输出, 这是glib库的输出, 不知道是不是属于BUG。另外, 个人感觉GTK+静态编译出来的程序还是太大了, 同样是静态编译出来的QT的程序, 相比较而言大小就小一些, 大概12M多。

总之, 这次尝试还是值得的。

展开阅读全文
打赏
1
4 收藏
分享
加载中
更多评论
打赏
0 评论
4 收藏
1
分享
返回顶部
顶部