にゃははー

はへらー

bjam AdC jp 2011 21日目

つらいれす...

フラグとか共通化

feature.extend toolset : nvcc ;
toolset.inherit-generators nvcc : unix : unix.link unix.link.dll ;
toolset.inherit nvcc : unix ;

generators.override nvcc.prebuilt : builtin.lib-generator ;
generators.override nvcc.prebuilt : builtin.prebuilt ;
generators.override nvcc.searched-lib-generator : searched-lib-generator ;

ここらへんは既存のものを使い回すための設定です。最初の1行だけはnvccというtoolsetがあるという登録をしてる感じです。

rule init ( version ? : command * : options * )
{
	local condition = [ common.check-init-parameters nvcc : version $(version) ] ;
	local command = [ common.get-invocation-command nvcc : nvcc : $(command) ] ;
	handle-options nvcc : $(condition) : $(command) : $(options) ;
}

local rule handle-options ( toolset : condition * : command * : options * )
{
	common.handle-options $(toolset) : $(condition) : $(command) : $(options) ;

	flags nvcc.compile.cu OPTIONS $(condition)
	  : [ feature.get-values <cuflags> : $(options) ]
	  : unchecked ;
}

using nvcc ; で呼ばれるinit ruleです。これはtoolsetの初期化を行ないます。バージョン番号を取得したり色々します。
今回は特に何もしてないです。大体こんなことかいてあればいい感じらしいので適当です。

で、generatorがくるのですが、これは前々回やってるので飛ばします。

コンパイラオプション周りの定義です。

flags nvcc.compile OPTIONS <address-model>32 : -m32 ;
flags nvcc.compile OPTIONS <address-model>64 : -m64 ;

flags nvcc.compile OPTIONS <debug-symbols>on : -g ;

feature device-debug-symbols : off on : propagated ;
flags nvcc.compile OPTIONS <device-debug-symbols>on : -G ;

flags nvcc.compile DEFINES <define> ;
flags nvcc.compile INCLUDES <include> ;

feature cuflags : : free optional ;
flags nvcc.compile.cu OPTIONS <cuflags> ;

flags nvcc.link LINKPATH <library-path> ;
flags nvcc.link LIBRARIES <library-file> ;
flags nvcc.link OPTIONS <linkflags> ;

feature ruleはrequirementsなどに書くfeatureを定義します。いくつかはbuiltinで定義されています。ここではnvcc特有のデバイスコードのデバッグシンボルを含めるかのフラグと/とは違うCUDA専用のフラグとしてを定義します。
featureにも種類があって、何でも記述できるfreeや無くても問題ないoptionalなどがいくつかあります。公式のドキュメントに書いてあるので探すといいです。

次にflags ruleです。これは定義したfeatureをどうやってコマンドに投げつけるかという簡単な対応を記述できます。

flags nvcc.compile OPTIONS <device-debug-symbols>on : -G ;

という書き方のだと、

nvcc toolsetでコンパイルする場合にonというrequirementsが記述されていればOPTIONSというシェル変数に-Gを追加する

となります。OPTIONSはjamで使われる変数ではなく、actionsなどで使われるシェル変数であることに注意してください。
同じ要領でインクルードパスやリンカフラグも設定します。

コンパイラに渡す部分

rule compile.cu ( target * : sources * : properties * )
{
	local target = [ feature.get-values target : $(properties) ] ;
	switch $(target)
	{
		case "" : OPTIONS on $(targets) += -c ;
		case * : EXIT "unknown target" ;
	}
}
actions compile.cu
{
	$(CONFIG_COMMAND) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -o "$(<)" "$(>)"
}

actions link bind LIBRARIES
{
	$(CONFIG_COMMAND) $(OPTIONS) -L"$(LINKPATH)" -o "$(<)" "$(>)" $(LIBRARIES)
}

rule名と同名のactionsがある場合、ruleを処理してからactionsが呼ばれます。また、actions内ではruleの第1引数は$(>)第2引数は$(<)という変数に格納されます。
$(CONFIG_COMMAND)はinit rule内で呼び出したcommon.handle-options内で定義されます。とりあえず適当にやった甲斐があったものです。

また、rule側でactionsで使用するシェル変数を定義したり変更したりしたいことがあります。この時、シェル変数はターゲット毎に空間が用意されているので、どのターゲットに対して操作するかを指定した上で操作する必要があります。
それが OPTIONS on $(targets) という書き方で、この場合 が無いのでデフォルトでオブジェクトを生成するように-cオプションを追加しています。

また、bjamのsequenceについて面白い特性を見ることができます。通常、シェルスクリプトなどで

var = hoge fuga piyo
echo x$(var)

とすると、出力結果は

xhoge fuga piyo

となります。

しかし、bjamではsequenceにスペースで区切られていない隣合ったものがある場合、すべての順列に展開します。つまり

var = hoge fuga piyo ;
ECHO x$(var) ;

の出力結果は

xhoge xfuga xpiyo

となります。すべての順列なので、複数のsequenceが隣り合っている場合、

var1 = hoge fuga piyo ;
var2 = foo bar baz ;
ECHO $(var1)$(var2) ;

の出力結果は

hogefoo hogebar hogebaz fugafoo fugabar fugabaz piyofoo piyobar piyobaz

となります。

これを利用すると、すべてのインクルードパスに-Iを付けることも、マクロに-Dを付けることも容易です。
これでコンパイルに必要な引数がうまく生成されるわけです。

まとめ

あと2日分のネタがありません。