yaml って Makefile を書くのに向いてるんじゃないか?
設定ファイルとして、私は yaml がお気に入りです。
なんといっても記述量が少ない。DSL もいいですが、やっぱり特化型には敵わないと思います。また、ライブラリが豊富で主要なプログラミング言語のほとんどで使えるというのも魅力です。
話は変わって「C/C++ 開発のストレスを軽減する」で触れたとおり、ビルドツールとして SCons、CMake がお気に入りです。ただし、SCons は Python なのでどうしても文字列を何らかの引用符で括る必要があるということに不満があります。CMake は専用の書式で書かなければならないということに不満があります。
例えば、SCons と CMake で hello world をビルドするときを考えてみます。
# Scons Program(target = "hello", source = ["helloworld.c"])
# CMake project(hello c) add_executable(hello helloworld.c)
これくらいだとどっちも十分にシンプルなので、どっちで書いてもいいかな、という気がしますね。仮に、このプログラムが順調に育ちソースコードが増えていったとしましょう。
# Scons Program(target = "hello", source = ["helloworld.c", "helloearth.c", "hellouniverse.c"])
# CMake project(hello c) add_executable(hello helloworld.c helloearth.c hellouniverse.c)
まだ大丈夫ですね。次に、プラットフォーム毎に異なるソースコードをコンパイルしたくなったとしましょう。
# Scons import os env = Environment() platform = env['PLATFORM'] sources = ["helloworld.c", "helloearth.c", "hellouniverse.c"] if platform == 'posix': sources.append('helloposx.c') elif platform == 'darwin': sources.append('hellodarwin.c') elif platform == 'win32': sources.append('hellowin32.c') env.Program(target = "hello", source = sources)
# CMake project(hello c) set(sources) if (UNIX) set(sources helloworld.c helloearth.c hellouniverse.c helloposix.c) elseif (APPLE) set(sources helloworld.c helloearth.c hellouniverse.c hellodarwin.c) elseif (WIN32) set(sources helloworld.c helloearth.c hellouniverse.c hellowin32.c) endif add_executable(hello ${sources})
どちらも一気に野暮ったくなりましたね*1。ここで、どういう風に書きたいかを考えてみましょう。
project: name: hello type: executable source: general: [helloworld.c, helloearth.c, hellouniverse.c] posix: [helloposix.c] darwin: [hellodarwin.c] win32: [hellowin32.c]
ソースコードがもっと増えていくことを考えると、次のように書くべきかもしれません。
project: name: hello type: executable source: general: - helloworld.c - helloearth.c - hellouniverse.c posix: - helloposix.c darwin: - hellodarwin.c win32: - hellowin32.c
これだとすっきりしますね。ソースコードひとつにつきハイフンがいるのが厄介ですが、引用符で括るよりも楽だと思います。
さらにプログラムが大きくなると、他のライブラリを使いたくなるかもしれません。そうすると、include ディレクトリの追加とか、lib ディレクトリを追加する必要が出てきます。
project: name: hello type: executable source: general: - helloworld.c - helloearth.c - hellouniverse.c posix: - helloposix.c darwin: - hellodarwin.c win32: - hellowin32.c incdir: - contrib/include libdir: - contrib/lib lib: - foo
条件付きコンパイルもやってみましょう。
project: name: hello type: executable source: general: - helloworld.c - helloearth.c - hellouniverse.c posix: - helloposix.c darwin: - hellodarwin.c win32: - hellowin32.c ENABLE_XXX: - xxx.c incdir: - contrib/include libdir: - contrib/lib lib: - foo
マルチプラットフォーム向けに開発するときには、リンクするライブラリやコンパイルするソースコードはプラットフォームごとに異なるので、もう少し書き方を工夫してみます。
project: name: hello type: executable source: - helloworld.c - helloearth.c - hellouniverse.c incdir: - contrib/include libdir: - contrib/lib lib: - foo platform_posix: source: - helloposix.c platform_darwin: source: - hellodarwin.c platform_win32: source: - hellowin32.c
platform_xxx では、トップレベルでの incdir、libdir、lib が使えるというイメージですね。
これだと、解析も簡単なのでこれから Autotools 用のファイルを作ったり、SCons 用のファイルを作ったり、Visual Studio 用のプロジェクトファイルを作ったり、nmake 用のメイクファイルを作ったりと、夢が広がります。既存のビルドツールからの移行を考えると、ここで挙げたような作りだけでは到底機能が足りませんが、まぁなんとかなるんじゃないかな、と思います。
ここで挙げた YAML は「Rubyist Magazine - プログラマーのための YAML 入門 (初級編)」の print-yaml.rb で出力を確認したので多分構文的に間違いはないと思います。
*1:もっといい書き方をご存知の方は是非ご教授を・・・