注意:这个问题与 OpenCL 本身无关......检查最后一段以获得我的问题的简洁陈述。但要提供一些背景:
我正在编写一些使用 OpenCL 的 C++ 代码。我喜欢将我的 OpenCL 内核的源代码保存在它们自己的文件中,以简化编码和维护(而不是将源代码直接作为字符串常量嵌入到相关的 C++ 代码中)。这不可避免地会导致在分发二进制文件时如何将它们加载到 OpenCL 运行时的问题——理想情况下,OpenCL 源代码包含在二进制文件中,因此二进制文件不需要位于特定位置在某个目录结构中知道 OpenCL 源代码在哪里。
我想将 OpenCL 文件作为字符串常量包含在某处,并且最好不使用额外的构建步骤或外部工具(为了交叉编译器/跨平台的易用性......即,禁止xxd
等)。我以为我偶然发现了一种基于此线程中第二个答案的技术,如下所示:
#define STRINGIFY(src) #src
inline const char* Kernels() {
static const char* kernels = STRINGIFY(
#include "kernels/util.cl"
#include "kernels/basic.cl"
);
return kernels;
}
请注意,如果可能的话,我宁愿不将STRINGIFY
宏嵌入到我的 OpenCL 代码中(正如上面引用的 SO 问题中所做的那样)。现在,这在 Clang/LLVM 编译器上运行得非常好,但是 GCC 死得很惨(“未终止的参数列表调用宏 STRINGIFY”和与 .cl 文件内容相关的各种语法“错误”出现)。所以,很明显,这种精确的技术不能在编译器中使用(没有尝试过 MSVC,但我也希望它在那里工作)......我怎样才能最小化地按摩它以便它在编译器中工作?
总之,我想要一种符合标准的技术,用于将文件的内容作为 C/C++ 字符串常量包含在内,而无需调用外部工具或使用无关代码污染文件。想法?
编辑:正如 Potatoswatter 指出的那样,上述行为是未定义的,因此不涉及接触要字符串化的文件的真正交叉编译器预处理器技术可能是不可能的(第一个找出令人发指的人对大多数/所有编译器都有效的 hack 得到了答案)。出于好奇,我最终执行了此处第二个响应中的建议……也就是说,我将STRINGIFY
宏直接添加到了我包含的 OpenCL 文件中:
在somefile.cl
:
STRINGIFY(
... // Lots of OpenCL code
)
在somefile.cpp
:
#define STRINGIFY(src) #src
inline const char* Kernels() {
static const char* kernels =
#include "somefile.cl"
;
return kernels;
}
这适用于我尝试过的编译器(Clang 和 GCC,因为它在宏中没有预处理器指令),并且至少在我的上下文中不是太大的负担(即,它没有t 干扰语法高亮/编辑 OpenCL 文件)。像这样的预处理器方法的一个特点是,由于相邻的字符串被连接起来,你可以写
inline const char* Kernels() {
static const char* kernels =
#include "utility_functions.cl"
#include "somefile.cl"
;
return kernels;
}
并且只要 STRINGIFY 宏在两个.cl
文件中,字符串就会连接起来,允许您模块化 OpenCL 代码。