2013/06/15

[obc]mainはC風でしか書けなさそうなので、Objective-C風に書いた関数を呼び出してみよう。


#import <stdio.h>

@interface Hell
+ (void)print;
@end

@implementation Hell
+ (void)print
{
 printf("Hell\n");
}
@end

int main(void)
{
 [Hell print];
 return 0;
}
yebisu:objc hirokuma$ gcc -o tst 1.m
Undefined symbols for architecture x86_64:
  "__objc_empty_cache", referenced from:
      _OBJC_METACLASS_$_Hell in ccJImdLx.o
      _OBJC_CLASS_$_Hell in ccJImdLx.o
  "__objc_empty_vtable", referenced from:
      _OBJC_METACLASS_$_Hell in ccJImdLx.o
      _OBJC_CLASS_$_Hell in ccJImdLx.o
  "_objc_msgSend", referenced from:
      _main in ccJImdLx.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

リンクエラーだ。
オブジェクトだけ作ってみよう。
yebisu:objc hirokuma$ gcc -c 1.m
yebisu:objc hirokuma$ ls
1.m     1.o
yebisu:objc hirokuma$ nm 1.o
0000000000000000 t +[Hell print]
00000000000001c0 s +[Hell print].eh
00000000000001a8 s EH_frame0
000000000000006f s L_.str
0000000000000082 s L_OBJC_CLASS_NAME_0
0000000000000074 s L_OBJC_METH_VAR_NAME_0
000000000000007a s L_OBJC_METH_VAR_TYPE_0
0000000000000170 S _OBJC_CLASS_$_Hell
0000000000000148 S _OBJC_METACLASS_$_Hell
                 U __objc_empty_cache
                 U __objc_empty_vtable
0000000000000030 T _main
00000000000001f0 S _main.eh
                 U _objc_msgSend
                 U _puts
0000000000000098 s l_OBJC_$_CLASS_METHODS_Hell
0000000000000100 s l_OBJC_CLASS_RO_$_Hell
00000000000000b8 s l_OBJC_METACLASS_RO_$_Hell

えーっと・・・、「U」が外部を参照しているとかだっけ。
putsは、引数無しのprintf()だから置き換えられてるのかな。
そこはgccがlibcをリンクするから解決するけど、objc部分はライブラリを指定せんといかんと言うことか。
うーん、Objective-Cのライブラリ名ってなんだろう・・・。
yebisu:objc hirokuma$ gcc -o tst 1.m -lobjc
yebisu:objc hirokuma$ ./tst
Hell

あ、通った。
yebisu:objc hirokuma$ nm tst
0000000100000e70 t +[Hell print]
0000000100001170 S _NXArgc
0000000100001178 S _NXArgv
0000000100001148 S _OBJC_CLASS_$_Hell
0000000100001120 S _OBJC_METACLASS_$_Hell
0000000100001188 S ___progname
0000000100000000 T __mh_execute_header
                 U __objc_empty_cache
                 U __objc_empty_vtable
0000000100001180 S _environ
                 U _exit
0000000100000ea0 T _main
                 U _objc_msgSend
                 U _puts
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000e30 T start

よくわからんが、「Objective-Cはメソッド呼出じゃなくてメッセージ送信」というのだが、動作としてそう作ってるんだな。
もちろん、print()をC風にすると関数呼び出しになる(と思う)。
#import <stdio.h>

void print()
{
 printf("Hell\n");
}

int main(void)
{
 print();
 return 0;
}
yebisu:objc hirokuma$ nm tst
0000000100001050 S _NXArgc
0000000100001058 S _NXArgv
0000000100001068 S ___progname
0000000100000000 T __mh_execute_header
0000000100001060 S _environ
                 U _exit
0000000100000ed0 T _main
0000000100000eb0 T _print
                 U _puts
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000e70 T start


拡張子を.mmにすると、C++もいけるらしい。
#import <stdio.h>

class Hell {
public:
 static void print();
};

void Hell::print()
{
 printf("Hell\n");
}

int main(void)
{
 Hell::print();
 return 0;
}
yebisu:objc hirokuma$ nm tst
0000000100001050 S _NXArgc
0000000100001058 S _NXArgv
0000000100000eb0 T __ZN4Hell5printEv
0000000100001068 S ___progname
0000000100000000 T __mh_execute_header
0000000100001060 S _environ
                 U _exit
0000000100000ed0 T _main
                 U _puts
0000000100001000 s _pvars
                 U dyld_stub_binder
0000000100000e70 T start

まあ、違いはprint()のマングリングした名前くらいか。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。