【问题标题】:How to create an artificial circular dependency between targets如何在目标之间创建人为的循环依赖
【发布时间】:2017-11-25 17:10:18
【问题描述】:

我有一个导出符号的可执行文件(游戏引擎)(我使用过set_target_properties(game PROPERTIES ENABLE_EXPORTS ON))。

我有一堆链接到该可执行文件的插件:

foreach(plugin ${PLUGINS})
    target_link_libraries(${plugin} game)
endforeach()

它们由可执行文件使用LoadLibrary/dlopen 动态加载。

当我在 Visual Studio 中按 F5 并开始游戏时,我没有重新构建更改后的插件,因为游戏不依赖于它们 - 恰恰相反。

我想做以下事情:

foreach(plugin ${PLUGINS})
    add_dependencies(game ${plugin})
endforeach()

但它在每个插件和游戏之间引入了循环依赖。如何解决我的 F5 问题?

【问题讨论】:

  • 如何在插件代码中使用导出的函数?如果你有硬编码的接口描述或者你有它在一个头文件中,那么只有从plugingame的间接依赖。那么,如果您只使用“game 取决于plugin”变体会发生什么?从我的角度来看应该可以正常工作。
  • @Florian 好吧,我调用了引擎...几乎所有功能都从可执行文件中导出。我在插件中使用引擎头文件...“plugin 依赖于game”依赖项将继续存在。我想知道如何使 F5 工作流程也能正常工作......
  • 如果我使用getProcAddress而不是__declspec(dllimport)带注释的前向声明从插件访问引擎导出的所有内容,我可以删除“plugin取决于game”依赖项,但这不会'编码不实用......
  • 我没有完全理解/理解这一点,但我想我找到了解决方案 - 我可以将 ALL_BUILD(由 CMake 创建)设置为启动项目(用于 F5)并设置这是运行可执行文件的命令
  • 好吧,我忘了windows下需要先生成导入库,也就是说你需要在插件之前构建game(因为导入库是静态链接的)。所以我已经用你的场景和 Visual Studio 运行了一些测试,并将结果放在答案中。

标签: visual-studio visual-c++ cmake dependencies circular-dependency


【解决方案1】:

这是一个“先有鸡还是先有蛋”的问题,因为game 构建将生成plugin 所需的导入库。所以你不能在game之前构建plugin

我已经尝试过您的方案,并且

  1. 如果我在 POST_BUILD 步骤中强制重建,我显然会得到一个递归的构建调用:

    add_custom_command(
        TARGET game 
        POST_BUILD 
            COMMAND ${CMAKE_COMMAND} --build . --target ALL_BUILD --config $<CONFIG>
    )
    
  2. 如果我构建一个单独的目标作为“跑步者”目标,我可能会混淆使用我的项目的其他人:

    file(WRITE nobuild.cpp "")
    add_executable(game_runner nobuild.cpp)
    
    set_source_files_properties(nobuild.cpp PROPERTIES HEADER_FILE_ONLY 1)
    set_target_properties(game_runner PROPERTIES OUTPUT_NAME "game")
    
    foreach(plugin ${PLUGINS})
        add_dependencies(game_runner ${plugin})
    endforeach()
    
  3. 因此,您重新使用ALL_BUILD 目标的建议可能是最好的。对于自动生成所需的.user 设置,您可能会发现以下有趣的内容:

    CMake add_custom_target(): Run custom command using 'Debug->Start Debugging'


我已使用以下内容来测试您的场景:

project(TestPlugins)

file(WRITE main.cpp "int main() { return 0; }")
file(WRITE empty.cpp "")

add_executable(game main.cpp)
set_target_properties(game PROPERTIES ENABLE_EXPORTS ON)
set_target_properties(game PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)

add_executable(plugin1 empty.cpp)
add_executable(plugin2 empty.cpp)

set(PLUGINS plugin1 plugin2)
foreach(plugin ${PLUGINS})
    target_link_libraries(${plugin} game)
endforeach()

【讨论】:

  • 谢谢!您生成 .user 文件的其他答案也很好,并且有效!没有更多的手动设置:) 你是堆栈溢出中 cmake 最活跃的人之一 - 谢谢你,先生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 2014-11-10
  • 2021-04-23
相关资源
最近更新 更多