Search code examples
c++cudacmakedllexportnvcc

How to add definitions for cuda source code in cmake


I am on Visual Studio 2013, Windows 10, CMake 3.5.1.

Everything compiles properly with standard C++, for example:

CMakeLists.txt

project(Test)

add_definitions(/D "WINDOWS_DLL_API=__declspec(dllexport)")
add_definitions(/D "FOO=1")

set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/Test.cpp)    
set(PROJECT_INCS ${PROJECT_SOURCE_DIR}/include/Test.h)

include_directories(${PROJECT_SOURCE_DIR}/include)

add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})

Test.h

class WINDOWS_DLL_API Test{
 public:
  Test();
};

Test.cpp

#include "Test.h" 

Test::Test(){
  int a = 0;
  if (FOO) a++;
}

However, simply changing the CMakeLists to compile the exact same code with CUDA NVCC results in "identifier FOO and WINDOWS_DLL_API is undefined":

project(Test)

add_definitions(/D "WINDOWS_DLL_API=__declspec(dllexport)")
add_definitions(/D "FOO=1")

set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/Test.cu)    
set(PROJECT_INCS ${PROJECT_SOURCE_DIR}/include/Test.cuh)

include_directories(${PROJECT_SOURCE_DIR}/include)

find_package( CUDA REQUIRED )

cuda_add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})

After spending some time googling, the closest I get is changing the syntax of add_definitions as shown below which works for "FOO" but not for "WINDOWS_DLL_API". The error message is "nvcc fatal : A single input file is required for a non-link phase when an outputfile is specified". Note that if this syntax is applied on standard C++ an error will occur.

project(Test)

add_definitions("-DWINDOWS_DLL_API=__declspec(dllexport)")
add_definitions("-DFOO=1")

set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/src/Test.cu)    
set(PROJECT_INCS ${PROJECT_SOURCE_DIR}/include/Test.cuh)

include_directories(${PROJECT_SOURCE_DIR}/include)

find_package( CUDA REQUIRED )

cuda_add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})

I also verified that without specifying the definitions in CMake everything compiles even with CUDA NVCC like below:

Test.h

#define WINDOWS_DLL_API __declspec(dllexport)

class WINDOWS_DLL_API Test{
 public:
  Test();
};

Test.cpp

#include "Test.h" 
#define FOO 1

Test::Test(){
  int a = 0;
  if (FOO) a++;
}

How can I specify a macro (specifically __declspec(dllexport)) for a cuda source code using CMake?


Solution

  • Since you've requested it in the comments, here is how I/we do it in our libraries.

    A general header file defines the actual compiler visibility attribute based on a preprocessor flag (and some internal default flags: _WINxx):

    // eximport.h
    #pragma once
    
    #if defined(_WIN32) || defined(_WIN64)
    #define DECL_EXPORT __declspec(dllexport)
    #define DECL_IMPORT __declspec(dllimport)
    #else
    #define DECL_EXPORT
    #define DECL_IMPORT
    #endif
    
    #if defined(mylib_SHARED) || defined(mylib_STATIC)
    #ifdef mylib_SHARED
    #define MYLIB_API DECL_EXPORT
    #else
    #define MYLIB_API
    #endif
    #else
    #define MYLIB_API DECL_IMPORT
    #endif
    

    And use it in the way of

    #include "eximport.h"
    
    class MYLIB_API MyLibClass
    {
      //
    };
    

    In your CMake you just do

    # in case myLib is build as shared
    target_add_definition(myLibTarget mylib_SHARED)
    
    # or
    
    # in case myLib is build as static
    target_add_definition(myLibTarget mylib_STATIC)
    

    If myLib is used somewhere (either static or shared) don't define any.

    Note: With CMake's add_definitions/target_add_definitions commands you don't (actually shouldn't) need to explicitly specify the compiler flag (/D/-D). CMake will do that for you when the arguments of those commands are CMake ;-lists.


    A more general approach (including a cross-platform solution) should be possible with some macro (black) magic using GitHub:Eyenseo/ABI. (Disclaimer: I haven't tested it yet.)