【问题标题】:Avoid repetitive CMake code with multiple targets避免具有多个目标的重复 CMake 代码
【发布时间】:2025-12-08 10:35:01
【问题描述】:

在具有多个目标的 CMake 项目中,我经常发现自己一遍又一遍地重复一些代码。看这个例子:

cmake_minimum_required(VERSION 3.12)
project(rapid_benchmark)

set(CMAKE_CXX_STANDARD 17)

add_executable(benchmark main.cpp)
add_executable(benchmark_parallel main.cpp) # enable parallel processing
add_executable(benchmark_openmp main.cpp) # enable openmp
add_executable(benchmark_static main.cpp) # enable static optimizations
# ... more targets

# Adding basic dependecies
find_package(abc)
if(abc_FOUND)
    target_link_libraries(benchmark abc::abc)
    target_link_libraries(benchmark_parallel abc::abc)
    target_link_libraries(benchmark_openmp abc::abc)
    # ... all other targets ...
    # The same for the includes etc.

find_package(xyz)
if(xyz_FOUND)
    target_link_libraries(benchmark xyz::xyz)
    # ... all other targets ...

这很烦人且容易出错,尤其是在添加新目标时。

如何避免 CMake 项目中包含多个目标的重复代码? 例如,有没有办法将目标放入某种列表并在该列表上调用target_link_libraries

【问题讨论】:

    标签: c++ cmake


    【解决方案1】:

    和 Bernhard 说的一样,但是在 CMake 中:)

    macro(add_benchmark)
      set(singleValue NAME)
      set(multipleValues SOURCES)
      cmake_parse_arguments(local "" "${singleValue}" "${multipleValues}" ${ARGN})
    
      set (libraries)
      if (abc_FOUND)
        set (libraries ${libraries} abc::abc)
      endif()
      if (xyz_FOUND)
        set (libraries ${libraries} xyz::xyz)
      endif()
    
      add_executable(${local_NAME} ${local_SOURCES})
      target_link_libraries(${local_NAME} ${libraries})
    endmacro()
    

    然后你可以简单地调用它作为任何其他 CMake 命令:

    add_benchmark(
      NAME benchmark
      SOURCES main.cpp
    )
    
    add_benchmark(
      NAME benchmark_other
      SOURCES main.cpp other.cpp
    )
    

    【讨论】:

    • 我会删除库变量并在 if 中执行 target_link_libraries。这将为您节省两行并提高清晰度。
    • @Bernhard 口味问题 :) 我会定义另一个宏/函数,让我回到可用库的列表,然后链接到这些。
    • 最好使用function() 而不是macro(),这样每个set() 中的所有变量都将作用于函数体...
    【解决方案2】:

    我会考虑创建一个macro,您可以为每个应用程序调用它,它同时进行编译和链接

    你可能会发现你想使用cmake-parse-arguments

    【讨论】:

      【解决方案3】:

      像这样... https://cmake.org/cmake/help/latest/command/foreach.html

      set(targets a b c d e)
      foreach(loop_var IN targets)
          add_executable($loop_var main.cpp)
      endforeach(loop_var)
      

      结合做很多事情的宏将使其易于管理。

      更多详情: Looping over a string list

      【讨论】:

        最近更新 更多