Sean
Sean

Reputation: 149

unresolved external symbol cuda_library::foo(int) in Visual Studio/CMake

Original question (title: .cu file is processed as a .cpp file in Visual Studio/CMake)

I am trying to add a static library with CUDA code to my C++ project. I have a top level CMakeLists.txt file, a static library that's added from there, and my CUDA-using library that's added from that library (both libraries have their own CMakeLists.txt file. In the root file I have used enable_language(CUDA), in the 1st level library's CMakeLists.txt I have done this:

  add_subdirectory(cuda_library)
  set_target_properties(level_1_lib PROPERTIES POSITION_INDEPENDENT_CODE ON)
  set_target_properties(level_1_lib PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
  target_link_libraries(level_1_lib cuda_library)

and in the CUDA library's CMakeLists.txt:

add_library(cuda_library 
  cuda_library.cu cuda_library.h)

target_include_directories(cuda_library
  INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
  )

A .cpp file in the level 1 library calls an "interface function" I declare in cuda_library.h that is implemented in cuda_library.cu and internally launches a CUDA __global__ kernel this way:

namespace cuda_library {
    __global__
    void real_foo(int number, int *out) { 
        *out = number * 2; 
    }

    inline int foo(int number) { 
        int* x;
        
        cudaMallocManaged(&x, sizeof(int));
        real_foo<<<1,1>>>(number, x); 
        cudaDeviceSynchronize();
        int y = *x;
        cudaFree(x);
        return y;
    } 
}

When I build from Visual Studio (with the CMake extension enabled, and it uses ninja as a generator), though, the build does not like the __global__ keyword, making me think that the .cu file is treated like a normal .cpp file and not compiled as CUDA code.

What am I doing wrong?

Edit to better clarify the errors I get

If I hit Visual Studio's "Build All" (or run CMake with ninja from the Visual Studio command prompt, which normally can compile simple CUDA examples with nvcc, the errors are the same) and I'm not on the cuda_library.cu file, I only get errors that boil down to unresolved external symbol cuda_library::foo(int), which from some research means that the function might be declared but not defined. This makes sense if the header is included but the .cu file is not correctly compiled.

However, only if I make the .cu file active VS shows me the errors that are related to the CUDA code treated like C++ code, and they don't have the normal error logo (like the first error in this image), but the one you can see in the second and third one:

Possible intellisense errors

so could they simply be Intellisense errors that do not appear while building?

In that case there might be another cause why the static library's implementation is not properly linked. To be more thorough about it, this is the header (cuda_library.h):

#ifndef _CUDA_LIBRARY_H_
#define _CUDA_LIBRARY_H_

namespace cuda_library {
    inline int foo(int number);
}

#endif

and I try to import and use it this way in the .cpp file where the unresolved external symbol cuda_library::foo(int) error occurs:

#include "cuda_library/cuda_library.h"

printf("Result from the GPU: %d\n", cuda_library::foo(5));

Funnily enough I've also tried

#include <cuda_library.h>

and the result is the same, maybe because CMake includes it in what would be the include search path?

The project has this structure:

root_dir\
  CMakeLists.txt
  libs\
    CMakeLists.txt
    level_1_lib\
      CMakeLists.txt
      file_using_cuda_lib.cpp
      cuda_library\
        CMakeLists.txt
        cuda_library.cu
        cuda_library.h

I really can't understand what's exactly going wrong, so any help is well accepted.

Upvotes: 3

Views: 651

Answers (2)

Sean
Sean

Reputation: 149

I realized that there were two main things keeping this from working:

  • The inline in the function signature seemed to break it on its own (and at this point I do not care enough about it in my code to not remove it, if someone wants to investigate more on it they're free to do it).
  • The enable_language(CUDA) has to be in the top level CMakeLists.txt file.

Fixing these two things it builds without any issues.

Upvotes: 0

alfC
alfC

Reputation: 16242

You have to add a property to each source cpp file to say that it is really a cuda source.

    set_source_files_properties(file.cpp PROPERTIES LANGUAGE CUDA)

After enabling CUDA as a language (enable_language(CUDA)).

We use that, but I don't know if it is a good practice (feedback on that is appreciated).

Upvotes: 1

Related Questions