前言
由於 Windows 不是 Objective-C 的官方開發環境,無法使用 Cocoa。在 Windows 上,只能使用 MinGW (GCC) 搭配 GNUstep 或 ObjFW 做為 Objective-C 的物件庫。
一般來說,會優先使用 GNUstep,因為該物件庫在 API 上相容於 Cocoa,學習曲線會比較平滑。而且 GNUstep 可和 Cocoa 交互參考,可讀的線上資料會比較多。本文會介紹如何建置 GNUstep 開發環境。
使用 GNUstep 官方安裝程式
比較簡單的方式是到 GNUstep 的官網下載給 Windows 用的安裝程式。諘依序安裝以下三個開發工具:
- GNUstep MSYS System (MinGW + MSYS 環境)
- GNUstep Core (函式庫)
- GNUstep Devel (標頭檔和開發工具)
這時候會得到 MinGW (GCC) 加上 GNUstep 物件庫。但 GNUstep 官方的 Windows 安裝程式的版本滯後,會得到陳舊的開發環境。如果願意花點時間,建議自行從 Msys2 開發環境編譯 GNUstep。本文的後半部會說明自行編譯 GNUstep 的流程。
支援 Objective-C 的編輯器
對於 Objective-C 來說,Windows 反而是小眾環境,所以沒什麼大型 IDE 可用。以下是支援 Objective-C 的編輯器:
前兩者是免費的編輯器,對 Objective-C 有基本的支援。後者則是商業軟體,可免費試用 30 天,有興趣的讀者可自行選購。
自行編譯 GNUstep 原始碼
在 Unix 上編譯軟體算是家常便飯,但 Windows 使用者反而較少自行編譯軟體,所以筆者在這裡說明編譯 GNUstep 的流程。
前置作業
請讀者先安裝 MSYS2。若對 MSYS2 不熟悉,可參考這篇文章。
本小節的操作會在 Msys 終端機。請將工作目錄切換到家目錄:
$ cd
先安裝基本的工具:
$ pacman -S wget git
拷貝相關工具命令稿:
$ git clone https://github.com/gnustep/tools-scripts.git
這個專案有幾個安裝過程會用到的命令稿,就不需要逐一打指令。
下載以下四個開發工具的穩定版本壓縮檔:
$ wget --no-check-certificate -c https://github.com/gnustep/tools-make/releases/download/make-2_9_1/gnustep-make-2.9.1.tar.gz
$ wget --no-check-certificate -c https://github.com/gnustep/libs-base/releases/download/base-1_29_0/gnustep-base-1.29.0.tar.gz
$ wget --no-check-certificate -c https://github.com/gnustep/libs-gui/releases/download/gui-0_30_0/gnustep-gui-0.30.0.tar.gz
$ wget --no-check-certificate -c https://github.com/gnustep/libs-back/releases/download/back-0_30_0/gnustep-back-0.30.0.tar.gz
雖然也可以直接拷貝 GNUstep 的 master 分支的原始碼來用。但該分支的原始碼比較不穩定,不建議使用。如果對 GNUstep 很有愛,想要幫 GNUstep 測試和除錯,可以自行玩玩看。
這裡的軟體版本號是實際到各個專案去查閱而得的,每隔一陣子就會變動。請不要死背這個版本號。
雖然筆者先前發給 GNUstep 官方團隊的 PR 被拒絕,但 GNUstep 過一陣子後的確修好了 GNUstep 在 MSYS2 上的臭蟲。由此可知,即使 PR 被拒絕,仍然可以對自由軟體間接做出貢獻。
然後將各個專案重新整理名稱,這是為了和 build-mingw64_nt (編譯用命令稿) 內的目錄名稱一致:
$ tar xf gnustep-make-2.9.1.tar.gz
$ mv gnustep-make-2.9.1 tools-make
$ tar xf gnustep-base-1.29.0.tar.gz
$ mv gnustep-base-1.29.0 libs-base
$ tar xf gnustep-gui-0.30.0.tar.gz
$ mv gnustep-gui-0.30.0 libs-gui
$ tar xf gnustep-back-0.30.0.tar.gz
$ mv gnustep-back-0.30.0 libs-back
安裝 GNUstep 相依性
切換到 Msys 終端機,執行以下命令稿:
$ ./tools-scripts/install-dependencies-mingw64_nt
安裝套件的過程中可能需要手動確認幾次,請自行完成。
編譯 GNUstep
切換到 MinGW64 終端機,執行以下命令稿:
$ ./tools-scripts/build-mingw64_nt
這時候會從頭到尾編譯整個 GNUstep。如果順利的話,就可以得到 GNUstep,會安裝在 MinGW64 環境下的 /usr/GNUstep 中。由於編譯時間比較久,可以喝杯咖啡休息一下。
但是,不一定每次編譯都會成功。目前該命令稿沒有檢查錯誤的機制,所以要自行檢查錯誤訊息。可以用 tee(1)
把錯誤訊息存下來再慢慢看。
(選擇性) 錯誤排除
編譯 GNUstep 時,最困難的就是錯誤排除。隨著 MSYS2 環境,每次編譯時有可能有不同的錯誤出現,要有自行勤找資料的精神來除錯。
例如,最新版本的 libxml2 造成 libs-base 的編譯錯誤:
GSXML.m: In function 'getEntityDefault':
GSXML.m:2674:22: error: 'xmlEntity' {aka 'struct _xmlEntity'} has no member named 'checked'
2674 | if (ret->checked == 0)
| ^~
GSXML.m:2676:22: error: 'xmlEntity' {aka 'struct _xmlEntity'} has no member named 'checked'
2676 | ret->checked = 1;
| ^~
GSXML.m: In function 'hasInternalSubsetFunction':
GSXML.m:2968:7: warning: '__htmlDefaultSAXHandler' is deprecated [-Wdeprecated-declarations]
2968 | has = TREEFUN(hasInternalSubset, (ctx));
| ^~~
In file included from C:/tools/msys64/mingw64/include/libxml2/libxml/threads.h:35,
from C:/tools/msys64/mingw64/include/libxml2/libxml/xmlmemory.h:222,
from C:/tools/msys64/mingw64/include/libxml2/libxml/tree.h:1310,
from GSXML.m:82:
解法方式是用 wget(1)
下載舊版的 libxml2:
$ wget -c https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-libxml2-2.10.4-1-any.pkg.tar.zst
將 libxml2 手動降級:
$ pacman -U mingw-w64-x86_64-libxml2-2.10.4-1-any.pkg.tar.zst
GNUstep 也是要依賴底層的 C 函式庫才能運作的,錯誤往往來自於兩者的程式碼不匹配。實務上不可能改 GNUstep 的程式碼。把相關的 C 函式庫降級倒是可以嘗試的作法。
讀者不一定會碰到相同的錯誤。還是得培養自己找尋資料、解決問題的能力。
自動載入 GNUstep 開發環境
在 MinGW 終端機下執行以下命令稿:
$ ./tools-scripts/setup-mingw64_nt
以後就可以用 GNUstep Make 編譯 Objective-C 程式。我們會在後文介紹 GNUstep Make 的使用方式。
編譯第一個 Objective-C 程式
用編輯器建立空白的 hello.m 文字檔案,加入以下內容:
#import <Foundation/Foundation.h>
#define PRINT(FORMAT, ...) \
fprintf(stdout, "%s\n", \
[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
int main(void)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
if (!pool)
return 1;
PRINT(@"Hello World");
[pool release];
return 0;
}
我們的目的是測試開發環境,不說明程式碼。
編譯並執行此範例程式:
$ gcc -o hello hello.m -lobjc -lgnustep-base -I /usr/GNUstep/System/Library/Headers -L /usr/GNUstep/System/Library/Libraries -fconstant-string-class=NSConstantString
$ ./hello.exe
Hello World
GNUstep 視為獨立的系統,不位於 GCC 的標準位置上,所以要加許多額外的參數。日後用 GNUstep Make 就可以改善這個情形。
無法順利執行 GNUstep 執行檔
請將 /usr/GNUstep/System/Tools 加到 PATH 變數中。若讀者的系統路徑和此路徑相異,請自行更改。
在 Windows 原生環境執行 GNUstep 程式
若要在 Windows 原生環境下執行編譯好的 GNUstep 程式,要附帶額外的動態函式庫 (DLL 檔)。以筆者的系統為例,可到 C:\msys64\usr\GNUstep\System\Tools 底下找所需的 DLL 檔。除此之外,在 MSYS2 的執行檔路徑 C:\msys64\mingw64\bin 等處也可能會有所需的 DLL。
因為 GNUstep 相依蠻多函式庫的,要手動逐一拷貝有點費工。筆者寫了個 shell 命令稿 deploy2win,可以簡化拷貝 DLL 的動作。有需要的讀者可以參考一下。