【在主画面加入捷径】
       
【选择语系】
繁中 简中

在 Windows 平台上以 GNUstep 建立开发 Objective-C 程序的开发环境

【赞助商连结】

    前言

    苹果公司 (Apple Inc.) 没有将 Cocoa 框架放到其他平台上,日后应该也不会放。若想要在 Windows 上练习 Objective-C,可以用 GNUstep,这是一个 Cocoa 的自由软件再制版本。GNUstep 有提供 Windows 版本的安装档 (installer),但也可以自行从源代码来编译;我们两种方法都会介绍,并且比较其差异。

    一般的方法,使用现有的 GNUstep 安装程序

    GNUstep 己经预先包好给 Windows 用的安装档,下载后即可安装使用。到 GNUStep for Windows 网站,依序下载并安装以下套件:

    • GNUstep MSYS System (MinGW + MSYS 环境)
    • GNUstep Core (函式库)
    • GNUstep Devel (头文件和开发工具)

    其他套件是选择性的,可装可不装。

    默认情形下,这些套件会安装到 C:\GNUstep 目录中。如果终端机无法侦测到 GNUstep 内附的 GCC,可以将 C:\GNUstep\bin 加入 PATH 环境变量中;但实际编译 Objective-C 程序时,会用到 GNUstep 安装程序附的 MSYS 环境,我们将于后文说明。

    选择适用于 GNUstep 的编辑器 (editor) 或整合式开发环境 (IDE)

    由于 Objective-C 的主流平台是 Mac,在 Windows 并没有什么大型 IDE 可用。AtomVSCode 对 Objective-C 有语法高亮 (syntax highlighting) 等基本支援。EditRocket 是一个商业编辑器,可试用 30 天后再买,有兴趣的读者可自行试用。

    撰写 GNUstep 版本的 Hello World 程序

    Hello World 程序是用来确认开发环境可正常运作,一开始不用急着了解程序的语义。本节建立一个 Objective-C 版本的 Hello World 程序。

    用编辑器或 IDE 建立新的文件 *hello.m*,加入以下内容:

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[])
    {
        @autoreleasepool {
            NSLog(@"Hello World");
        }
    
        return 0;
    }
    

    现阶段 Hello World 程序的用途是确认开发环境可正常运作,暂时不用纠结在语法细节上,我们会于后文介绍其语法。

    撰写 hello.m 后,使用以下指令来编译及执进程式:

    C:\path\to\file> gcc -o hello hello.m -IC:\GNUstep\GNUstep\System\Library\Headers -LC:\GNUstep\GNUstep\System\Library\Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
    C:\path\to\file> .\hello.exe
    2019-03-11 13:37:08.184 Main[10:10] Hello World
    

    由于 GNUstep 不是位于 MinGW 的标准路径上,所以我们要以 -I 指定头文字档 (header) 的位置,以及 -L 指定二进位函式库的位置。

    读者一定会觉得这个指令很长,每次都要逐字打相当繁琐。GNUstep 提供 GNUstep Make,这是一套以 Makefile 为基础的项目设定框架,用来简化编译 Objective-C 程序的过程,我们将于后文介绍这个软件。

    另外,由于 NSLog 是用于纪录档 (log) 的函式,故会跑时间戳记 (time stamp) 出来,和传统上 C 语言的 printf函数略有不同。

    替代的方法,自行从源代码编译及安装 GNUstep

    GNUstep 内附的 MinGW + MSYS 开发环境比较旧,不若新版的 MSYS2 来得好用;比起原本的 MinGW,MSYS2 引入源自于 Arch Linux 的 pacman 套件管理程序以及许多自由软件在 Windows 上的移植品,让 C (或 C++) 的开发更加方便。我们可以利用 MSYS2 内附的 GCC 来编译 GNUstep,藉此建立 GNUstep 开发环境。

    Windows 使用者多习惯使用预编好的安装程序来安装软件,甚少自行编译软件;但对类 Unix 系统使用者来说,编译软件是常做的动作,而且类 Unix 系统对这方面支援比较好一些。笔者使用的主机规格是 Intel i7-8550U 笔电版 + 8GB 内存,运行 Windows 10 家用版;在这样的环境下,完整编译一次约半小时至一小时左右。编译中大型软件通常无法一步到位,还是要有一些试误精神,笔者将安装过程纪录下来,希望可以减少读者试误的时间。

    MSYS2 有三个终端机环境,先开启 MSYS 环境。建立一个目录 (directory),因为我们会抓数个软件源代码。参考以下指令:

    $ mkdir gnustep
    $ cd gnustep
    

    接下来的操作,都会在此工作目录下。

    用 Git 下载以下项目:

    $ git clone https://github.com/gnustep/tools-make
    $ git clone https://github.com/cwchentw/libs-base.git
    $ git clone https://github.com/gnustep/libs-gui
    $ git clone https://github.com/gnustep/libs-back
    $ git clone https://github.com/cwchentw/tools-scripts.git
    

    在这五个项目中,前四个项目是 GNUstep 实际的函式库和工具软件,而第五个项目则是一些跑编译及安装 GNUstep 的脚本。眼尖的读者会发现其中几个项目的来源不是 GNUstep 上游,而是笔者 fork 出来的版本,因为这些 fork 出来的项目是笔者实际修改及安装的版本,目前还没有被 GNUstep 开发团队接受。

    tools-scripts 中有针对 32 位元和 64 位元的 MSYS2 所用的安装相依套件脚本,读者视自己需求择一使用即可。这里以 64 位元的脚本为例:

    $ ./tools-scripts/install-dependencies-msys2-64bit
    

    这个 (修改过的) 脚本会自动更新 pacman 套件数据库并安装相依的套件,这个步骤应该不会太久。

    在实际编译 GNUstep 前,要先 hack 一下 MSYS2 的系统头文字档,这是笔者试误出来的笔记。

    C:\msys64\mingw64\x86_64-w64-mingw32\include\winnetwk.h 的第 124 行第 80 个字符似乎有 bug,应将 BOOL 改为 WINBOOL

    C:\msys64\mingw64\x86_64-w64-mingw32\include\shlwapi.h 在使用 Objective-C 时,无法顺利编译。暂时的 workaround 是在该头文件的前面加入以下内容:

    #ifndef _INC_SHLWAPI
    #define _INC_SHLWAPI
    
    #include <_mingw_unicode.h>
    #include <winapifamily.h>
    
    /* Some kludge for Obj-C.
       For Obj-C the 'interface' is a keyword, but interface is used
       in midl-code too.  To resolve this conflict for at least the
       main windows API header, we define it here temporary.  */
    #ifdef __OBJC__
    #pragma push_macro("interface")
    #undef interface
    #define interface struct
    #endif
    

    为了怕污染整个命名空间,要在尾端加入以下内容:

    /* Restore old value of interface for Obj-C.  See above.  */
    #ifdef __OBJC__
    #pragma pop_macro("interface")
    #endif
    
    #endif
    

    修改完这两处后,应该可以顺利编译 GNUstep 了 (希望如此)。

    关掉原本的 MSYS 终端机,视自己的需求重开一个 MinGW 32 bit 或 MinGW 64 bit 终端机,以本文来说,就是 MinGW 64 bit 终端机。在这两个终端机中编译的程序是 Windows 系统原生程序,而且这两个终端机也可以各自和 Windows 系统目录互通,其工作原理是在这个环境中编译好的程序丢到 Windows 目录下使用。

    开好 MinGW 64 终端机后,重新回到 gnustep 目录的根目录,输入以下指令:

    $ ./tools-scripts/windows-build
    

    如果顺利的话,这个指令会依序将 GNUstep 的四个子项目编译并安装到 C:\GNUstep 目录上。我们先前有提过,在笔者的笔电上,整个编译过程约半小时至一小时,所以可以先去做其他的事。编译 GNUstep 时把主机上除了 MSYS2 以外的应用程序都关掉的话,编译速度会快得多,因为有足够的内存,不会动到硬盘缓存。

    如果发生错误的话,就不要一直重试了;错误原因没有排除的话,仍然会发生错误,不会自动修好。这时候建议将 tools-scripts/windows-build 内的指令逐一贴到终端机上,慢慢看是那个环节发生了问题。如果错误成因在 GNUstep 子项目本身的话,可以将该项目 fork 一份,进行修改后发出 PR (pull request),若被 GNUstep 开发团队接受的话,代表读者也替 GNUstep 项目尽了一些心力。

    最后说明一下,由于 MSYS2 设计成使用动态链接函式库 (DLL),笔者目前没有找到可以透过 MSYS2 编译静态可执行文件的方法。透过 MSYS2 编译出来的 GNUstep 所编译的 Objective-C 程序同样也是透过动态链接来链接 GNUstep函数库。这时候可以到 C:\GNUstep\GNUstep\System\Tools 找所需的 DLL;将 DLL 和可执行文件放在同一个目录内即可。

    结语

    在本文中,我们为读者介绍了两种在 Windows 平台上建立 GNUstep 开发环境的方式。使用 GNUstep 安装程序很简单,但其内附的 MinGW 和 MSYS 环境相对旧;自行从源代码编译和安装 GNUstep 就可以搭配 (较新的) MSYS2 开发环境,但是编译出来的可执行文件使用动态链接。读者应该权衡两种方式的利弊得失,选择适合自己的方式。

    在试用 Windows 平台的 GNUstep 一段时间后,会发现即使正确地编译和安装 GNUstep 开发环境,有时候仍然会碰到一些小问题;有些问题可以自行排除,有些问题到最后仍然无法解决。有时候把同样的程序代码放到 GNU/Linux 平台的 GNUstep 环境去跑,发现程序就可以正常执行了。或许对自由软件基金会来说,Windows 支援不是该项目首要的目标。如果读者时常碰到一些非程序代码本身的问题,或许可以转用 Paiza 云端开发平台或其他以 GNU/Linux 为基础的开发平台,以减少不必要的问题。

    【赞助商连结】