スポンサーサイト

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

携帯電話のSDカードのファイルをMacで管理するアプリケーション

スマートフォン全盛の時代にこんなものを公開するのもどうかと思うが。 タイトルの通りのアプリケーション(のソースコード)をgithubで公開した→https://github.com/minoki/keitaisdeditor。 ドコモのフィーチャーフォンを想定している。

開発を始めた時点では、Windows用の同様のアプリケーションはあったがMac用がないという状況だった。今はどうなっているか知らない。

開発は2年前ぐらいからやっていたが、ここ1年ほど放置していて、これ以上更新することもなさそうなので(ソースコードを)公開することにした。 SDカード内のファイルの追加ぐらいはできるはず。

もちろん、完全に無保証である。SDカードのファイルが壊れても知らない。

FC2 Management

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で同じようにうまくいくのかは知らない。

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

Cなどで書かれたプログラムからHaskellを使う(メモ)+Xcodeのプロジェクトに組み込むときのメモ

ある種の処理を書く時にHaskellは便利だが、プログラムの他の部分はCなどの他の言語で書きたい場合がある。 そこで、Haskellで動的ライブラリ(.soや.dylib)を作り、他のプログラムから呼び出せるようにしたいと思った。

Haskell側ではforeign exportで関数をエクスポートすればよい。 foreign exportの入ったモジュールをコンパイルすると*_stub.h,*_stub.cというファイルが生成される…と思ったら現在のGHCでは_stub.cの方は生成されない?

C側のプログラムからは、生成された_stub.hを#includeすればHaskellで書かれた関数のC言語でのプロトタイプが見える…のだが、この_stub.hからはHsFFI.hというHaskell処理系の(?)ヘッダで、単体のライブラリとして配布する際に依存性があると邪魔だ。なので、自前でヘッダファイルを書くか、Haskellで書かれた関数をラップする関数をCで書くかするといいと思う。

また、Haskellの関数を使う前にHaskellのランタイムを初期化する必要がある。 Calling Haskell from C - HaskellWiki8.2. Using the FFI with GHCを参考に初期化ルーチンを書こう。 __attribute__((constructor))__attribute__((destructor))をつけておけばライブラリの使い手でいちいち初期化ルーチンを呼ぶ必要がなくて楽かもしれない。

ライブラリのコードとしてはCのコードとHaskellのコード両方が含まれる。どっちもまとめてGHCに渡してしまうといいだろう:

ghc -O2 --make -no-hs-main -optl '-dynamiclib' -o libHogehoge.dylib Hogehoge.hs Higehige.c

当初試したときは、リンク時に_environが見つからないというようなエラーが出たが、この問題はGHCの最新バージョンでは直っているらしく、Haskell Platform 2012.4(GHC 7.4.2)をインストールしたら解決した。

自分の場合は、ライブラリを呼ぶ側のプログラムはCocoaアプリケーションで、Xcodeで開発している。それで、Xcodeのビルドボタンを押すとHaskellのライブラリも一緒にビルドされるようにしたい。 ビルド中に上記のコマンドラインが実行されるようにしたいのだが、Haskell用のBuild Ruleを追加して…というのは難しそうだったのでMakefileを書いてExternal Build Systemとしてターゲットを作った。

Makefileの内容はこんな感じで:

PRODUCT = $(BUILT_PRODUCTS_DIR)/libHogehoge.dylib

all: $(PRODUCT)

$(PRODUCT): Hogehoge.hs Higehige.c $(BUILT_PRODUCTS_DIR)
	ghc -c -O2 --make -outputdir $(DERIVED_FILE_DIR) -o $@ Hogehoge.hs
	ghc -O2 --make -no-hs-main -optl '-dynamiclib' -outputdir $(DERIVED_FILE_DIR) -o $@ Hogehoge.hs Higehige.c
	install_name_tool -id @executable_path/libHogehoge.dylib $@

$(BUILT_PRODUCTS_DIR):
	mkdir -p $@

$(BUILT_PRODUCTS_DIR)$(DERIVED_FILE_DIR)はXcodeがコマンドを呼び出す際に設定してくれる環境変数。 Higehige.cから_stub.hを参照する場合、.hsと.cを一度にghcに渡すと_stub.hが存在しない場合エラーになるようで、先に.hsだけをコンパイルして_stub.hが確実に存在するようにしている。なんだか無駄なようで、自分のやり方が悪いのかもしれない。 ライブラリを.app内に含めることを考えて、リンク後にinstall_nameを設定している。

Xcode側の設定は、External Build Toolとして作ったターゲット(仮にHigehigeとする)の、DirectoryにMakefileがあるディレクトリを設定しておく。ソースコード内の位置指定に$(SRCROOT)が使える。 また、プロジェクトのファイルとして、生成されるlibHigehige.dylibを追加しておく。ビルドしてできたファイルをXcodeに追加して、プロパティーのLocationをRelative to Build Productsに設定すればいい感じになるだろう。

主となるアプリケーションの設定としては、Build PhasesのTarget DependenciesにHigehigeを追加しておく。 それから、先に追加したlibHigehige.dylibをリンクするように設定する。 あと、ビルド後にlibHigehige.dylibをアプリケーションバンドル内にコピーするBuild Phaseを追加しておく。

我ながらかなり読みにくい文章になってしまった。CからHaskellを呼ぶ話と、XcodeでExternal Build Toolを使ってファイルをビルドする話が混ざっている気がする。 しかし、読みやすい文章を心がけたりスクリーンショットを載せたりしてがんばると、ただでさえ半年間更新していないブログの更新がますます億劫になってしまうのは間違いない。だからこのぐらいの適当さでいいのだ、ということにしておく。

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

テキストファイルのエンコーディング(com.apple.TextEncoding)を設定するコマンドを作った

Mac OS Xでは、テキストファイルのエンコーディングを拡張属性com.apple.TextEncodingに格納できる。テキストエディットなどでそのファイルを開くと、ファイルがcom.apple.TextEncodingで指定されたエンコーディングで読み出される。誤判定の多いエンコーディングの自動判別機能に頼る必要は無い。

テキストエディットなどでファイルを作成すればこの拡張属性は自動的に設定されるのだが、外部から取得したファイルなどにはこの拡張属性は設定されていないことが多い。そこで、任意のファイルに拡張属性com.apple.TextEncodingを設定するコマンドを書いた→https://github.com/minoki/setTextEncoding

使い方は

$ setTextEncoding エンコーディング名 ファイル(複数可)…

とすればよい。CFStringEncodingの値はエンコーディング名から自動で求めてくれる。また、エンコーディングの表記にぶれがあったとしても、

$ setTextEncoding euc-jp
euc-jp;2336
$ setTextEncoding eucjp
euc-jp;2336
$ setTextEncoding eucjp
euc-jp;2336

のようにIANA名に規格化される。

入力ソースを設定するコマンドを作った

Mac OS Xの入力ソース(ことえりやGoogle日本語入力など)をCUIで設定(有効/無効/選択)できるコマンドを作った→https://github.com/minoki/InputSourceSelector

入力ソースをいじるには、Mac OS X 10.5以降であればCarbonのText Input Source Servicesを叩けばいい。入力ソースのID(例:com.apple.inputmethod.Kotoeri.Roman)から入力ソースを取得するにはTISCreateInputSourceListを呼び出す。この関数は名前の通り入力リストのリストを返すが、第一引数にプロパティリストを渡す事で入力ソースを絞り込む事ができる。帰ってきたCFArrayRefから入力ソース(TISInputSourceRef型)を取得しTISEnableInputSourceTISSelectInputSourceを呼び出せば、それぞれ入力ソースを有効化、選択できる。

プログラム中でTISCreateInputSourceListから帰ってきた入力ソースの配列を走査するのにFast Enumerationを使っているが、TISInputSourceRef型はObjective-Cのid型と互換性がないため、ループを

for (TISInputSourceRef inputSource in inputSources) {
    ...
}

と書くことはできない。しかし、__attribute__((NSObject))を使えばid互換の型として扱ってくれるようだ。

for (TISInputSourceRef __attribute__((NSObject)) inputSource in inputSources) {
    ...
}

さて、このコマンドの使い方だが、

$ InputSourceSelector list

と打てば入力ソースのIDと名前の一覧が表示される。list-enabledとすれば現在有効になっている入力ソース飲みが表示される。これで調べたIDに対して

$ InputSourceSelector enable (調べたID)

と打てばその入力ソースが有効化される(右上のメニューの入力ソース一覧に現れる)。また、

$ InputSourceSelector select (調べたID)

と打てばその入力ソースが現在の入力ソースとして選択される。

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

プロフィール

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

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