Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cmake + swig + dependicies

Tags:

c++

cmake

swig

Today I tried to use combination of "cmake + swig" to generate bindings for my code. Basically it works:

set(SWIG_EXECUTABLE "/usr/bin/swig")
find_package(SWIG REQUIRED)
include(${CMAKE_CURRENT_SOURCE_DIR}/UseSWIG.cmake)

set(CMAKE_SWIG_FLAGS -package example)
set(CMAKE_SWIG_OUTDIR "${CMAKE_CURRENT_SOURCE_DIR}/example")
set_source_files_properties(native.i PROPERTIES CPLUSPLUS ON)
SWIG_ADD_MODULE(core Java native.i lib.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})

with such native.i:

%module native
%include "lib.hpp"
%{
#include "lib.hpp"
  %}

But if I change lib.hpp build system cmake build not call swig to regenerate code. So I have to touch native.i to get it works, this is very annoying.

I found -M option of swig to generate dependencies, Is any idea how use it to fix UseSWIG.cmake?

UseSWIG.cmake just uses add_custom_command for generation, so I need somehow add_custom_command depend on dynamic set of files, not static?

like image 378
fghj Avatar asked Sep 06 '16 21:09

fghj


1 Answers

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)
like image 150
Jens Munk Avatar answered Oct 07 '22 14:10

Jens Munk