Reputation: 463
I am trying to call a CUDA kernel from a C++ program. I am using CMake to manage the build process.
CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(SeamCarving LANGUAGES CUDA CXX VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CUDA_STANDARD_REQUIRED True)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
file(GLOB CPU_SRC_FILES
"src/*.cpp"
"src/*.h"
)
add_library(MyLibrary STATIC src/Kernels.cu src/Kernels.cuh)
set_target_properties( MyLibrary PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
set(SOURCES ${CPU_SRC_FILES})
add_executable(myProject ${SOURCES})
target_link_libraries( myProject PRIVATE ${MyLibrary} )
target_link_libraries( myProject PRIVATE ${OpenCV_LIBS} )
MyClassA.cpp (This file calls the CUDA kernel in the .cu file through a function)
#include "MyClassA.h"
MyClassA::MyClassA() : MyClassB()
{
myHelloWorldKernel();
}
MyClassA.h
#include <iostream>
#include <opencv2/opencv.hpp>
#include "MyClassB.h"
#include "Kernels.cuh"
class MyClassA : public MyClassB
{
public:
MyClassA();
};
Kernels.cuh
#ifndef MY_KERNEL_H
#define MY_KERNEL_H
void myHelloWorldKernel();
#endif
Kernels.cu
#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include "Kernels.cuh"
__global__ void helloWorld() {
printf("Hello!\n");
}
void myHelloWorldKernel()
{
dim3 block(2, 2);
dim3 grid(3, 3);
helloWorld<<<grid, block>>>();
cudaDeviceSynchronize();
printf("Completed!\n");
}
And this is the following error I am getting from CMake when I try to build:
...
[build] [ 87%] Linking CUDA static library libMyLibrary.a
[build] [ 87%] Built target MyLibrary
[build] [100%] Linking CXX executable myProject
[build] CMakeFiles/myProject.dir/src/MyClassA.cpp.o: In function `MyClassA::MyClassA()':
[build] /PATH/src/MyClassA.cpp:5: undefined reference to `myHelloWorldKernel()'
[build] collect2: error: ld returned 1 exit status
...
I am not quite sure what the problem is. Any help appreciated.
Upvotes: 0
Views: 1235
Reputation: 2531
MyLibrary
is not a variable, it's a CMake target. The syntax ${variable}
is used to substitute the contents of a variable. The correct syntax to create a dependency to MyLibrary
is this:
target_link_libraries( myProject PRIVATE MyLibrary )
The syntax is probably correct in the case of ${OpenCV_LIBS}
. It's common practice that packages define a variable that contains the names of the libraries that need to be included to use the package. So in your case, ${OpenCV_LIBS}
might evaluate to something like "OpenCV_lib1 OpenCV_lib2"
.
A few other improvements you could make:
GLOB
your source files. The glob will be evaluated at configure-time, and if you add files to your directory without re-running CMake configuration, they will not be taken in consideration.
The canonical way AFAIK is to just list your sources explicitly.target_include_directories
instead of include_directories
, to limit the effect to just the appropriate target.Upvotes: 2