Note: This question has nothing to do with OpenCL per se... check the last paragraph for a succinct statement of my question. But to provide some background:
I'm writing some C++ code that makes use of OpenCL. I like to keep the source for my OpenCL kernels in their own files, to keep coding and maintenance easy (as opposed to embedding the sources directly as string constants in associated C++ code). This inevitably leads to the question of how to load them into the OpenCL runtime once it comes time to distribute binaries---ideally, the OpenCL source is included in the binary, so that the binary doesn't need to be in a specific place within some directory structure to know where the OpenCL source code is.
I'd like to include the OpenCL files as string constants somewhere, and preferably without the use of additional build steps or external tools (for cross-compiler/cross-platform ease of use... i.e., no to xxd
and the like). I thought I'd stumbled on a technique based on the second answer in this thread, like so:
#define STRINGIFY(src) #src
inline const char* Kernels() {
static const char* kernels = STRINGIFY(
#include "kernels/util.cl"
#include "kernels/basic.cl"
);
return kernels;
}
Note that I'd prefer not to embed the STRINGIFY
macro in my OpenCL code if at all possible (as was done in the above referenced SO question). Now, this works wonderfully on the Clang/LLVM compiler, but GCC dies a horrible death ("Unterminated argument list invoking macro STRINGIFY" and various syntax "errors" related to the contents of the .cl files appear). So, clearly this exact technique isn't usable across compilers (haven't tried MSVC, but I'd like it to work there too)... How could I massage it minimally so that it works across compilers?
In summary, I'd like a standards-compliant technique for including the contents of a file as a C/C++ string constant without invoking external tools or polluting the files with extraneous code. Ideas?
EDIT: As Potatoswatter pointed out, the behavior of the above is undefined, so a truly cross-compiler preprocessor technique that doesn't involve touching the files-to-be-stringified probably isn't possible (first person to figure out a heinous hack that does work for most/all compilers gets the answer points). For the curious, I ended up doing what was suggested in the second response here... that is, I added the STRINGIFY
macro directly to the OpenCL files I was including:
In somefile.cl
:
STRINGIFY(
... // Lots of OpenCL code
)
In somefile.cpp
:
#define STRINGIFY(src) #src
inline const char* Kernels() {
static const char* kernels =
#include "somefile.cl"
;
return kernels;
}
This works in the compilers I've tried it in (Clang and GCC as well, since it doesn't have preprocessor directives inside the macro), and isn't too large a burden at least in my context (i.e., it doesn't interfere with syntax highlighting/editing the OpenCL files). One feature of preprocessor approaches like this one is that, since adjacent strings get concatenated, you can write
inline const char* Kernels() {
static const char* kernels =
#include "utility_functions.cl"
#include "somefile.cl"
;
return kernels;
}
and as long as the STRINGIFY macro is in both .cl
files, the strings get concatenated, allowing you to modularize your OpenCL code.
-I
compiler option. Makes for very comfortable file loading... just let the runtime to do it for you! Not sure if it would handle binaries, but I suppose it would work the same. – Rambler