theosのLogo用拡張子は種類がいくつかあるのでその話。
theosって?
theosはiOS/Mac向けのMakefileフレームワークだ。Makefileからincludeしてあげれば苦行のようなMakefileの記述からある程度解放してくれる。
Logo
どちらかと言えばtheosはビルド過程にこの処理を含ませるためのMakefileという側面が強いが、MobileSubstrate向けのswizzleコードの記述を楽に書けるよう変換も行わせる事ができる。
その際の拡張子が以下だ。
この拡張子の違いについて説明しよう。まず一番一般的な.xmだが、これはLogo変換処理を行い.mmファイルを生成し、Objective-C++としてプリプロセス、コンパイル、リンクを行う。
次に.xはそれのObjective-C版だ。全てに言える事だがLogoの変換処理に違いはない。オリジナルのマクロによってObjc/Objc++で普通にswizzleを書くのと同じ状態へ持っていくのだから至極当然の処理順だ。
最後にそれらにiがついたものだ、これは真っ先にobjc/objc++プリプロセスが行われる。その後にLogo処理、コンパイル、リンクとなる。そこそこコードを書いていると以下のように書きたいと思うこともあるだろう。
#define SHARED_INSTANCE [%c(SBProcess) sharedInstance]
%cマクロはLogo処理向けであるのでプリプロセスに放り込むとエラーになる。このレベルであればobjc_getClassで代用がきくが以下のようなケースはそうもいかない。
%hook UIKBKey
- (NSString *)displayString {
NSString *result = %orig();
return [self.name rangeOfString:@"-Small-"].location != NSNotFound ? [result lowercaseString] : result;
}
%end
%hook UIKBTree
- (NSString *)displayString {
NSString *result = %orig();
return [self.name rangeOfString:@"-Small-"].location != NSNotFound ? [result lowercaseString] : result;
%end
処理内容が同じなので変更は一度ですむようにすべきだが、関数にまとめても%origは%hookの外では使用できない。
プリプロセスが先に走る.xi, .xmiではdefineにLogoを書いておく事が可能になるのでdefineでまとめられる。
#define HONOR_CASE \
NSString *result = %orig(); \
return [self.name rangeOfString:@"-Small-"].location != NSNotFound ? [result lowercaseString] : result;
%hook UIKBKey
- (NSString *)displayString { HONOR_CASE }
%end
%hook UIKBTree
- (NSString *)displayString { HONOR_CASE }
%end
めでたく修正時には一度の変更ですむようにできた。
コード出典: ShowCase – github/ashikase
まとめ
|
extension |
process order |
|
.x |
Logo –> objc preprocess+compile –> link |
|
.xm |
Logo –> objc++ preprocess+compile –> link |
|
.xi |
objc preprocess –> Logo –> objc compile –> link |
|
.xmi |
objc++ preprocess –> Logo –> objc++ compile –> link |
なおこの表はiphonedevwikiにも記述しておいた。