スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Xcodeで書いたCocoaアプリケーションをGNUstepで動かすメモ

コードを書く際の注意

まずWriting portable code - GNUstepWikiに書いてあることはだいたい守る。 FoundationやAppKit以外の、OSXに特有のライブラリを使わないということ。

その他に気をつけることとしては、

  • Xcodeが自動生成するコードがNSApplicationDelegateプロトコル(formal protocol)を使っている場合があるが、GNUstepにはこのプロトコルはないので、#ifndef GNUSTEPなどで対処する。
    • GNUstepにはGSAppDelegateProtocolというプロトコルがあるが、コメントによればこれはドキュメント用に宣言されているだけで、アプリケーションが実装する必要はないとのこと。
    • GSAppDelegateProtocol@optional指定つければNSApplicationDelegateになりそうだが
  • Interface BuilderでUIを作る際に、Auto Layoutを使わないようにする。デフォルトでは「Interface Builder Document」の「Use Auto Layout」チェックがついていて、生成されるxib中でNSLayoutConstraintが使われてしまう。OSX上でもNSLayoutConstraintはかなり新しいAPIのはずだが、どうしてこうなった。

など。

ビルドシステム

GNUstep Makeを使うのが素直だろう。つまり、Xcodeのプロジェクトとは別にMakefileを書く。GNUstep MakeのMakefileの書き方はこのへんを参照。

ただし、上のリンク先に書いてない重要なことがいくつかあって、まずInterface Builderで作ったxibを指定すること。どう書けばいいかと言うと、アプリケーション名(APP_NAME)を例えばHogeとすると

Hoge_RESOURCE_FILES = Hoge/en.lproj/MainMenu.xib
Hoge_MAIN_MODEL_FILE = MainMenu

のような記述を入れておく。こうするとmakeした時にMainMenu.xibがアプリケーションバンドルにコピーされていい感じになる。

ここまでの手順で、簡単なアプリケーションはビルドできるはず。運が良ければ問題なく動作するかもしれない。

Info.plist

Xcodeで開発した時はInfo.plistというというファイルにアプリケーションの情報(名前とか作者とかアイコンとか)をいろいろ書いたが、GNUstepの場合はどうか?

まあ実際にビルドしてみるとアプリケーションバンドル内にInfo-gnustep.plistというファイルができていて、中には"Automatically generated"とか書かれている。アプリケーションアイコンを設定したり、アプリケーションメニューの「Info…」で出てくるダイアログにアプリケーションの情報を載せるにはInfo-gnustep.plistに書き出される内容をカスタマイズする必要があるわけだが、その方法には2種類ある。

  • Makefile中で変数を定義する。さっきの*_MAIN_MODEL_FILEと同様。CFBundleIconFile(*_APPLICATION_ICON)やNSPrincipalClass(*_PRINCIPAL_CLASS)など。
  • テンプレートとなるInfo.plistファイルを作って、make時に自動生成される分と合わせてマージさせる。上記以外のキー/値はこの方法を使う。テンプレートとなるInfo.plistファイルの名前は「HogeInfo.plist」で、GNUmakefileと同じディレクトリに置いておけば勝手に拾ってくれる。

この辺はまともなドキュメントがなさそうだが、辛うじて見つけられたのはこのへんとかこのへん。まあGNUstep Makeのソースコード(core/make/Instance/application.makeなど)を読むべきかもしれない。

あと今回はLinux(Ubuntu)でしか試していないので、Windowsで同じようにうまくいくのかは知らない。

スポンサーサイト

テーマ : プログラミング | ジャンル : コンピュータ

GNUstepのWindowsバイナリをMacからクロスコンパイル

幾度とない失敗を乗り越え、ようやく成功した。

必要な物

  • GNUstep
    svnで取得する。ビルドしたのはr29897。
  • クロスコンパイラ(i386-mingw32-*)
    MacPortsで取得する。
  • GNUstepが依存するライブラリ(バージョンはビルドに使ったもの)
    • pthread-win32 2.8.0 → gnustep-baseに必要。
    • libffi 3.0.8 → gnustep-baseに必要。ローカルにあった物を使ったけど、サイトを見るといつのまにか3.0.9が出ていた件。
    • libgpg-error 1.7 → libgcryptに必要。
    • libgcrypt 1.4.5 → gnutlsに必要。
    • libtasn1 2.4 → gnutlsとgnustep-baseに必要。
    • gnutls 2.8.5 → gnustep-baseに必要。
    • libxml2 2.7.6 → gnustep-baseに必要。
    • libjpeg 8a → gnustep-guiに必要。
    • libtiff 3.9.2 → gnustep-guiに必要。
    • zlib 1.2.3 → libpngに必要。
    • libpng 1.4.1 → gnustep-guiに必要。
    • sqlite3 3.6.23 → gworkspaceに必要。
    • gmpとかiconvとかopensslもあればいいのかもしれないけどよくわからん。
  • Wine
    楽をするために必要。

続きを読む

テーマ : プログラミング | ジャンル : コンピュータ

tag : GNUstep

Objective-CのProtocolについて

Objective-Cのプロトコルはどう実装されているのか。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

int main() {
  Protocol *p = @protocol(SomeProtocol);
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}

@protocol(protocol_name)で、プロトコルの実体(Protocol *)を取得することができる。このコードをコンパイル、実行すると以下のようになる。

$ gcc test1.m -lobjc
$ ./a.out
SomeProtocol: 0x300c SomeProtocol

次に、@protocol(protocol_name)の代わりに、ランタイム関数であるobjc_getProtocol()を使ってみる。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}

同じようにコンパイル、実行する。

$ gcc test2.m -lobjc
$ ./a.out
SomeProtocol: 0x0 nil

今度はnilが返ってきたようだ。このプロトコル(SomeProtocol)はどこでも使用されておらず、このプロトコルの実体が作られなかったようだ。

今度は、SomeProtocolに適合したクラスを宣言してみる。

#include <objc/Protocol.h>
#include <objc/runtime.h>
#include <stdio.h>

@protocol SomeProtocol
- someMethod;
@end

@interface SomeClass <SomeProtocol>
- someMethod;
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}
$ gcc test3.m -lobjc
$ ./a.out
SomeProtocol: 0x0 nil

今度もnilが返ってきた。宣言するだけでは不足なようだ。次はクラスの実装も書く。

#include <stdio.h>
#include <objc/runtime.h>
#include <objc/Protocol.h>

@protocol SomeProtocol
- someMethod;
@end

@interface SomeClass <SomeProtocol>
- someMethod;
@end

@implementation SomeClass
- someMethod { return nil; }
@end

int main() {
  Protocol *p = objc_getProtocol("SomeProtocol");
  printf("SomeProtocol: %p %s\n", p, protocol_getName(p));
}
$ gcc test4.m -lobjc
$ ./a.out
SomeProtocol: 0x30a4 SomeProtocol

取得できた。Class型のオブジェクトは、そのクラスが適合するプロトコルのリストを持つ(class_copyProtocolListで実行時に取得できる)ので、SomeProtocolの実体が作られたのだろう。

まとめ。Protocolの実体が作られる条件:

  • そのプロトコルに適合するクラス(カテゴリも?)の@implementationが書かれた
  • @protocol()で参照された

従って、どこからも参照されていないプロトコルを実行時にobjc_getProtocolで取得することはできない。

ちなみに、Protocolの実体はファイルごとに作られる。同じSomeProtocolであっても、あっちのファイル由来のものとこっちのファイル由来のものではアドレスが違う。protocol_isEqualで比較しよう。

テーマ : プログラミング | ジャンル : コンピュータ

プロフィール

minoki

Author:minoki
好きなプログラミング言語:
Haskell,Lua
GitHubアカウント
Twitter

最新記事
月別アーカイブ
カテゴリ
検索フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。