Hello everyone.
I am looking for help in either configuring properly my project or determining if this is a bug that should be reported on gitlab. I have prepared a minimalistic project that reproduces the issue (but as a new user I cannot attach it… uhhh… I pasted all contents at the end).
The issue is that after performing changes in header files that SWIG template inlcudes (like %include mylib.hpp
), the autogenerated SWIG wrapper is not re-generated and resulting module is not recompiled.
If you take my code, create a build directory, navigate to it and execute make check
, a failing test will get executed. It fails with SWIG error which says that value provided to function is too large and it overflows int8_t
.
Hello world
error: in method 'add1', argument 1 of type 'int8_t' (SWIG_OverflowError)
To make it pass, you should edit mylib.cpp/hpp
and change int8_t
in function add1
to uint8_t
, both in argument and return value.
After you make this change, you should expect that autogenerated SWIG module would be re-generated and resulting code re-compiled to reflect this change. Unfortunatelly, this is not what happens - running the test case again with make check
recompiles target libmylib
but not mylib_octave
, so it prints the same kind of error about overflowing int8_t
(where at this point it should be uint8_t
and there should be no overflow).
If you now execute make clean && make check
, the test passes.
This issue does not happen if I provide relative paths to included files in mylib_octave.swg
, like if I write %include ../src/mylib.hpp
instead of simple %include mylib.hpp
. Following this trail, I’ve noticed that using relative paths to included file properly adds this file to build/test/CMakeFiles/mylib_octave_swig_compilation.dir/depend.make
as a dependency of .stamp
file. This suggests that SWIG module/wrapper generation is not properly using include directories that I have configured, or I did this wrong.
I am using CMake version 3.16.4, but so far didn’t find any substantial changes in recent versions in UseSWIG module that would help with my issue.
The directory tree is as follows:
cmake_bug_mvp
│ CMakeLists.txt
│
├───cmake
│ FindOctave.cmake
│
├───include
│ external_interface_here
│
├───src
│ mylib.cpp
│ mylib.hpp
│
└───test
CMakeLists.txt
mylib_octave.swg
run_octave.sh
test_mylib.m
Contents of files
./CMakeLists.txt
cmake_minimum_required(VERSION 3.16.3)
project(cmake_bug_mvp VERSION 0.1.0)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(test EXCLUDE_FROM_ALL)
add_library(mylib
${CMAKE_CURRENT_SOURCE_DIR}/src/mylib.cpp
)
target_include_directories(mylib
PUBLIC include
PRIVATE src
)
include(CheckPIESupported)
check_pie_supported()
set_property(TARGET mylib PROPERTY POSITION_INDEPENDENT_CODE TRUE)
src/mylib.hpp
#pragma once
#include <cstdint>
void hello(char * who);
int8_t add1(int8_t x);
src/mylib.cpp
#include "mylib.hpp"
#include <iostream>
void hello(char * who) {
std::cout << "Hello " << who << std::endl;
}
int8_t add1(int8_t x){
return x+1;
}
test/CMakeLists.txt
find_package(Octave)
find_package(SWIG 4.0)
cmake_policy(SET CMP0078 NEW)
include(UseSWIG)
set(UseSWIG_MODULE_VERSION 2)
set(UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
set(SWIG_SOURCE_FILE_EXTENSIONS ".i" ".swg")
set_property(SOURCE mylib_octave.swg PROPERTY CPLUSPLUS ON)
swig_add_library(mylib_octave
LANGUAGE Octave
SOURCES mylib_octave.swg
)
set_property(TARGET mylib_octave PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)
set_property(TARGET mylib_octave PROPERTY SWIG_GENERATED_INCLUDE_DIRECTORIES ${OCTAVE_INCLUDE_DIR}/../)
target_link_libraries(mylib_octave mylib)
target_include_directories(mylib_octave
PRIVATE ../src
)
enable_testing()
add_executable(run_octave IMPORTED)
set_property(TARGET run_octave PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/run_octave.sh)
add_dependencies(run_octave mylib_octave)
function(add_octave_test name)
add_test(NAME ${name}
COMMAND run_octave ${CMAKE_CURRENT_SOURCE_DIR}/${name}.m
)
endfunction()
add_octave_test(test_mylib)
add_custom_target(
check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS run_octave
)
test/mylib_octave.swg
%module mylib_octave
%{
#include "mylib.hpp"
#define SWIG_OCTAVE_NO_SEGFAULT_HACK
%}
%include "stdint.i"
%include "typemaps.i"
%include "mylib.hpp"
test/run_octave.sh
#!/usr/bin/env bash
octave-cli -qfH "$1"
[ $? -eq 0 ] || exit 1
test/test_mylib.m
mylib_octave
hello("world")
add1(254)
exit(0)