Как распространить зависимость на уровне файлов (пользовательская команда + пользовательская цель) через интерфейсную библиотеку в CMake? - PullRequest
0 голосов
/ 16 мая 2018

У меня есть следующий сценарий:

  1. Проект, над которым я работаю, в основном статическая библиотека
  2. так как это встроенный проект, у меня также есть скрипты компоновщика
  3. каждый скрипт компоновщика требует некоторой предварительной обработки перед использованием
  4. статическая библиотека, включая пути, флаги компилятора и флаг компоновщика для использования предварительно обработанного сценария компоновщика, передаются пользователям через интерфейсную библиотеку.

Обычно это работает нормально, однако существует только целевая зависимость между пользовательским приложением и предварительно обработанным сценарием компоновщика (через интерфейсную библиотеку). Нет зависимости на уровне файлов, поэтому, когда я изменяю источник сценария компоновщика, предварительно обработанный сценарий компоновщика восстанавливается, однако приложение пользователя не связывается.

Вот тестовый пример

$ ls
CMakeLists.txt  dummy.c  linker-script.ld-source  main.c

$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.1)
project(a_test)

add_custom_command(OUTPUT linker-script.ld
        COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/linker-script.ld-source linker-script.ld
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker-script.ld-source)
add_custom_target(linker-script DEPENDS linker-script.ld)

add_library(static-library STATIC
        dummy.c)

add_library(interface-library INTERFACE)
target_link_libraries(interface-library INTERFACE
        # -Tlinker-script.ld
        static-library)
add_dependencies(interface-library linker-script)

add_executable(application
        main.c)
target_link_libraries(application interface-library)

$ cat main.c 
int main(void)
{
    return 0;
}

dummy.c и linker-script.ld-source просто пусты. Сгенерированный скрипт компоновщика фактически не используется, но рекомендованный фрагмент показывает, как я собираюсь его использовать. Давайте запустим это:

$ mkdir output

$ cd output

$ cmake ..
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake/output

$ make
Scanning dependencies of target static-library
[ 20%] Building C object CMakeFiles/static-library.dir/dummy.c.o
[ 40%] Linking C static library libstatic-library.a
[ 40%] Built target static-library
Scanning dependencies of target linker-script
[ 60%] Generating linker-script.ld
[ 60%] Built target linker-script
Scanning dependencies of target application
[ 80%] Building C object CMakeFiles/application.dir/main.c.o
[100%] Linking C executable application
[100%] Built target application

ок, все вроде нормально. Теперь предположим, что источник скрипта компоновщика обновлен:

$ touch ../linker-script.ld-source

$ make
[ 40%] Built target static-library
[ 60%] Generating linker-script.ld
[ 60%] Built target linker-script
[100%] Built target application

Как видите, приложение не связано, и это проблема здесь. Есть идеи, как можно решить такой сценарий?

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Обновление : Кажется, появляется дополнительная поддержка, добавляя новое свойство цели для целей интерфейса в CMake 3.13 (INTERFACE_LINK_DEPENDS и обновленный документ для LINK_DEPENDS, в котором упоминается Ninja как поддерживаемый генератор (хотя, не уверен, когда в какой версии CMake эта функция была реализована).


Примечание. Не полный ответ, нопросто документирование моего использования с ниндзя в качестве генератора

Использование LINK_DEPENDS не работает с генераторами, отличными от Makefile, например Ninja .

Мой обычный подходИз всех найденных в этом сообщении списка рассылки необходимо использовать фиктивный файл и изменить его временную метку, используя

add_custom_command(OUTPUT linker-script.ld
  [...]
  COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/dummy.c
  [...])

Тем не менее, это не очень хорошо работает, так как при первом вызовеобнаруживает, что скрипт компоновщика устарел, и, таким образом, выполняет его копирование и «касается» фиктивного исходного файла. Однако требуется второй вызов, чтобы подобрать модификацию и перестроить все зависимые цели.

Это неудобно, но я полагаю, что оно направлено на классификацию зависимостей Ninja (неявная, явная, только для порядка).С помощью команды add_dependencies создается только зависимость Ninja только для порядка, поскольку сценарий компоновщика не влияет в терминах CMake на строку сборки двоичной цели, с которой вы хотите его запустить.

Что касается интерфейс библиотека, я не вижу, как это могло бы помочь в этой ситуации, поскольку она даже не создает вывод сборки;в основном он действует как организационный заполнитель.

0 голосов
/ 05 сентября 2018

Единственное правильное решение (по крайней мере сейчас) - это использовать LINK_DEPENDS target свойство. Для этого я добавил свою вспомогательную функцию, которая выглядит следующим образом:

#
# Specifies linker script(s) used for linking `target`.
#
# `distortosTargetLinkerScripts(target [linker-script.ld ...])`
#
# Most common use will be with single linker script provided by distortos:
# `distortosTargetLinkerScripts(target $ENV{DISTORTOS_LINKER_SCRIPT})`
#
# Proper linker flag is added, as well as CMake dependency via LINK_DEPENDS target property.
#

function(distortosTargetLinkerScripts target)
    foreach(linkerScript IN LISTS ARGN)
        target_link_libraries(${target} PRIVATE
                -T"${linkerScript}")
        get_target_property(linkDepends ${target} LINK_DEPENDS)
        if(NOT linkDepends)
            unset(linkDepends)
        endif()
        list(APPEND linkDepends "${linkerScript}")
        set_target_properties(${target} PROPERTIES
                LINK_DEPENDS "${linkDepends}")
    endforeach()
endfunction()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...