undefined reference to `cuCtxGetCurrent` while getting CUDA context for OptiX

2.4k views Asked by At

I'm trying to learn how to implement OptiX into my C++ project. One of the first steps is to get the current CUDA context with cuCtxGetCurrent(&some_CUcontext_variable), however I'm getting a compile time error saying that I've made an undefined reference to cuCtxGetCurrent.

Here's what I have:

  • I'm following code from this repo to learn about OptiX and I'm on example 2 (where you get the CUDA context).
  • In my code (main.cpp) I have included cuda_runtime.h, device_launch_parameters.h, optix.h, and optix_stubs.h, but I'm still getting the error at compile time.
  • Interestingly, my IDE, JetBrains' CLion, is not showing any undefined reference errors/warnings inline. Errors only show up when I compile.
  • In my CMakeLists.txt, I've used find_package(CUDAToolkit REQUIRED) to get CUDA. I then used target_link_libraries{ ... CUDA::cudart} to link in CUDA.

I believe this error is linker related, so I'm assume I'm missing something in my CMakeLists, but I don't know what. Please let me know how I can fix this issue!

Thank you in advanced for your help!


Update #2: Solved

It's moments like this make make me pull my hair out: all I had to do with literally put cuda in my target link libraries. Not -lcuda or CUDA::cuda, just cuda. Somehow that linked in the drivers and it looks to be compiling now.


[OLD, BUT KEPT FOR REFERENCE] Update #1: Here's my CMakeLists.txt.

Sorry for the lack of code in my original post. I was trying to avoid pasting large chunks of arbitrary code.

cmake_minimum_required(VERSION 3.17)
project(My_Project_Name CUDA CXX)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_MODULE_PATH
    "${CMAKE_SOURCE_DIR}/cmake"
    ${CMAKE_MODULE_PATH})

find_package(CUDAToolkit REQUIRED)
find_package(OptiX REQUIRED VERSION 7.0)

add_executable(
    ${PROJECT_NAME}
    main.cpp [and other cpp and cu files])

# For project
set_target_properties(
    ${PROJECT_NAME}
    PROPERTIES
    CUDA_SEPARABLE_COMPILATION ON
)
target_compile_options(
    ${PROJECT_NAME}
    PRIVATE
    $<$<COMPILE_LANGUAGE:CUDA>:
    -arch=sm_61
    -gencode arch=compute_52,code=sm_52>
)
target_include_directories(
    ${PROJECT_NAME}
    PRIVATE
    include
    ${OptiX_INCLUDE}
)
target_link_libraries(
    ${PROJECT_NAME}
    PRIVATE
    CUDA::cudart
    CUDA::cublas
)
2

There are 2 answers

3
einpoklum On BEST ANSWER

As @talonmies notes, CUDA has two (official) host-side APIs: The "CUDA Runtime API" and the "CUDA Driver API"; you can read about the difference between them here.

You have mentioned files and CMake identifiers relating to the Runtime API: cuda_runtime.h, CUDA::cudart. But - "CUDA Contexts" are concepts of the Driver API, and cuCtxGetCurrent() etc. are driver API calls.

Specifically, an "undefined reference" is indeed a linker error. In your case, you need to link with the CUDA driver. As a library, on Linux systems, that's called libcuda.so. For that to happen, and for your executable named ERPT_Render_Engine, you need to add the command:

target_link_libraries(ERPT_Render_Engine cuda)

I'll also say that the CMakeLists.txt you listed above looks weird, because it defines dependencies for a target that doesn't exist - the project name; your relevant target is your executable.

Additionally - a CUDA context doesn't exist merely by virtue of you creating your process. You need to initialize the driver, create a context and make it current - or have something else do that for you (like a library) - before you can obtain the current context using cuCtxGetCurrent().


Finally, and in case you're interested, I am the author of the C++ cuda-api-wrappers library, which covers (most of) the host-side functionality of both the driver and runtime APIs. Some example code:

cuda::initialize_driver();
(cuda::device::count() > 0) or die_("No CUDA devices on this system") {}
auto device_id =  cuda::device::default_device_id;
auto device = cuda::device::get(device_id);
auto context = cuda::context::create(device);
//etc. etc.

and when you using it within CMake (explained on the repository page), the dependencies are taken care of. But again - you really don't have to use this, it's just a convenience.

0
Todd On

Using plain old "cuda" may work, but it does create a "CUDA" target for you to use, so you should probably use that. I use something like the following.

target_link_libraries(${TARGET_NAME}
    PUBLIC CUDA::cudart
    PUBLIC CUDA::cuda_driver
)

CMake Find CUDA Toolkit Documentation