cmake + swig + dependicies
I believe that I have found a solution to your request.
I am currently using a solution, where all relevant dependencies are added such that SWIG
re-generates the interface, whenever any of the headers parsed are modified.
The idea is to make a custom target, which touch a dummy file in addition to deleting the generated interface file. I have put the solution below for a project named fnm
with a wrapper swig_fnm
.
# Method to make swig_fnm.i depend on input headers
execute_process(COMMAND swig -M -python -c++ -I${CMAKE_CURRENT_BINARY_DIR}/.. -I${CMAKE_CURRENT_SOURCE_DIR}/.. swig_fnm.i
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE swig_deps
INPUT_FILE swig_fnm.i)
# Match all lines except the first one until " \"
string(REGEX MATCHALL "\n [^ ]+" temp ${swig_deps})
# Valid dependency extensions
set(valid_ext .h .hpp)
# Dependency list
set(swig_deps_actual)
foreach(t ${temp})
string(STRIP "${t}" t)
# Add to dependency list
if (EXISTS "${t}")
set(filter)
get_filename_component(filter "${t}" EXT)
if (";${valid_ext};" MATCHES ";${filter};")
set(swig_deps_actual ${swig_deps_actual} "${t}")
endif()
endif()
endforeach()
# This makes configure run again, but does not regenerate the SWIG interface.
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${swig_deps_actual})
# All headers except for the single .i file are ignored
swig_add_module(swig_fnm python swig_fnm.i ${swig_fnm_HEADERS} ${swig_deps_actual})
# Removes generated file (if any of the dependent files are changed)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/swig.stamp
COMMAND ${CMAKE_COMMAND} -E remove ${swig_generated_file_fullname}
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/swig.stamp
DEPENDS ${swig_deps_actual} # The dependent files
COMMENT "Removing old SWIG generated file" VERBATIM)
# Custom target for establishing dependency
add_custom_target(
swigtrick
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/swig.stamp)
# Dependency
add_dependencies(_swig_fnm swigtrick)
During configuration you can run swig with the -M flag to generate the dependencies. You can then parse the output of that and pass it as DEPDENDS to add_custom_command.
The output looks like:
test_wrap.c: \
.../swig.swg \
... \
test.i \
test.h
This can be generated with execute_command and needs further processing:
execute_process(COMMAND swig -M <SWIG_ARGUMENTs> OUTPUT_VARIABLES swig_deps)
# Match all lines except the first one until " \"
string(REGEX MATCHALL "\n [^ ]+" temp ${swig_deps})
set(swig_deps)
foreach(t ${temp})
string(STRIP "${t}" t)
set(swig_deps ${swig_deps} "${t}")
endforeach()
...
add_custom_command(... DEPENDS ${swig_deps})
This makes swig depend on all headers that are included in the .i files. If one of the .i or the header files is edited in a way that adds new dependencies you need to reconfigure so cmake knows about it. This can happen automatically if you add CMAKE_CONFIGURE_DEPENDS.
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${swig_deps} test.i)