Yoosuf
Yoosuf

Reputation: 463

CMake CUDA C++ Linking Error - Undefined reference to `someFunction()`

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

Answers (1)

Dan Nestor
Dan Nestor

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:

  • It's a bad idea to 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.
  • Consider using target_include_directories instead of include_directories, to limit the effect to just the appropriate target.

Upvotes: 2

Related Questions