как распространить параметры компиляции из цели на все остальные в Cmake - PullRequest
0 голосов
/ 10 мая 2019

Я внедряю современный Cmake для проекта ARM.У меня есть 3 разных CMakeLists:

  • top CMakeLists: содержит файлы приложения для компиляции (main.c) + 2 целевые зависимости (алгоритмы и оборудование)
target_link_libraries(app_target PUBLIC algo_target hardware_target)
  • algo CMakeLists имеет только C-файлы, которые вычисляют только (algo.c)
  • аппаратные CMakeLists, которые компилируют все файлы об аппаратных зависимостях (hardware.c) и параметры компиляции в зависимости от оборудования, в частности -mcpu -mthumb -mfloat-abi -mfpu
target_compile_options(hardware_target -mcpu=${CPU} -mthumb -mfloat-abi=hard -mfpu=${FPU})

Проблема в том, что параметры компиляции распространяются на верх, но не на algo_target.У меня следующая ошибка:

приложение использует аргументы регистра VFP, algo.a (algo.cpp.obj) не

Как распространить параметры компиляции на все цели?Я не хочу устанавливать параметры компиляции в переменной параметра компиляции, в будущем приложение будет работать на 2 разных аппаратных целях

1 Ответ

1 голос
/ 10 мая 2019

Поскольку вы не предоставили минимальный рабочий пример, я не смог бы ответить на ваш вопрос полностью. Тем не менее, поскольку CMake занимается исключительно целями и управлением зависимостями между этими целями, я полагаю, что любая цель, которой требуются некоторые настройки / зависимости от другой, должна зависеть от этой цели.

Предположим, что у нас есть следующая структура каталогов:

.
├── 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_* friends aldo необходимо заполнить свойства INTERFACE_* цели, т. Е. Команды target_* должны определить свойства либо как PUBLIC (отображая оба в заголовочных файлах и файлах реализации) или INTERFACE (отображаются только в заголовочных файлах), но не PRIVATE (отображаются только в файлах реализации).

...