GYP (Generate Your Projects) をご存知でしょうか。その名の通り、GYP はビルドツールで、ウェブブラウザの Chromium や JavaScript Engine の V8、そして JavaScript の実行環境に V8 を採用している Node.js など様々なプロジェクトで採用されています。 GYP はオープンソースです。Google Code で公開されており、誰でも手に入れることができます。 GYP は C++ をはじめ、ビルドを必要とする C や Objective-C を使用したプロジェクトにおいて、ビルドオートメーションを実現するために役に立ちます。 ただ、CMake や SCons に比べまだまだユーザが少なく、ドキュメントも豊富ではありません。そこで今日は GYP について紹介します。
GYP ってどんなもの?
例えばあなたが、C++ で書かれたスーパーエキセントリックでヘビーな、マルチプラットフォームをターゲットにしたゲームエンジンの開発者だとしましょう。数百、数千に渡るヘッダーファイルと、プラットフォームごとのインプリメントファイル、そしてそれらを検証するテストコードと、エンジンを初めて使う人のために用意したサンプルゲームのコードがあります。もちろんソースコードだけでは何の意味もありません。それらをビルドする必要があります。Visual Studio でビルドするためには Visual Studio 用のプロジェクトファイルが必要です。また Xcode でビルドするためには Xcode 用のプロジェクトファイルが必要になります。Linux でビルドするためには make ファイルを用意する必要があるでしょう。
無慈悲にもプロジェクトは拡大していく
今また、エンジンに新たなソースコードが加わりました!あなたは Visual Studio を開き、プロジェクトファイルに項目を追加します。すかさず OSX を立ち上げ Xcode のプロジェクトも変更します。ああ、次は make ファイルも編集しなきゃ。 新たに iOS, Android もサポートすることになりました。追加されたプラットフォームごとのインプリメントファイルや、テストコードも増え、いよいよ大変に。ユーザのために書いたチュートリアルのコードもビルドを前にして今となっては煩わしい。 もし、Visual Studio のプロジェクトや Xcode のプロジェクト、あるいは make ファイルを 1 つのテキストファイルで管理できたら。そして、コマンドをたたくだけでビルドに必要なファイルを自動生成することができたら、ずっと楽になるのに! その悩みを解消するのが GYP (Generate Your Projects) です。
GYP を手に入れよう
お使いのコンピュータに Subversion は入っていますか?もしすでにインストールされていれば話は早いです。Subversion を使って最新の GYP を手に入れることができます:
$ svn --version
$ svn co http://gyp.googlecode.com/svn/trunk gyp
もし、Subversion よりも Git を使うのが好みであれば、次のようにして入手できます:
$ git clone https://chromium.googlesource.com/external/gyp.git gyp
本来の GYP の Subversion リポジトリから git-svn で引っ張ってくることもできますが、あまりお勧めしません。なぜならとても時間がかかるからです1。 「それでもいいよ」と言う物好きな方のために git-svn を利用する方法も載せておきます:
$ git svn clone -s http://gyp.googlecode.com/svn gyp
EDIT (May 8, 2015)
この記事を書いた当時、GYP は Subversion (SVN) でバージョン管理されていましたが、 2015 年 2 月に、SVN から Git に移行し、リポジトリは googlecode から googlesource (https://chromium.googlesource.com/external/gyp
) に移動しました。
Python 2.x をいれておこう
GYP は Python で書かれたソフトウェアです。GYP を使うには Python 2.x2 の実行環境が必要になるので一緒に手に入れておきましょう。Python 3 では上手く動作しないことがあるのでバージョンを確認しておきましょう:
$ python --version
Python 2.7.2
GYP のセットアップ
Python と GYP は手に入れましたか?手に入れた GYP は最初に一度だけセットアップする必要があります。
Linux や Mac OSX の場合
$ cd gyp
$ [sudo] python setup.py install
Windows の場合
$ cd gyp
$ python setup.py install
Linux や Mac OSX の場合、セットアップ後 gyp
コマンドで GYP が使えるようになります。
$ which gyp
/usr/local/bin/gyp
GYP を使ってみよう
触ってみないとわからないものです。早速 GYP を使ってビルドしてみましょう。今回は、非常に小さな謎のライブラリ "Trivial Engine" とそのテストコードをビルドします。必要な GYP ファイルとビルド対象となるソースコードは次の5つです。
- build/common.gypi
- build/trivial.gyp
- include/trivial/Entity.h
- src/Entity.cpp
- test/EntityTest.cpp
例として扱うサンプルコードは GitHub で公開しています。Git を使って最新版を入手することができます。
$ git clone git://github.com/mogemimi/gyp-getting-started.git
完全を期すため、ソースコードを載せておきます:
include/trivial/Entity.h
#pragma once
#include <string>
namespace Trivial {
class Entity
{
public:
char const* GetName() const;
void SetName(char const* name);
private:
std::string name;
};
}// namespace Trivial
src/Entity.cpp
#include <trivial/Entity.h>
namespace Trivial {
char const* Entity::GetName() const
{
return name.c_str();
}
void Entity::SetName(char const* name)
{
this->name = name;
}
}// namespace Trivial
test/EntityTest.cpp
#include <iostream>
#include <trivial/Entity.h>
int main()
{
static_assert(__cplusplus == 201103L, "C++11 supported.");
Trivial::Entity entity;
entity.SetName("Hello, GYP");
std::cout << entity.GetName() << std::endl;
return 0;
}
build/common.gypi
{
'variables': {
'conditions': [
['OS == "mac"', {
'target_arch%': 'x64',
}, {
'target_arch%': '<(target_arch)',
}],
],
},
'target_defaults': {
'default_configuration': 'Release',
'conditions': [
['target_arch == "arm"', {
# arm
}], # target_archs == "arm"
['target_arch == "ia32"', {
'xcode_settings': {
'ARCHS': ['i386'],
},
}], # target_archs == "ia32"
['target_arch == "mipsel"', {
# mipsel
}], # target_archs == "mipsel"
['target_arch == "x64"', {
'xcode_settings': {
'ARCHS': ['x86_64'],
},
}], # target_archs == "x64"
],
'configurations': {
'Debug': {
'defines':['DEBUG=1'],
'cflags': ['-g', '-O0'],
'msvs_settings': {
'VCCLCompilerTool': {
'Optimization': '0', # /Od
'conditions': [
['OS == "win" and component == "shared_library"', {
'RuntimeLibrary': '3', # /MDd
}, {
'RuntimeLibrary': '1', # /MTd
}],
],
},
'VCLinkerTool': {
'LinkIncremental': '2',
},
},
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '0', # -O0
},
}, # Debug
'Release': {
'cflags': ['-O3'],
'msvs_settings':{
'VCCLCompilerTool': {
'Optimization': '2', # /O2
'InlineFunctionExpansion': '2',
'conditions': [
['OS == "win" and component == "shared_library"', {
'RuntimeLibrary': '2', # /MD
}, {
'RuntimeLibrary': '0', # /MT
}],
],
},
'VCLinkerTool': {
'LinkIncremental': '1',
'OptimizeReferences': '2',
},
},
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '3', # -O3
},
}, # Release
}, # configurations
'variables': {
'component%': 'static_library',
},
}, # target_defaults
}
build/trivial.gyp
{
'includes': ['common.gypi'],
'make_global_settings': [
['CXX','/usr/bin/clang++'],
['LINK','/usr/bin/clang++'],
],
'target_defaults': {
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': '4', # /W4
},
},
'xcode_settings': {
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_CXX_LANGUAGE_STANDARD': 'c++0x',
'MACOSX_DEPLOYMENT_TARGET': '10.8', # OS X Deployment Target: 10.8
'CLANG_CXX_LIBRARY': 'libc++', # libc++ requires OS X 10.7 or later
},
},
'targets': [
{
'target_name': 'trivial_engine',
'product_name': 'TrivialEngine',
'type': 'static_library',
'include_dirs': [
'../include',
],
'sources': [
'../src/Entity.cpp',
],
'xcode_settings': {
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', # '-fvisibility-inlines-hidden'
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # '-fvisibility=hidden'
},
},
{
'target_name': 'trivial_test',
'product_name': 'TrivialTest',
'type': 'executable',
'dependencies': [
'trivial_engine',
],
'include_dirs': [
'../include',
],
'sources': [
'../test/EntityTest.cpp',
],
'xcode_settings': {
},
},
] # targets
}
おっと、逃げないでください!サンプルにしてはあまりにも長いコードに思わずびっくりしたかもしれませんが、ひとまずここは騙されたと思って、早速ビルドしてみましょう。
MSBuild (Visual Studio 2012) でビルドしてみよう。
Visual Studio 2012 のソリューションファイル、プロジェクトファイルを作ってみましょう。コマンドプロンプトまたは MinGW + MSYS を開き、次を実行します。(説明のために、GYP の場所を tools/gyp
ディレクトリ3にしています。)
$ python tools/gyp/gyp build/trivial.gyp --depth=. -f msvs -G msvs_version=2012 -D target_arch=ia32
成功すると build
ディレクトリ内に各プロジェクトファイルが生成されます。
生成されたソリューションファイルをビルドしてみましょう。先に MSBuild を利用するためにパスを通しておきます。環境に合わせて適宜置き換えてください。コマンドプロンプトを開き:
$ set Path=C:\Windows\Microsoft.NET\Framework\v4.0.30319;%PATH%
MSBuild を実行します。
$ MSBuild.exe build\trivial.sln
これでビルドができました!試しに動かしてみましょう。
$ build\Debug\TrivialTest.exe
Hello, GYP
ちなみに MSBuild でリリースビルドするには次を実行します。
$ MSBuild.exe build\trivial.sln /p:Configuration=Release
Xcode (Apple LLVM Clang++) でビルドしてみよう。
Xcode のプロジェクトファイルを生成してみましょう。 ターミナルを開き、
$ gyp build/trivial.gyp --depth=. -f xcode --generator-output=./build.xcodefiles/
ターゲットアーキテクチャを明示的に指定する場合は次のように target_arch 変数を指定します。
$ gyp build/trivial.gyp --depth=. -f xcode -D target_arch=ia32 --generator-output=./build.xcodefiles/
$ gyp build/trivial.gyp --depth=. -f xcode -D target_arch=x64 --generator-output=./build.xcodefiles/
Xcode のプロジェクトファイル build/trivial.xcodeproj
が生成されます。ではビルドしてみましょう。
$ xcodebuild -project build.xcodefiles/build/trivial.xcodeproj
xcodebuild
でリリースビルドを行う場合は次のようにします:
$ xcodebuild -project build.xcodefiles/build/trivial.xcodeproj -configuration Release
実際にビルドしたプログラムをターミナルから実行してみます。
$ build/build/Release/TrivialTest
Hello, GYP
感動しました? 初めて GYP をプロジェクトに導入してビルドが正常に通った日のことを僕は今でも鮮明に覚えています。 ええ、あれはとても晴れた日で、思わず感動して、えーと、そう、あの日の晩ごはんは確か…。
GYP を実際のプロジェクトで使ってみよう。
少々長くなりました(汗) GYP について少しでもおわかりいただけたでしょうか。GYP は非常に強力なビルドオートメーションツールです。 あなたのプロジェクトが今よりずっと規模が大きくなって複雑になったとしても、そのときはきっと役に立ってくれるはずです(巨大なソフトウェアである Chromium で使用されているくらいですから!)。
今回サンプルとして用意した .gyp
ファイルは、実際に開発で使用しているファイルを流用したものです。
サンプルとして最小におさまるよう努力しましたが、できる限りこのまま本来のプロジェクトに使っていただけるような形にしています4。
もし次回機会があれば、お話できなかった GYP の機能について紹介します。
追記
GYP の具体的な使い方に関して、次の記事を書きました。ご参考になりましたら幸いです。
- GYP (Generate Your Projects) の入力フォーマットと基本的な使い方
- ビルドツール GYP で Visual Studio プロジェクトのあれこれを設定しよう
- GYP における MSBuild Settings (msbuild_settings) の使い方
- GYP を使って Xcode プロジェクトを作ってみよう
-
およそ1~2時間くらい。 ↩
-
Python 2.6 または 2.7 がオススメです。Python ウェブサイトから取得できます。その他に chromium のリポジトリから Python を取得することもできます。Subversion を使って "svn co http://src.chromium.org/svn/trunk/tools/third_party/python_26@89111 tools/python" ↩
-
V8 や node.js など GYP を採用しているプロジェクトでは、GYP 本体の場所を
project-root/tools/gyp
ディレクトリに指定するなどプロジェクトディレクトリ下にインストールすることも少なくないようです。 ↩ -
プロジェクトファイル生成時にターゲットアーキテクチャを指定できるように追加しています。また、C++11 を利用できるようにしています。その他、各プラットフォーム向けに必要な設定を行っています。 ↩
Leave a Reply