C/C++で他のファイルをincludeして文字列として埋め込む方法(OpenCLとか)


例えば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なんかは、計算式は式テンプレートで持っておいて、コンパイルするカーネルはそれぞれ最適な感じで生成しますしね。