黒毛和牛モモバラ切り落し100g298円

iPhoneアプリを作ってます。リリースノートとかごにょごにょとか用ブログです。

コマンドラインからObjective-Cソースファイルをコンパイルする方法

iOSアプリの話ですが、UIの絡まない処理はXcodeで書くよりもviとかでコーディングしてコマンドラインでコンパイルする方が速いと思っておりますのでその方法を書いときます。

Macのコマンドラインから(iOSでも動くようにFoundationをインポートした状態のソースを)コンパイルする場合、以下のようにclangを動かせばXcodeからiOSアプリをビルドする際とコンパイルオプション的にはほぼ同じになります(アーキテクチャ指定と、長ったらしいのでワーニングオプションは省略してます)。

clang -g -x objective-c -fmessage-length=0 -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings a.m -framework Foundation
  • x objective-cオプションはソースがObjective-Cであることを指示するフラグです。分割コンパイル後にリンクする場合はこのオプションは不要になります。

a.mの中身はこんな感じ。当然ながらUIKitとかはMacにはありませんし、MacにもiOSにもあるフレームワークでもサポート内容が違うものもちらほらありますので、何がどこまで動くのかはライブラリのリファレンスとにらめっこしてください。

#import <Foundation/Foundation.h>

int
main(void)
{
    @autoreleasepool {
        NSLog(@"Hello, world!");
    }
    return 0;
}

コンパイルしたらa.outができますのでシェルから実行できます。

$ ./a.out
2013-08-12 21:37:54.923 a.out[1609:707] Hello, world!

デバッガを使いたい場合はlldbを起動します。使い方はgdbとほぼ一緒と思いますがあまりちゃんと調べてないのでその辺はご自身でお願いします。

$ lldb a.out
Current executable set to 'a.out' (x86_64).
(lldb) b main
breakpoint set --name 'main'
Breakpoint created: 1: name = 'main', locations = 2
(lldb) run
Process 1625 launched: '/private/tmp/a.out' (x86_64)
Process 1625 stopped
* thread #1: tid = 0x1f03, 0x0000000100000daf a.out`main + 15 at a.m:6, stop reason = breakpoint 1.1
    frame #0: 0x0000000100000daf a.out`main + 15 at a.m:6
   3   	int
   4   	main(void)
   5   	{
-> 6   	    @autoreleasepool {
   7   	        NSLog(@"Hello, world!");
   8   	    }
   9   	    return 0;
(lldb) n
Process 1625 stopped
* thread #1: tid = 0x1f03, 0x0000000100000dbb a.out`main + 27 at a.m:7, stop reason = step over
    frame #0: 0x0000000100000dbb a.out`main + 27 at a.m:7
   4   	main(void)
   5   	{
   6   	    @autoreleasepool {
-> 7   	        NSLog(@"Hello, world!");
   8   	    }
   9   	    return 0;
   10  	}
(lldb) n
2013-08-12 21:40:38.620 a.out[1625:1307] Hello, world!
Process 1625 stopped
* thread #1: tid = 0x1f03, 0x0000000100000dc9 a.out`main + 41 at a.m:8, stop reason = step over
    frame #0: 0x0000000100000dc9 a.out`main + 41 at a.m:8
   5   	{
   6   	    @autoreleasepool {
   7   	        NSLog(@"Hello, world!");
-> 8   	    }
   9   	    return 0;
   10  	}
(lldb) n
Process 1625 stopped
* thread #1: tid = 0x1f03, 0x0000000100000dd7 a.out`main + 55 at a.m:9, stop reason = step over
    frame #0: 0x0000000100000dd7 a.out`main + 55 at a.m:9
   6   	    @autoreleasepool {
   7   	        NSLog(@"Hello, world!");
   8   	    }
-> 9   	    return 0;
   10  	}
(lldb) n
Process 1625 stopped
* thread #1: tid = 0x1f03, 0x0000000100000d94 a.out`start + 52, stop reason = step over
    frame #0: 0x0000000100000d94 a.out`start + 52
a.out`start + 52:
-> 0x100000d94:  movl   %eax, %edi
   0x100000d96:  callq  0x1000016e4               ; symbol stub for: exit
   0x100000d9b:  hlt    
   0x100000d9c:  nop    
(lldb) cont
Process 1625 resuming
Process 1625 exited with status = 0 (0x00000000) 
(lldb) q