Файлы CUDA * .obj не обрабатываются компоновщиком Visual Studio - PullRequest
0 голосов
/ 02 декабря 2018

Я использовал CMake 3.13 для создания решения Visual Studio (VS 2017) с одним проектом «cudatest».Проект содержит два файла:

main.cpp
kernel.cu

Чтобы включить поддержку CUDA, я использовал скрипт, предоставленный Nvidia, то есть FindCUDA.cmake, в отличие от использования последней поддержки CMake для приложений на основе CUDA (яне пользуюсь этой последней поддержкой, потому что она не позволяет мне делать определенные вещи, поэтому мне нужно прибегнуть к FindCUDA).

CMake успешно генерирует проект, который содержит два вышеупомянутых файла.Не вдаваясь в подробности, файл main.cpp содержит объявление функции:

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);

Вы можете распознать его как функцию, которая создается по умолчанию при создании нового проекта в Visual Studio с использованием типа среды выполнения CUDA.проекта (интеграция NVIDIA CUDA для Visual Studio).

Принимая во внимание, что файл kernel.cu содержит определение указанной функции:

__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
    int *dev_a = 0;
    int *dev_b = 0;
    int *dev_c = 0;
...
    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);
...
}

Оба файла успешно скомпилированы, и компоновщик выдает ошибку:

Error   LNK2019 unresolved external symbol "enum cudaError __cdecl addWithCuda(int *,int const *,int const *,unsigned int)" ...

Следует отметить, что файл * .obj для kernel.cu успешно создан NVCC.

Однако файлы * .obj помещаются в разные каталоги, что заставляет меня думать, что это может быть проблемой, а также обнаруживает, что я не понимаю, где компоновщик Visual Studio ищет файлы * .obj вдля разрешения символов. Файл

main.obj заканчивается в build\cudatest.dir\Debug, где build - папка, содержащая созданное решение. Файл

cudatest_generated_kernel.cu.obj заканчивается в build\CMakeFiles\cudatest.dir\Debug

Конфигурация путей к выходным файлам настраивается скриптом FindCUDA.cmake.

Я пытался поместить cudatest_generated_kernel.cu.obj в ту же папку, что и main.obj, но ничего не сделал.

Установка свойства компоновщика 'Show Progress' на /VERBOSE показала, что компоновщик даже не ищет cudatest_generated_kernel.cu.obj, чтобы попытаться найти соответствующие символы.

=====================

Вопрос:

Учитывая, что я собираю ядро ​​CUDA в файл * .obj, используя NVCC, ифайл * .cpp в свой собственный файл * .obj, используя CL.exe, как я могу сказать компоновщику проверить ядро ​​cuda * .obj file?

Пожалуйста, дайте мне знать, если мне нужно расширить вопрос, чтобы сделать его более понятным, то есть указать параметры компилятора NVCC, которые я использовал, предоставить полный список кода и т. д. Любые подсказки и указатели в правильном направлении будутс благодарностью!

РЕДАКТИРОВАТЬ: По предложению @talonmies для каждого пользователя (__cdecl addWithCuda может указывать, что компоновщик ищет связь C), я явно пометил функцию addWithCuda с extern "C" в main.cpp и kernel.cu:

extern "C" cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)

Теперь ошибка выглядит следующим образом:

Error   LNK2019 unresolved external symbol addWithCuda referenced in function main  cudatest    D:\projects\vs2017\TestCUDA_CMake\build\main.obj        

1 Ответ

0 голосов
/ 06 декабря 2018

Таким образом, оказалось, что если проект Visual Studio не имеет интеграции CUDA (щелчок правой кнопкой мыши -> свойства -> свойства компоновщика CUDA C ++ / CUDA), ядра CUDA, скомпилированные в файлы * .obj, автоматически не рассматриваются компоновщиком хоста.

Во-первых, я добавил путь к скомпилированным файлам CUDA * .obj в Linker-> Дополнительные каталоги библиотек.

Во-вторых, я указал имя объектного файла в Linker-> Input-> Additional Dependencies.

Это решило проблему.Следует отметить, что изначально я использовал комбинацию нативных команд cmake и макросов FindCUDA.cmake:

add_executable(cudatest main.cpp kernel.cu)
CUDA_WRAP_SRCS(cudatest OBJ generated_files kernel.cu ${cmake_options} OPTIONS ${options} )

Макрос CUDA_WRAP_SRCS добавляет пользовательские шаги сборки, которые заставляют Visual Studio вызывать nvcc вместо CL для компиляции CUDA.ядра.Этот макрос также вызывается из макросов CUDA_ADD_EXECUTABLE и CUDA_ADD_LIBRARY, которые также указывают все пути к сгенерированным файлам * .obj, которые уже должны быть включены в сгенерированный проект Visual Studio, тем самым сохраняя дополнительные усилия, которые я описал выше.

Кроме того, CUDA_ADD_EXECUTABLE и CUDA_ADD_LIBRARY также облегчают генерацию проектов для ядер, для которых включен код перемещаемого устройства, что означает, что должен быть предварительный шаг, который позволит устройству связать все файлы CUDA * .obj сперемещаемый код устройства в них, в промежуточный файл CUDA * .obj, который может использоваться компоновщиком хоста (в противном случае компоновщик хоста не сможет обрабатывать файлы * .obj, содержащие код перемещаемого устройства).Вышеупомянутые макросы также будут включать зависимости для этого промежуточного сгенерированного файла CUDA * .obj.

...