Search code examples
pythonc++cmakeswig

cmake problem of target type when using swig with C++17


Things are getting confused for me, so I hope to be clear.

I made a c++17 library (called here myLib), and I bind it with python using swig. Everything is working when I compile by hand. Now, I would like to automatize and clean my work using cmake: no problem for the library.

But things are getting more obscure to me when it comes to creating the binding with cmake.

I came with the following cmake sample:

include(FindSWIG)

find_program(SWIG_PATH swig)
find_package(SWIG 4.0 COMPONENTS python)

include(UseSWIG)

find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)

set(CMAKE_SWIG_FLAGS -py3)

message("PYTHONLIBS_VERSION_STRING: ${PYTHONLIBS_VERSION_STRING}")
message("CMAKE_SWIG_FLAGS: ${CMAKE_SWIG_FLAGS}")

add_custom_target(
     binding_target
     )

include_directories("${PROJECT_SOURCE_DIR}/external/include" "${PROJECT_SOURCE_DIR}/include" ${PYTHON_LIBRARIES})
# If I use the following line instead to the previous, I get an error of target type non-compilable
# target_include_directories(binding_target "${PROJECT_SOURCE_DIR}/external/include" "${PROJECT_SOURCE_DIR}/include" ${PYTHON_LIBRARIES})


set_source_files_properties(py_myLib.i PROPERTIES CPLUSPLUS ON)

# If I use the following line, I get an error of target type non-compilable.
# target_compile_features(binding_target SHARED cxx_std_17)

swig_add_library(binding_target 
     TYPE SHARED 
     LANGUAGE python 
     SOURCES py_myLib.i
)
swig_link_libraries(binding_target ${PYTHON_LIBRARIES} USE_TARGET_INCLUDE_DIRECTORIES)

With the previous code, the command cmake .. is exiting without error, but the compilation with make is returning errors as the compiler is not using the option -std=c++17 to compile. (by the way, I am wondering why make is compiling while make binding_target does nothing, I would expect the opposite.)

I tried to add a C++17 feature to the compilation with the line target_compile_features but then, I get an error from cmake .. about a target_compile_features called with non-compilable target type

So my question is: how can I build properly (inside a target) the swig binding with cmake (precising the include directories and compilation option for this target) ?


Solution

  • I came up with this solution (do not hesitate to improve it):

    include(FindSWIG)
    
    find_program(SWIG_PATH swig)
    find_package(SWIG 4.0 COMPONENTS python)
    
    include(UseSWIG)
    
    find_package(PythonLibs 3 REQUIRED)
    find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)
    
    set(CMAKE_SWIG_FLAGS -py3)
    
    message("PYTHONLIBS_VERSION_STRING: ${PYTHONLIBS_VERSION_STRING}")
    message("CMAKE_SWIG_FLAGS: ${CMAKE_SWIG_FLAGS}")
    
    
    # 
    set_source_files_properties(py_myLib.i PROPERTIES CPLUSPLUS ON)
    set_property(SOURCE py_myLib.i PROPERTY SWIG_MODULE_NAME py_myLib)
    set (UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
    
    swig_add_library(py_myLib 
       TYPE SHARED 
       LANGUAGE python 
       SOURCES py_myLib.i
    )
    
    # For Swig wrapping
    set_property(TARGET py_myLib PROPERTY SWIG_INCLUDE_DIRECTORIES 
       "${PROJECT_SOURCE_DIR}/external/include" 
       "${PROJECT_SOURCE_DIR}/include"
    )
    
    # For Cxx compilation
    set_property(TARGET py_myLib PROPERTY INCLUDE_DIRECTORIES 
       "${PROJECT_SOURCE_DIR}/external/include" 
       "${PROJECT_SOURCE_DIR}/include" 
       ${PYTHON_INCLUDE_PATH}
    )
    set_property(TARGET py_myLib PROPERTY COMPILE_OPTIONS -shared -std=c++17 ) #
    
    # swig_link_libraries( 
    target_link_libraries( py_myLib
       ${PYTHON_LIBRARIES} 
    ) 
    
    # 
    target_include_directories(py_myLib
       PRIVATE
          # where the library itself will look for its internal headers
          ${CMAKE_SOURCE_DIR}/include # 
          ${CMAKE_SOURCE_DIR}/external/include
       PUBLIC
          # where top-level project will look for the library's public headers
          $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
    )