2012/03/23

在Windows上寫Objective-C程式(使用GNUstep與Clang、LLVM)

之前我寫了一篇Objective-C on Windows,以GNUstep在Windows XP上寫Objective-C程式,但是Objective-C已經加了很多新東西,而GNUstep裡的gcc並不提供,所以,這篇要介紹GNUstep,再加上新一代的編譯器架構Clang與LLVM(這也是Apple在新版Xcode裡預設使用的編譯器),這樣就能有Objective-C 2.0的功能,以及block與ARC(automatic reference counting)。

問:想開發iPhone或iPad或Mac的軟體,該怎麼辦?
答:使用Apple官方的軟體開發工具Xcode,只要到Apple公司的開發者網站,註冊一下(免費),即可下載最新版的Xcode。Xcode只能在Mac OS X(作業系統)上運行,所以要買一台Mac機器(硬體)。

PS 最新版的Xcode可以直接從Mac App Store下載。

問:哇,這麼多種漂亮的Mac,應該買哪一台啊?
答:有錢的話就買最貴的那一台*_*。


問:什麼是Xcode?
答:Xcode是Apple公司官方的軟體開發工具組,可開發在Mac、iPhone、iPad的軟體,是一個總稱,裡面包含很多東西,有整合式開發編輯器(IDE,也叫做Xcode)、視覺化使用者介面開發工具(Interface Builder)、compiler、linker、debugger(gcc、gdb、llvm...)等等、還有模擬器,以及各種framework(函式庫、類別庫、API)。

這是Xcode IDE,負責管理專案檔案、編輯、以及各種設定,從這裡進行編譯除錯執行。


這是Interface Builder,視覺化使用者介面設計,使用拖拉放的方式來操作。(在Xcode 4以前是支獨立的軟體,之後Xcode IDE已經整合Interface Builder。)


這是模擬器,不用買一支iPhone也可以進行開發iPhone軟體喔。


也就是說,如果你有一台Mac電腦(花錢買),下載Xcode(免費下載)後,就可以開始開發,在模擬器上執行看到成果。但是,如果想在iPhone實機上執行你寫的程式的話,那就要加入Apple的iOS Developer Program(要錢,一年要付$99),至於加入、付錢、設定、下載軟體到手機上的過程,本篇不介紹。

問:想先學學Objective-C程式語言,還不想砸錢買Mac,有辦法在Windows上寫Objective-C程式嗎?
答:有,就是這篇的重點了。

問:聽說gcc可以編譯Objective-C,所以在Windows上裝cygwin,裡面有gcc,就可以寫Objective-C程式了?
答:cygwin的gcc的確可以編譯Objective-C程式,但光裝cygwin並不會有任何的物件類別庫(library、class library、framework),所以也就沒有各種基本的物件類別可以用,沒有NSLog可以呼叫(想像成c的printf);沒有NSObject可以繼承,讓你沒辦法立即開始寫自己的物件;沒有Foundation.h(想像成c的stdio.h)連preprocessor都過不去,更別提compiler了。所以只有compiler是不夠的。而且,一般版本的gcc裡頭的Objective-C部分,很舊,沒有許多Apple加入的新功能。

同樣的,若只有clang(llvm)也不夠。

問:所以除了compiler還需要?
答:還需要一套framework,裡面會有基本的物件類別。如果是裝Xcode就會有Cocoa for Mac、Cocoa Touch for iPhone。Cocoa大致上分為Foundation跟AppKit兩個部分,AppKit是GUI元件與較高階的元件,而Foundation就是一堆基本的物件類別,例如NSObject、NSString、NSArray、NSNumber等等;而Cocoa Touch分成Foundation跟UIKit,差不多的意思。

問:聽說Cocotron...?
答:Cocotron也是一個Objective-C的開發環境,其目標是讓開發出來的軟體可以在各種平台上執行,例如Windows,但其本身還是要搭配Xcode使用,所以不符本篇主題。

問:那所以咧?
答:使用GNUstep,可在unix-like與Windows上使用,有Cocoa API,也有一些開發工具(類似Xcode提供的工具)可以用,但本篇重點是在Windows上寫一支Objective-C的hello world!程式,所以會用命令列模式shell,只會使用compiler的部份(也是gcc),以及鏈結Cocoa API中Foundation的部份,也就是說不理會AppKit的部分,也不會介紹GNUstep提供的開發工具(Gorm, ProjectCenter...)。

因為GNUstep裡的gcc,其Objective-C的部份很舊了,無法編譯Objective-C的新功能與特色,所以除了GNUstep,我們還需要安裝clang(llvm)。

問:GNUstep可在哪些版本的Windows上跑?
答:官方網站上說在WinXP與Win2K測試過,我的電腦是Windows XP。

問:怎麼安裝GNUStep?
答:到GNUstep網站的Windows下載區,下載下面三個安裝套件。
1. GNUstep MSYS System,53MB,基本環境與命令列shell。
2. GNUstep Core,9MB,函式庫、類別庫。
3. GNUstep Devel,44MB,開發工具,gcc、make、gdb等等。
注意:請按照順序安裝。


把三個都安裝在同一個目錄(預設值是C:\GNUstep),安裝時也都是按Next即可。安裝後執行「開始-程式集-GNUstep-shell」,會出現一個命令列畫面,恭喜你,已經成功了一半。


問:怎麼安裝clang(llvm)?
答:
首先,我們將下載原始碼自行編譯,編譯時需要很多工具,前面安裝的GNUstep幾乎都有了,但還缺個python,請到python官方網站下載頁面,下載python的windows版,我下載的是2.7.2版。安裝後,修改環境變數(開始-設定-控制台-進階-環境變數),將「C:\Python27」(這是預設的安裝路徑)加入「PATH」。

然後,開啟「程式集-GNUstep-shell」,依序執行下列指令:

$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

$ cd llvm/tools

$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang

第一道指令會下載llvm(約106 MB),第二道指令切換目錄,第三道指令下載clang(約65 MB)。

然後,我們需要修改clang一些寫死的路徑,請用文字編輯器開啟「C:\GNUstep\msys\1.0\home\username\llvm-tools-clang-lib-Frontend\InitHeaderSearch.cpp」,尋找字串"FIXME: temporary hack: hard-coded paths.",大約在第215行附近的地方,加入底下這幾行。

...
// FIXME: temporary hack: hard-coded paths.
AddPath("C:\\GNUstep\\include", System, true, false, false);
AddPath("C:\\GNUstep\\msys\\1.0\include", System, true, false, false);
AddPath("C:\\GNUstep\\lib\\gcc\\mingw32\\4.6.1\\include", System, true, false, false);
AddPath("C:\\GNUstep\\lib\\gcc\\mingw32\\4.6.1\\include\\c++", System, true, false, false);
AddPath("C:\\GNUstep\\GNUstep\\System\\Library\\Headers", System, true, false, false);
//AddPath("/usr/local/include", System, true, false, false);
break;
....

記得要把原有的AddPath("/usr/local/include", System, true, false, false);拿掉。
 
存檔後,接下來就是要進行編譯了。
$ cd ~/llvm && mkdir build && cd build

$ ../configure --enable-optimized --enable-targets=host-only

$ make

$ make install
第一行切換目錄到llvm底下,並建立一個build目錄,我們將把編譯後的東西放在這個目錄下。
第二行做一些設定。(需要一點時間,看你的機器多快。)
第三行進行編譯。(需要花很多時間,看你的機器多快。) 
第四行進行安裝。雖然會出現groff的錯誤,但沒關係。
 
安裝後,你可以執行
$ clang --version
檢查會不會秀出版本編號。 
clang version 3.1 (trunk 153251)
Target: i686-pc-mingw32
Thread model: posix 

問:接下來,怎麼編譯執行一支hello, world!程式呢?
答:
$ cd ~
$ mkdir hello
$ cd hello
在家目錄下建立一個新目錄hello。我們將放入兩支檔案。
家目錄大概是C:\GNUstep\msys\1.0\home\username,自己找找。

首先是hello.m,用你喜歡的編輯器寫程式,大致內容如下:

#include <Foundation/Foundation.h>

int main(int argc, char * argv[]){
    @autoreleasepool{
        NSLog(@"Objective-C has ARC now, yeah.");
    }
    return 0;
}

另一支檔案是GNUmakefile,內容如下:
include $(GNUSTEP_MAKEFILES)/common.make

TOOL_NAME = hello
hello_OBJC_FILES = hello.m

include $(GNUSTEP_MAKEFILES)/tool.make

然後以這道指令進行編譯與連結:

$ make CC=clang

成功後,執行檔會在hello目錄的子目錄obj裡。

$ ./obj/hello.exe

應該就能看到輸出"Objective-C has ARC now, yeah."了。

恭喜你。

根據我的測試,property與fast enumeration都沒問題。ARC也可以。garbage collection與non-fragile instance variables我沒測試。

問:block呢?
答:需要開啟編譯器選項-fblocks,請修改C:\GNUstep\GNUstep\System\Library\Makefiles\common.make,尋找"INTERNAL_OBJCFLAGS = ",在後面加入"-fblocks"。

這麼一來,底下這支使用block的程式,應該就能成功編譯並執行了。
#import <Foundation/Foundation.h>

int main (int argc, char * argv[])
{
   @autoreleasepool {
      void (^print_message)(void) =
         ^(void) {
             NSLog (@"hello, block.");
          } ;
      printMessage ();
   }
   return 0;
}

問:Objective-C與iOS的學習資源?
答:請看另一篇


參考文件:
Solarian Programmer's Clang and Objective-C on Windows

20 comments:

  1. Anonymous13/6/12 20:45

    在跑 configure 的時候發現多支木馬威脅...?!
    是正常現象嗎??
    (~\llvm\build\conftest.exe;~\llvm\build\projects\sample\conftest.exe)

    ReplyDelete
  2. 這應該是防毒軟體誤報吧,只要你是用svn從llvm網站抓下原始碼來編譯,應該不會有病毒。

    你是用什麼防毒軟體?

    我用avast,有時有會出現誤報(極少)。

    ReplyDelete
  3. Anonymous20/9/12 14:07

    XYPoint.m, Rectangle.m, RectTest.m 檔案一起 compile, GNUmakefile 如何寫 ?

    ReplyDelete
  4. hello_OBJC_FILES = hello.m,
    把hello.m改成你想要compile跟link的.m檔名。

    ReplyDelete
  5. 我再執行$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm


    的步驟不小心把他案調 請問要怎麼補救?

    ReplyDelete
    Replies
    1. 你是說Ctrl-C取消嗎?

      $ svn co會把抓下來的東西放在你指定的"llvm"目錄裡,你就把"llvm"刪除,然後再重新執行指令即可。

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. 我的電腦是Windows 7 旗艦版我安裝 gnustep-msys-system-0.29.1-setup.exe 或是 0.30版都會遇見無法寫入 F:\GNUstep\msys\1.0\bin\info.exe的error message, 所以我只好試試看gnustep-msys-system-0.28.1-setup.exe,結果成功了,測試五次都一樣結果
    是否GNU在包裝時就有問題?

    ReplyDelete
    Replies
    1. 咳咳,我沒有Win7。

      我不知道包裝有無問題,我測試的版本是gnustep-msys-system-0.29.0-setup.exe。在xp下並無問題。

      搜尋"windows 7 gnustep",找到的安裝教學文章,也有些簡體文章用的是0.30版,並無問題。

      我已經沒有在Windows下開發Objective-C了,還是買台mac吧。

      Delete
    2. 感謝您如此熱誠分享,我是準備買台MAC.只是目前才開始K Object-C,暫時先用Windows玩玩
      那知遇到這的多麻煩;無論如何,實在太感謝您

      Delete
    3. 咳咳,實際上,我只是記錄一下,主要是留待我以後有需要的時候看。

      聽說可以在windows上安裝mac os x,但我沒試過。
      我曾經試過在linux上安裝clang/llvm,但版本不夠新,而且該有的framework也沒有。

      有錢的話就買台mac吧。

      Delete
  8. 有幾個問題請問一下
    clang --version出現了 sh:command not found.這是為何?
    另外$ make CC=clang後在hello目錄下有出現子目錄obj,但是沒有執行檔。
    小弟不知道原因出現哪?請協助,謝謝。
    PS:我的windows是vista home

    ReplyDelete
    Replies
    1. shell找不到這支指令,可能是因為PATH沒設好吧,還是安裝不完全,所以找不到clang。

      看不到執行檔,那就是沒成功囉,請問有哪些錯誤訊息。如果之前clang --version執行不成功,那當然就沒辦法編譯出執行檔。

      我沒有vista。

      Delete
  9. 感謝回覆~~重做了一次,錯誤的訊息我以printscreen方式擷取下來,寄到你的mail給你,麻煩你了,謝謝。

    ReplyDelete
  10. $ ../configure --enable-optimized --enable-targets=host-only
    做到這邊就出錯了@@
    ypass these sanity checks.disable-compiler-version-checks to configure toade
    出現了這樣的錯誤訊息 要怎麼做呢?
    小弟剛學所以拜託不吝賜教><

    ReplyDelete
    Replies
    1. LLVM & Clang可能提高需要的gcc版本,而你系統內的gcc版本不符合,所以出錯。

      可試著安裝4.7甚至4.8的gcc,
      或是加入參數--disable-compiler-version-checks,跳過檢查編譯器版本的步驟,但這麼做不保證後果可行。

      Delete
  11. Raise your cup, say cheers to the moon, look down on the ground, the shadow is also drinking with me. I'm not a lonely drinker. 舉杯邀明月,對影成三人?

    ReplyDelete
  12. I got problem when i reach "$ ../configure --enable-optimized --enable-targets=host-only"
    it said that "The LLVM project no longer supports building with configure & make."
    pls help, how can i set the configuration?

    ReplyDelete
    Replies
    1. This post is pretty old. And I don't play related stuff anymore.

      Maybe you can try to get the older version of LLVM.

      Delete