如何将编译选项从目标传播到 Cmake 上的所有其他目标

how propagate compilation options from a target to all others on Cmake

我正在 ARM 项目上实现现代 Cmake。我有 3 个不同的 CMakeLists:

target_link_libraries(app_target PUBLIC algo_target hardware_target)
target_compile_options(hardware_target -mcpu=${CPU} -mthumb -mfloat-abi=hard -mfpu=${FPU})

问题是,编译选项会传播到顶部,但不会传播到 algo_target。我有以下错误:

app uses VFP register arguments, algo.a(algo.cpp.obj) does not

如何在所有目标上传播编译选项? 我不想在编译选项变量中设置编译选项,将来,应用程序将 运行 在 2 个不同的硬件目标上

因为您没有提供最小的工作示例,所以我可能无法完整地回答您的问题。但是,由于 CMake 完全是关于目标和这些目标之间的依赖关系管理,我想任何需要另一个目标 settings/dependencies 的目标都应该依赖于该目标。

假设我们有以下目录结构:

.
├── algo
│   ├── CMakeLists.txt
│   ├── include
│   │   └── algo.hpp
│   └── src
│       └── algo.cpp
├── CMakeLists.txt
├── hardware
│   ├── CMakeLists.txt
│   ├── include
│   │   └── hardware.hpp
│   └── src
│       └── hardware.cpp
└── main.cpp

6 directories, 8 files

algo

的文件内容如下
# algo/CMakeLists.txt
add_library(algo
  include/algo.hpp
  src/algo.cpp
)
target_include_directories(algo
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

# if (TARGET hardware)
#   target_link_libraries(algo PRIVATE hardware)
# endif()

/* algo/include/algo.hpp */
#pragma once

double func1(const double);

/* algo/src/algo.cpp */
#include "algo.hpp"

double func1(const double x) {
#ifdef IMPORTANT_DEF
  return 2 * x;
#else
  return x;
#endif
}

对于hardware

# hardware/CMakeLists.txt
add_library(hardware
  include/hardware.hpp
  src/hardware.cpp
)
target_include_directories(hardware
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)
target_compile_definitions(hardware
  PUBLIC
    IMPORTANT_DEF
)

/* hardware/include/hardware.hpp */
#pragma once

#ifdef IMPORTANT_DEF
double func2(const double, const double);
#else
int func2(int, const int);
#endif

/* hardware/src/hardware.cpp */
#include "hardware.hpp"

#ifdef IMPORTANT_DEF
double func2(const double x, const double y) { return x + y; }
#else
int func2(int x, const int y) { return x - y; }
#endif

最后,app

# CMakeLists.txt
cmake_minimum_required(VERSION 3.9)

project(propagate LANGUAGES C CXX)

add_subdirectory(hardware)
add_subdirectory(algo)

add_executable(app main.cpp)
target_link_libraries(app
  PRIVATE
    hardware
    algo
)

/* main.cpp */
#include <iostream>
using namespace std;

#include "hardware.hpp"
#include "algo.hpp"

int main(int argc, char* argv[]) {
  cout << func1(5) << '\n';
  cout << func2(5, 3) << '\n';
  return 0;
}

当我们构建上面的项目并运行它时,我们得到

./app
5
8

这是因为我们没有告诉CMake algo依赖于hardware。当我们取消注释部分

# if (TARGET hardware)
#   target_link_libraries(algo PRIVATE hardware)
# endif()

algo/CMakeLists.txt中重建项目,这次我们得到

./app
10
8

基本上,target_* 命令用于定义应该或不应该传播到目标的 消费者 的依赖项。因此,我们应该使 algo 目标成为 hardware 目标的消费者。

另请注意,要进行传播,target_* 朋友也需要填充目标的 INTERFACE_* 属性,即 target_* 命令需要定义属性作为 PUBLIC(同时出现在头文件和实现文件中)或 INTERFACE(仅出现在头文件中),而不是 PRIVATE(仅出现在实现文件中)。