Файлы CUDA * .obj не обрабатываются компоновщиком Visual Studio

Я использовал 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 Runtime (интеграция 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, но это ничего не дало.

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

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

Вопрос в том:

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

Пожалуйста, дайте мне знать, если я должен расширить вопрос, чтобы сделать его более ясным, т.е. указать параметры компилятора 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        

Это похоже на проблему искажения символа. __cdecl addWithCuda( предполагает, что компоновщик ищет связь C, а не связь C++

talonmies 02.12.2018 19:13

Отредактировано @talonmies: явная пометка указанной функции с помощью extern "C" аналогичным образом приводит к LNK2019; Спасибо за предложение!

haykoandri 02.12.2018 19:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
673
1

Ответы 1

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

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

Во-вторых, я указал имя объектного файла в 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.

Другие вопросы по теме