#navi_header|C言語系| Objective-Cの勉強を始めようと思って、適当にネットで漁ったHelloWorldをgccでコンパイルしたら上手く動かない。 で、調べ始めたらObjective-C/NeXT/OpenStep/MacOSXの歴史とかUniversalBinaryとかにまで広がってしまいましたが、ようやく収拾がついたのでまとめます。 環境: #pre||> Mac OS X (Lion), 10.7.2 Intel Core i5 64 ビットカーネルと拡張機能:有効 Xcode 4.2 $ gcc --version i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 ¥ (Based on Apple Inc. build 5658) (LLVM build 2336.1.00) ||< #more|| helloworld.m: #pre||> #import #import @interface HelloWorld : Object { } -(void) hello; @end @implementation HelloWorld -(void) hello { printf("Hello, Objective-C!\n"); } @end int main(int argc, char *argv[]) { HelloWorld *o = [[HelloWorld alloc] init]; [o hello]; [o free]; return 0; } ||< コンパイル: #pre||> [msakamoto:ex01]$ gcc -o helloworld helloworld.m -lobjc helloworld.m: In function ‘main’: helloworld.m:19: warning: ‘HelloWorld’ may not respond to ‘+alloc’ helloworld.m:19: warning: (Messages without a matching method signature helloworld.m:19: warning: will be assumed to return ‘id’ and accept helloworld.m:19: warning: ‘...’ as arguments.) helloworld.m:19: warning: no ‘-init’ method found helloworld.m:21: warning: ‘HelloWorld’ may not respond to ‘-free’ ||< * 結論 64bit化に伴い、レガシーなObjectクラスの実装については64bit用のバイナリでは提供されなくなったようです(Appleからの明確なアナウンス情報が見つからなかった)。このため、"objc/Object.h"で定義されている"Object"クラスのallocメソッドなどが見つからないため、上記のようなwarningになっているようです。エラーではなくwarningというのも面白いけど・・・。 gccはデフォルトではホストマシンのアーキテクチャでバイナリを生成します。今回は64bitカーネルで動作しているため、64bit用のライブラリとリンクするようにビルドされた結果、上述のような状況に陥ったようです。 ** 解決策その1:素直にNSObjectを使う。 素直にNSObjectを使いましょう。仮にMac以外のプラットフォームでのコンパイルを考慮したとしても、最近であればlibFoundationと組み合わせればNSObjectなども普通に使える・・・らしい、です。 helloworld2.m: #pre||> #import #import @interface HelloWorld : NSObject { } -(void) hello; @end @implementation HelloWorld -(void) hello { printf("Hello, Objective-C!\n"); } @end int main(int argc, char *argv[]) { HelloWorld *o = [[HelloWorld alloc] init]; [o hello]; [o release]; return 0; } ||< コンパイル&実行: $ gcc -o helloworld2 helloworld2.m -framework Foundation $ ./helloworld2 Hello, Objective-C! ** 解決策その2:"-arch i386"でコンパイル レガシーなObjectクラスの実体は、/usr/lib/libobjc.A.dylib に含まれています。今回はIntel版のMacOSXということもあり、i386とx86_64の2つのバイナリが含まれたUniversalBinaryになっていました。 #pre||> $ file libobjc.A.dylib libobjc.A.dylib: Mach-O universal binary with 2 architectures libobjc.A.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64 libobjc.A.dylib (for architecture i386): Mach-O dynamically linked shared library i386 ||< このうち、i386版の方にはObjectのallocなど各種実装が含まれていました。 i386版: #pre||> [msakamoto:lib]$ nm -arch i386 libobjc.A.dylib | fgrep "[Object" 00017950 t +[Object allocFromZone:] 0001791c t +[Object alloc] 000179f0 t +[Object class] 00017f63 t +[Object conformsTo:] 00018092 t +[Object descriptionForInstanceMethod:] 000179d7 t +[Object free] 0001789b t +[Object initialize] 0001823c t +[Object instanceMethodDescFor:] 00017beb t +[Object instanceMethodFor:] 00017b1c t +[Object instancesRespondTo:] 0001799e t +[Object name] 000178c8 t +[Object new] ... ||< 一方、x86_64版にはObjectクラスの実装がほとんど含まれていません。 $ nm -arch x86_64 libobjc.A.dylib | fgrep "[Object" 000000000001d3d7 t +[Object class] 000000000001d3ce t +[Object initialize] (これだけ。) 以下の記事より、推測ですが32bitバイナリは"__OBJC2__"マクロ無しでビルドされ、64bitバイナリでは"__OBJC2__"マクロ有りでビルドされているのかも・・・いやそうとも限らないか・・・真相は調べきれませんでした。 - 2010-08-05 - 日記帳 -- http://d.hatena.ne.jp/sa-y/20100805 長くなりましたが、i386版のライブラリにObjectの実装があるならi386版でビルドすればよさそうです。 $ gcc -arch i386 -o helloworld helloworld.m -lobjc $ ./helloworld Hello, Objective-C! * Object, NSObjectの歴史的な経緯 + Objective-C自体はSmalltakを参考に開発されたC言語ベースのOOP(1980s) + NeXTSTEPでの開発言語に採用された。この時点ではまだ"Object"がルートクラスだった。 + Solarisに移植するため、NeXTSTEPからOS以外の部分をAPIとして切り出した。 ++ この時初めて"NS"が頭につくようになった。・・・と思われる。 ++ この辺り(ちょっとあいまい)でAppKitとFoundationの二種類にAPIが大別されたが、両方共ごっそりと現在のCocoaに引き継がれ、包含されている。 ++ FoundatinにNSObjectが含まれる。恐らくNSObjectの誕生はこの辺り。 + 1996年、AppleによりNeXTが吸収され、OpenStepの後継としてコードネームRhapsodyというOSの開発が始まる。 ++ OpenStepベースのライブラリサポートは"YellowBox"と呼ばれる。これが現在のCocoaになる。 ++ RhapsodyではMacOS8までのバイナリを動作させる"BlueBox"という技術も搭載されていた。 ・・・というわけで、OpenStep以降独自に発展していったOpenStep -> YellowBox -> Cocoaの血脈にNSObjectは含まれている次第。 ただしサポート自体はMacOSX 10.5(Leopard)までは続いていたようで、似たような状況「を使いたいけどうまくいかない・・・」というのは10.6以降に発生しているみたいです。この辺りは丁度OS全体の64bit化への切り替えとも重なっており、それによりObjectの実装に関連した問題が表面化したのかもしれません。なんとも分かりませんが・・・。ただ、似たような現象について取り上げられたスレッドや記事の殆どで、「Mac OS 10.5とかの昔のバージョンでは動いていたのに、10.6とか最新のOSXだと動かない!」というような内容が書かれています。 ** 参考:NSObjectの実体はどこ? NSObjectのコードを格納しているライブラリを探してみます。まず、helloworld2がロードするライブラリを確認します。 #pre||> $ otool -L helloworld2 helloworld2: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation ¥ (compatibility version 300.0.0, current version 833.20.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation ¥ (compatibility version 150.0.0, current version 635.15.0) ||< Foundationファイルを調べてみます。 #pre||> $ nm /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation ... 0000000000116df4 t +[NSObject(NSObject) implementsSelector:] 0000000000002b89 t +[NSObject(NSObject) initialize] 0000000000116d85 t +[NSObject(NSObject) instancesImplementSelector:] 00000000000944f2 t +[NSObject(NSObject) load] 0000000000116e6b t +[NSObject(NSObject) poseAsClass:] 000000000002ce54 t +[NSObject(NSObject) setVersion:] 000000000002ca96 t +[NSObject(NSObject) version] ... ||< CoreFoundationについても確認してみます。 #pre||> $ nm /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation | less ... 0000000000049320 t +[NSObject alloc] 000000000012fbc0 t +[NSObject allowsWeakReference] 000000000012fbe0 t +[NSObject autorelease] 0000000000055fd0 t +[NSObject class] 000000000009b4b0 t +[NSObject conformsToProtocol:] 000000000009b2f0 t +[NSObject copyWithZone:] 000000000012fc00 t +[NSObject copy] ... ||< Foundationは"NSObject(NSObject)"という表記になりましたが、CoreFoundationは"NSObject"のままです。 細い差異が多少あるものの、この辺のライブラリにNSObjectなどのCocoa Foundationの実体が収められているようです。 * 参考資料 - 2010-08-05 - 日記帳 -- http://d.hatena.ne.jp/sa-y/20100805 --- 全く同じ現象。このスレッドで"__OBJC2__"を知りました。 - Snow Leopard breaks GCC?: Apple Support Communities -- https://discussions.apple.com/thread/2140085 --- 全く同じ現象。このスレッドで「-arch i386を使うといいよ」とあり、これが解決につながりました。 - Object's +alloc and -init methods in 10.6.4, as opposed to 10.5.8 -- http://lists.apple.com/archives/objc-language/2010/Jun/msg00043.html --- 全く同じ現象。どうも10.5 - 10.6の間でObject関連の変更が行われたようです。 - NSObject vs Object -- http://objectmix.com/c/177907-nsobject-vs-object.html --- NSObjectとObjectの違い、なぜObjectがレガシーでdeprecatedとなり、NSObjectを使うべきなのかが端的にまとめられています。 - OBJC_API_VERSION and __OBJC2__ « JongAm's blog -- http://jongampark.wordpress.com/2008/04/26/objc_api_version-and-__objc2__/ --- こちらに"__OBJC2__"について「This distinguishes between the legacy (i386+ppc) version and the modern (x86_64+ppc64) version.」とあり、レガシーとモダンのABIバージョンをベースとしているという記述があります。 - ChangeLog.apple (Apple版gccのChangeLog) -- http://opensource.apple.com/source/gcc/gcc-5490/gcc/ChangeLog.apple --- 2006-02-15 に"Define __OBJC2__ for objc's new abi."とあります。 - 今日の総括ぶろぐ: Linuxでも使えるじゃん、NSObject -- http://blogs.dion.ne.jp/clubimpreza/archives/6863498.html - libFoundation - MacOS X Foundation | Free Development software downloads at SourceForge.net -- http://sourceforge.net/projects/libfoundation/ --- 最近のLinux(Fedora, Ubuntu)とかだとGNUstepではなくこちらが主流らしい。 他: - Objective-C入門 -- http://wisdom.sakura.ne.jp/programming/objc/index.html - Universal Binary -- http://hp.vector.co.jp/authors/VA009278/misc/univ.html 各種Wikipediaへのショートカット - Objective-C -- http://en.wikipedia.org/wiki/Objective-c -- http://ja.wikipedia.org/wiki/Objective-C - NeXT -- http://en.wikipedia.org/wiki/NeXT - NeXTSTEP -- http://en.wikipedia.org/wiki/NeXTSTEP - OpenStep -- http://en.wikipedia.org/wiki/OpenStep - GNUstep -- http://en.wikipedia.org/wiki/GNUstep - ApplicationKit -- http://en.wikipedia.org/wiki/Application_Kit - Foundation Kit -- http://en.wikipedia.org/wiki/Foundation_Kit - Rhapsody -- http://en.wikipedia.org/wiki/Rhapsody_(operating_system) - History of Mac OS X -- http://en.wikipedia.org/wiki/History_of_Mac_OS_X - Cocoa API -- http://en.wikipedia.org/wiki/Cocoa_(API) -- http://ja.wikipedia.org/wiki/Cocoa - Carbon API -- http://en.wikipedia.org/wiki/Carbon_(API) -- http://ja.wikipedia.org/wiki/Carbon - Classic Environment -- http://en.wikipedia.org/wiki/Classic_(Mac_OS_X) #navi_footer|C言語系|