Search code examples
pythonc++cmakedependenciesswig

Using CMake, how to rebuild Swig wrapper when header file changes


I have a C++ library (called myfibo) and I want to make a python binding modue (called myfibopy) using CMake and Swig.

The first build works perfectly. But if I rename an exposed C++ function, the python module doesn't build anymore because the Swig wrapper (PYTHON_wrap.cxx) is not regenerated.

I have already tried using SWIG_USE_LIBRARY_INCLUDE_DIRECTORIES as explained here but with no success.

What I am doing wrong?

Here is the toy example to reproduce the error:

Directory tree

.
├── CMakeLists.txt
├── myfibo
│   ├── CMakeLists.txt
│   ├── fibo.cpp
│   └── include
│       └── fibo.hpp
└── myfibopy
    ├── CMakeLists.txt
    └── fibo.i

fibo.hpp

#pragma once
void fib(int n);

fibo.cpp

#include "fibo.hpp"
#include <iostream>

void fib(int n)
{
  int a = 0;
  int b = 1;
  while (a < n)
  {
    std::cout << a << " ";
    a = b;
    b = a+b;
  }
  std::cout << std::endl;
}

fibo.i

%module myfibopy

%include fibo.hpp
%{
  #include "fibo.hpp"
%}

./CMakeLists.txt

project(myfibopy)      

cmake_minimum_required(VERSION 3.15) 

add_subdirectory(myfibo)
add_subdirectory(myfibopy)

myfibo/CMakeLists.txt

add_library(myfibo SHARED fibo.cpp)
target_include_directories(myfibo
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>   # unused 
)

myfibopy/CMakeLists.txt

find_package(PythonLibs 3 REQUIRED)
include_directories(${PYTHON_INCLUDE_PATH})

find_package(SWIG 4.0 REQUIRED)
include(${SWIG_USE_FILE})

set(SRC fibo.i)

set_source_files_properties(${SRC} PROPERTIES CPLUSPLUS ON)

swig_add_library(myfibopy LANGUAGE python SOURCES ${SRC})

target_link_libraries(myfibopy PUBLIC myfibo)

# See https://gitlab.kitware.com/cmake/cmake/-/issues/18003
set_target_properties(myfibopy PROPERTIES SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)

First compilation

> cmake -Bbuild -H.
   [...]
> cmake --build build
   [...]

Perfect. Now, build directory exists and I can play with myfibopy module.

After renaming fib into fib2 in fibo.hpp and fibo.cpp

> cmake --build build
Consolidate compiler generated dependencies of target myfibo
[ 20%] Building CXX object myfibo/CMakeFiles/myfibo.dir/fibo.cpp.o
[ 40%] Linking CXX shared library libmyfibo.so
[ 40%] Built target myfibo
[ 60%] Built target myfibopy_swig_compilation
Consolidate compiler generated dependencies of target myfibopy
[ 80%] Building CXX object myfibopy/CMakeFiles/myfibopy.dir/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx.o
./build/myfibopy/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx: In function ‘PyObject* _wrap_fib(PyObject*, PyObject*)’:
./build/myfibopy/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx:2968:3: error: ‘fib’ was not declared in this scope
   fib(arg1);
   ^~~
./build/myfibopy/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx:2968:3: note: suggested alternative: ‘fib2’
   fib(arg1);
   ^~~
   fib2
myfibopy/CMakeFiles/myfibopy.dir/build.make:75: recipe for target 'myfibopy/CMakeFiles/myfibopy.dir/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx.o' failed
make[2]: *** [myfibopy/CMakeFiles/myfibopy.dir/CMakeFiles/myfibopy.dir/fiboPYTHON_wrap.cxx.o] Error 1
CMakeFiles/Makefile2:170: recipe for target 'myfibopy/CMakeFiles/myfibopy.dir/all' failed
make[1]: *** [myfibopy/CMakeFiles/myfibopy.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2

Solution

  • Did you try:

    USE_SWIG_DEPENDENCIES
    New in version 3.20.
    If set to TRUE, implicit dependencies are generated by the swig tool itself. This property is only meaningful for Makefile, Ninja, Xcode, and Visual Studio (Visual Studio 11 2012 and above) generators. Default value is FALSE.
    New in version 3.21: Added the support of Xcode generator.
    New in version 3.22: Added the support of Visual Studio Generators.

    or

    USE_TARGET_INCLUDE_DIRECTORIES
    New in version 3.13.
    If set to TRUE, contents of target property INCLUDE_DIRECTORIES will be forwarded to SWIG compiler. If set to FALSE target property INCLUDE_DIRECTORIES will be ignored. If not set, target property SWIG_USE_TARGET_INCLUDE_DIRECTORIES will be considered.

    src: https://cmake.org/cmake/help/git-stage/module/UseSWIG.html