例えばOpenCLを使う時、ソースコードを文字列として実行時にコンパイラに渡しますが、それだと
- .clを別ファイルとして毎回ファイル読み込みする
- .clをリソースファイルとして埋め込む(Windowsの場合)
- 諦めてソースコード中に文字列として直書きする
という辺りが一般的ですが、それもちょっとイマイチです。
で、以前のアドベントカレンダーで @tap4453 さんが『マクロを使って便利にOpenCL』という記事を書いていたのですが、そのままだとうまくいかなかったので、私の使い方をメモしておきます。
device.cl
#ifndef OCL_EXTERNAL_INCLUDE
#define OCL_EXTERNAL_INCLUDE(x) x
#endif
OCL_EXTERNAL_INCLUDE(
kernel void func(global double dst[])
{
const int i = get_global_id(0);
dst[i] = i*i;
}
)
host.cpp
#define OCL_EXTERNAL_INCLUDE(x) #x
const char srcStr[] =
#include "ocl.cl"
;
cl::Program::Sources sources;
sources.push_back(std::make_pair(srcStr, std::strlen(srcStr)));
cl::Program program(context, sources);
program.build(devices);
としておくと、srcStr
が文字列としてdevice.clの内容を持ってくれます。
文字列の長さはstd::strlen
でとれますね。
OpenCL関係なくても、別のファイルを埋め込めるのは地味に便利です(UIテキストとか計算の入力値とか)。
C++で書きましたがCでも同じはず・・・。
ほんとに出来るのか試したい人はbitbucketに実際の使用例が置いてあるのでご覧ください。
ちなみに、「OpenCLはCUDAと違ってソースコードを文字列で持つのが嫌!」みたいなのたまに聞きますが、逆に最適化極めたい場合は実行時にソースコードを変更したり生成できたりするので、これはこれで利点だと思ってます。
ViennaCLなんかは、計算式は式テンプレートで持っておいて、コンパイルするカーネルはそれぞれ最適な感じで生成しますしね。