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

P. *_*dre 5 c gcc cross-platform cmake target

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

  • 顶部 CMakeLists:包含要编译的应用程序文件 (main.c) + 2 个目标依赖项(算法和硬件)
target_link_libraries(app_target PUBLIC algo_target hardware_target)
Run Code Online (Sandbox Code Playgroud)
  • algo CMakeLists 只有 C 文件,仅执行计算 (algo.c)
  • hardware CMakeLists 编译有关硬件依赖项的所有文件 (hardware.c) 并根据硬件专门编译选项 -mcpu -mthumb -mfloat-abi -mfpu
target_compile_options(hardware_target -mcpu=${CPU} -mthumb -mfloat-abi=hard -mfpu=${FPU})
Run Code Online (Sandbox Code Playgroud)

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

app 使用 VFP 寄存器参数,algo.a(algo.cpp.obj) 不使用

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

Ard*_*kin 3

由于您没有提供最小的工作示例,我可能无法完全回答您的问题。然而,由于 CMake 都是关于目标和这些目标之间的依赖关系管理,我想任何需要另一个目标的某些设置/依赖关系的目标都应该依赖于该目标。

\n

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

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 algo\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 include\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 algo.hpp\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 algo.cpp\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 hardware\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 include\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 hardware.hpp\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 hardware.cpp\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 main.cpp\n\n6 directories, 8 files\n
Run Code Online (Sandbox Code Playgroud)\n

具有以下文件内容algo

\n
# algo/CMakeLists.txt\nadd_library(algo\n  include/algo.hpp\n  src/algo.cpp\n)\ntarget_include_directories(algo\n  PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:include>\n)\n\n# if (TARGET hardware)\n#   target_link_libraries(algo PRIVATE hardware)\n# endif()\n\n/* algo/include/algo.hpp */\n#pragma once\n\ndouble func1(const double);\n\n/* algo/src/algo.cpp */\n#include "algo.hpp"\n\ndouble func1(const double x) {\n#ifdef IMPORTANT_DEF\n  return 2 * x;\n#else\n  return x;\n#endif\n}\n
Run Code Online (Sandbox Code Playgroud)\n

为了hardware

\n
# hardware/CMakeLists.txt\nadd_library(hardware\n  include/hardware.hpp\n  src/hardware.cpp\n)\ntarget_include_directories(hardware\n  PUBLIC\n    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n    $<INSTALL_INTERFACE:include>\n)\ntarget_compile_definitions(hardware\n  PUBLIC\n    IMPORTANT_DEF\n)\n\n/* hardware/include/hardware.hpp */\n#pragma once\n\n#ifdef IMPORTANT_DEF\ndouble func2(const double, const double);\n#else\nint func2(int, const int);\n#endif\n\n/* hardware/src/hardware.cpp */\n#include "hardware.hpp"\n\n#ifdef IMPORTANT_DEF\ndouble func2(const double x, const double y) { return x + y; }\n#else\nint func2(int x, const int y) { return x - y; }\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n

最后,为了app

\n
# CMakeLists.txt\ncmake_minimum_required(VERSION 3.9)\n\nproject(propagate LANGUAGES C CXX)\n\nadd_subdirectory(hardware)\nadd_subdirectory(algo)\n\nadd_executable(app main.cpp)\ntarget_link_libraries(app\n  PRIVATE\n    hardware\n    algo\n)\n\n/* main.cpp */\n#include <iostream>\nusing namespace std;\n\n#include "hardware.hpp"\n#include "algo.hpp"\n\nint main(int argc, char* argv[]) {\n  cout << func1(5) << '\\n';\n  cout << func2(5, 3) << '\\n';\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
./app\n5\n8\n
Run Code Online (Sandbox Code Playgroud)\n

这是因为我们没有告诉 CMake 这algo取决于hardware. 当我们取消注释该部分时

\n
# if (TARGET hardware)\n#   target_link_libraries(algo PRIVATE hardware)\n# endif()\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
./app\n10\n8\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n