Дурачество препроцессора (преобразование #include)

Примечание: этот вопрос не имеет ничего общего с OpenCL как таковым ... проверьте последний абзац, чтобы найти краткое изложение моего вопроса. Но чтобы предоставить некоторую предысторию:

Я пишу код на C ++, который использует OpenCL. Мне нравится хранить исходный код моих ядер 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, поведение вышеупомянутого не определено, поэтому метод препроцессора по-настоящему кросс-компилятора, который не включает касание файлов, которые необходимо преобразовать в строку, вероятно, невозможен (Первый человек, обнаруживший чудовищный взлом, который действительно работает для большинства / всех компиляторов, получает очки ответа). Для любопытных я закончил тем, что было предложено во втором ответе здесь ... то есть я добавил макрос 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.

17
задан Community 23 May 2017 в 11:58
поделиться