在Windows上靜態編譯GTK+

在Windows上面利用GTK+庫開發應用程序時, 大可能是動態連接的, 可是對於只是想拿它來寫一些小的工具的人來講, 動態編譯顯然有些不太合適, 寫完了程序還要附帶上一大堆的dll文件, 這樣不管是發佈仍是運行都比較麻煩。所以, 產生了想要靜態編譯GTK+庫的想法。html

去GTK+的mailing list中找到了相關的提問, 這是連接:python

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

其實, 從裏面的郵件回覆就能夠看出來, GTK+庫目前仍是不支持靜態編譯的。github

可是, 偶然的一次機會, 看到了StackOverflow裏面有人回覆, 有一個項目可讓GTK+實現靜態編譯, 這是StackOverflow的連接:windows

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

裏面提到了一個叫作mingw-cross-env的項目, 因而去看了一下, 而後順便找到了GitHub的項目頁面:app

https://github.com/mxe/mxe函數

因而, 就照着這個項目開始了GTK+-3.14.4庫的靜態編譯的探索。工具

查看一下這個項目的源代碼, 發如今src目錄下有不少的.mk和patch文件, 各個名字表明瞭各個庫, 如atk.mk和atk-1-DllMain.patch表明了這幾個文件是用於編譯atk的靜態庫的。.mk文件指明瞭庫的下載地址, 以及具體的configure和make的過程, 而.patch文件則是對應的庫的補丁。ui

首先, 去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多。

總之, 此次嘗試仍是值得的。

相關文章
相關標籤/搜索