in my opinion there is only one way to get those projects nearly compatible with any C++ compiler (regarding some quality aspects included).
One way is to embed the code via char, but you dont get any code highlighting and have to escape some chars and so one. It’s the most annoying way and not nice, I think!
Another way to embed your opencl code in the binary is to use resources. Just declare your files as resource and you will get an ID for them to get the resource at runtime anywhere, but it’s ugly code, and I don’t know, how G++ solves it!?
And now the one and only way with respect to testing issues:
There are three types of code:
- special host code
- special device code
- C99 code
The special host code cannot be run by the device, and the other way round. The only code you can test is the host code (since running in your development environment) and the C99 called from the host. The device code cannot be tested that easy (e.g. asserts). So you have to reduce the device code to write more C99 code. Think of only implementing helper methods your host can test, before the device invokes it. It’s not the same machine code but the same source code and same behavior!
So create your yourname.h.cl and yourname.cpp.cl file. Via preprocessor macros you can separate your source between host code, device code, and C99 pure code, included by the host and by the device. Just set the build options when compiling the opencl code.
See my current project fcocl (means “fast convolution open cl”):
/* differ between host and opencl code */
# ifndef fcocl_IS_HOST
# error IS_HOST has to be defined to decide whether to gather host or opencl code!
# else /* ifndef fcocl_IS_HOST */
# if fcocl_IS_HOST == 0
# define _fcocl_OPENCLCODE
# elif fcocl_IS_HOST == 1 /* if fcocl_IS_HOST == 0 */
# define _fcocl_HOSTCODE
# else /* if _fcocl_IS_HOST == 1 */
# error fcocl_IS_HOST has a wrong value!
# endif /* if fcocl_IS_HOST != 0 && fcocl_IS_HOST != 1 */
# endif /* ifdef fcocl_IS_HOST */
/* type definition to use unique file,
host and device */
# ifdef _fcocl_HOSTCODE
/* # define __CL_ENABLE_EXCEPTIONS */
# define __NO_STD_VECTOR
# ifdef __CL_ENABLE_EXCEPTIONS
# pragma warning(push)
# pragma warning(disable:4290)
# include <CL/cl.hpp>
# ifdef __CL_ENABLE_EXCEPTIONS
# pragma warning(pop)
typedef cl_uchar fcocl_uchar;
typedef cl_char fcocl_char;
typedef cl_ushort fcocl_ushort;
typedef cl_short fcocl_short;
typedef cl_uint fcocl_uint;
typedef cl_int fcocl_int;
typedef cl_ulong fcocl_ulong;
typedef cl_long fcocl_long;
typedef cl_half fcocl_half;
typedef cl_float fcocl_float;
# else /* ifdef _fcocl_HOSTCODE */
typedef unsigned char fcocl_uchar;
typedef char fcocl_char;
typedef unsigned short fcocl_ushort;
typedef short fcocl_short;
typedef unsigned int fcocl_uint;
typedef int fcocl_int;
typedef unsigned long fcocl_ulong;
typedef long fcocl_long;
typedef half fcocl_half;
typedef float fcocl_float;
# endif /* ifndef _fcocl_HOSTCODE */
/* C99 code */
__kernel void fcocl_tfunc(
/* size is kernel_size */
__global const fcocl_sample *g_h_real,
__global const fcocl_sample *g_h_imag,
/* size is fcocl_FFT_SIZE */
__global fcocl_sample *g_uninit_H_real,
__global fcocl_sample *g_uninit_H_imag
buildOptions << " -D fcocl_IS_HOST=0 "; // preprocessor define
buildOptions << " -I \"X:\\Development\\C++\\YourProject\""; // has to be dynamic e.g. ".\\" for current directory
So the only code to compile ist the “#include yourname.cpp.cl” and the include directory can be given via build options. In VS C++ you can set the running-in directory, but it is actually not in the Debug or Release, but the parent folder where the source is! So you can set it to “.\” as the current running-in folder, any absolute path or getting the location of the .exe file via WinAPI.
The only disadvantage is, e.g. providing a .exe file on your website you have to provide the two files (binary and opencl code). If you use archives the user must not run the binary out of the archiving program, since the binary is extracted to any temporary folder.