【问题标题】:cmake + swig + dependiciescmake + swig + 依赖项
【发布时间】:2017-01-14 11:12:30
【问题描述】:

今天我尝试使用“cmake + swig”的组合来为我的代码生成绑定。基本上它可以工作:

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})

用这样的native.i:

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

但如果我更改 lib.hpp 构建系统 cmake build 不调用 swig 来重新生成代码。所以我必须touch native.i 才能让它工作,这很烦人。

我找到swig-M 选项来生成依赖项, 知道如何用它来修复UseSWIG.cmake吗?

UseSWIG.cmake 只使用add_custom_command 生成, 所以我需要以某种方式add_custom_command 依赖于动态文件集, 不是静态的?

【问题讨论】:

  • 您是否尝试将 lib.hpp 添加到 SWIG_ADD_MODULE:SWIG_ADD_MODULE(core Java native.i lib.cpp lib.hpp)
  • @wasthishelpful 是的,正如预期的那样,这没有帮助。
  • 我认为这基本上是重复的:stackoverflow.com/q/31007635/168175 也许?
  • @Flexo 你是对的。
  • 不幸的是,我不知道什么比恢复的补丁更好

标签: c++ cmake swig


【解决方案1】:

我相信我已经找到了满足您要求的解决方案。

我目前正在使用一种解决方案,其中添加了所有相关依赖项,以便SWIG 重新生成接口,只要解析的任何标头被修改。

这个想法是制作一个自定义目标,除了删除生成的接口文件之外,它还会触及一个虚拟文件。我在下面为一个名为 fnm 的项目提供了解决方案,并带有一个包装器 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)

【讨论】:

    【解决方案2】:

    在配置期间,您可以使用 -M 标志运行 swig 来生成依赖项。然后,您可以解析它的输出并将其作为 DEPDENDS 传递给 add_custom_command。

    输出如下:

    test_wrap.c: \
      .../swig.swg \
      ... \
      test.i \
      test.h
    

    这可以用execute_command生成,需要进一步处理:

    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})
    

    这使得 swig 依赖于 .i 文件中包含的所有标头。如果以添加新依赖项的方式编辑 .i 或头文件之一,则需要重新配置以便 cmake 知道它。如果您添加 CMAKE_CONFIGURE_DEPENDS,这可能会自动发生。

    set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${swig_deps} test.i)
    

    【讨论】:

    • 虽然我认为这已经接近现在,但如果 .i 文件本身包含一个由构建过程的另一部分自动生成的头文件,会发生什么情况? (我认为 siwg -M 保释并且配置步骤因此失败?)
    • 确实如此。一种解决方法是使用包含生成文件的包装标头,然后将其包含在 .i 中。生成的当然需要手动添加到 swig 命令的依赖项中。
    【解决方案3】:

    确实,查看UseSWIG.cmake 的源代码,custom commands 是基于 .i 文件构建的,并且缺少对 other sources 的依赖。您可以在自定义命令中添加extra dependencies

    set(SWIG_MODULE_core_EXTRA_DEPS lib.hpp)
    SWIG_ADD_MODULE(core Java native.i lib.cpp)
    

    或者,您可以修改 UseSWIG.cmake 以自动添加依赖项:

    macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile other_sources)
        # ...
        add_custom_command(
            # ...
            DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS} ${other_sources}
            # ...
        )
    endmacro()
    
    # ...
    
    foreach(it ${swig_dot_i_sources})
        SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it} ${swig_other_sources})
        set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
    endforeach()
    

    这导致了我最初的评论:

    SWIG_ADD_MODULE(core Java native.i lib.cpp lib.hpp)
    

    【讨论】:

    • 其实我想自动生成这个依赖,而不是每次手动添加“额外”的依赖。
    • 不,这是太大的依赖关系。使用您的解决方案,我可以根据代码库中的任何更改重新生成native.i。我的意思是swig -M 生成依赖项列表,并且我想将此列表传递给add_custom_command,每次native.i 更改时我都需要更新依赖项列表的问题。所以它就像_EXTRA_DEPS,但是是动态的,而不是静态的。
    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多