При использовании CMake для кросс-компиляции обычно указывается файл инструментальной цепочки с помощью параметра CMAKE_TOOLCHAIN_FILE. В терминологии GNU можно указать набор инструментов архитектуры хоста, используя этот файл. Однако, как правило, нельзя ожидать выполнения чего-либо, созданного с помощью этой инструментальной цепочки. Достаточно часто некоторые инструменты сборки необходимо скомпилировать для архитектуры сборки.

Рассмотрим следующую схему. У меня есть два исходных файла: genfoo.c и bar.c. Во время сборки genfoo.c необходимо скомпилировать и запустить. Его вывод необходимо записать в foo.h. Затем я могу скомпилировать bar.c, который #include "foo.h". Поскольку CMake по умолчанию использует цепочку инструментов архитектуры хоста, инструкции для bar.c просты. Но как мне сказать ему использовать набор инструментов архитектуры сборки для компиляции genfoo.c? Если просто сказать add_executable(genfoo genfoo.c), будет использован неправильный компилятор.

14
Helmut 23 Мар 2016 в 12:08

1 ответ

Это можно сделать полностью в CMake.

Хитрость заключается в том, чтобы запустить отдельный этап настройки CMake в своем собственном пространстве , молча отклоняя все настройки кросс-компиляции и используя набор инструментов хоста по умолчанию, а затем импортировать сгенерированные выходные данные в родительскую кросс-компилирующую сборку.

Первая часть:

set(host_tools_list wxrc generate_foo)

if(CMAKE_CROSSCOMPILING)
    # Pawn off the creation of the host utilities into its own dedicated space
    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
    file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
    file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
    execute_process(
        COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
    )

    add_custom_target(host_tools
        COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
    )
    include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)

    foreach(tgt IN ITEMS ${host_tools_list})
        add_dependencies(host${tgt} host_tools)
    endforeach()

else()
    # Add an empty target, host tools are built inplace
    add_custom_target(host_tools
        DEPENDS ${host_tools_list}
    )
endif()

... затем вы добавляете обычный add_executable и все такое ...

В конце:

if(NOT CMAKE_CROSSCOMPILING)
    foreach(tgt IN ITEMS ${host_tools_list})
        add_executable(host${tgt} ALIAS ${tgt})
    endforeach()

    export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()

При кросс-компиляции он откладывает создание запускаемых на хосте инструментов в свое собственное выделенное пространство и импортирует целевые объекты как «hostwxrc» и «hostgenerate_foo» в зависимости от создания самих host_tools.

Когда он не компилируется, он строит wxrc и generate_foo как есть и присваивает им псевдонимы hostwxrc и hostgenerate_foo.

После этого, когда вы используете $<TARGET_FILE:wxrc>, вы ссылаетесь на wxrc, созданный для целевой платформы, а $<TARGET_FILE:hostwxrc> ссылается на wxrc, созданный для хоста Платформа вне зависимости от того, одинаковые они или нет.

2
Anonymous 23 Апр 2020 в 13:57