Примечание. Этот вопрос не имеет ничего общего с OpenCL per se... проверьте последний абзац для краткого изложения моего вопроса. Но для обеспечения некоторого фона:
Я пишу код на С++, который использует OpenCL. Мне нравится сохранять исходный код для своих ядер OpenCL в своих собственных файлах, чтобы упростить кодирование и обслуживание (в отличие от встраивания источников непосредственно в виде строковых констант в связанном С++-коде). Это неизбежно приводит к вопросу о том, как загрузить их в рабочую среду OpenCL, когда придет время для распространения двоичных файлов. В идеале источник OpenCL включен в двоичный файл, так что двоичный код не должен находиться в определенном месте в какой-либо структуре каталогов, чтобы узнать, где находится исходный код OpenCL.
Я хотел бы включать файлы OpenCL в виде строковых констант где-то и, желательно, без использования дополнительных шагов сборки или внешних инструментов (для кросс-компилятора/кросс-платформенной простоты использования... т.е. no to 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 умирает ужасной смертью (появляется список Unterminated arguments, вызывающий макрос STRINGIFY) и различные синтаксические "ошибки", связанные с содержимым файлов .cl). Итак, ясно, что эта точная техника не применима для компиляторов (не пробовал MSVC, но я бы хотел, чтобы она там тоже работала)... Как я мог бы массировать ее минимально, чтобы она работала через компиляторы?
В заключение я хотел бы, чтобы стандарт, совместимый со стандартами, включал содержимое файла в виде строковой константы C/С++, не вызывая внешние инструменты или не загрязнял файлы посторонним кодом. Идеи?
EDIT. Как отметил Potatoswatter, поведение вышеопределено undefined, поэтому метод препроцессора по-настоящему кросс-компилятора, который не предполагает касания файлов, (первый человек, чтобы выяснить отвратительный взлом, который работает для большинства/всех компиляторов, получает точки ответа). Для любопытных я в конечном итоге сделал то, что было предложено во втором ответе здесь... то есть я добавил макрос 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, так как он не имеет директив препроцессора внутри макроса) и не является слишком большим бременем, по крайней мере, в моем контексте (т.е. он не мешает синтаксическому освещению/редактированию файлов OpenCL). Одна из особенностей подхода к препроцессору, подобная этой, заключается в том, что, поскольку смежные строки конкатенируются, вы можете написать
inline const char* Kernels() {
static const char* kernels =
#include "utility_functions.cl"
#include "somefile.cl"
;
return kernels;
}
и до тех пор, пока макрос STRINGIFY находится в обоих файлах .cl
, строки объединяются, что позволяет вам модулизовать ваш код OpenCL.