Подтвердить что ты не робот

Как выразить, что файл карты зависит от add_executable?

Я строю исполняемый файл, используя стандартную команду:

add_executable(MyExe a.c b.c)

Я настраиваю CMAKE_EXE_LINKER_FLAGS для создания файла карты, и это работает.

Однако, если я удаляю файл карты, выполнение инкрементной сборки не восстанавливает файл карты. Это имеет смысл, поскольку я не говорил cmake, что файл карты зависит от MyExe. В приведенном выше сценарии MyExe.map даже не является целью, поэтому cmake даже не знает, что он существует.

Я пытался создать пользовательскую цель, но не могу создать пользовательскую команду, которая регенерирует файл карты, так как он прибывает из add_executable. Затем я попытался использовать add_dependencies(), но это, похоже, влияет только на порядок сборки.

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

Похоже, мне нужен какой-то способ сказать add_executable, что выходных данных больше, чем просто исполняемый образ. Есть ли способ сделать это?

Если бы кто-нибудь мог указать мне правильное направление, я был бы признателен! Заранее спасибо за чтение.

4b9b3361

Ответ 1

Я видел, что тот же вопрос был задан в списке рассылки CMake, и я так и не получил ответа. Итак, позвольте мне попытаться ответить здесь.

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

Если вы не хотите добавлять его в качестве дополнительного пользовательского команды/целевого шага, вы можете связать объектный файл, являющийся частью вашего исполняемого файла, со OBJECT_OUTPUTS исходного файла OBJECT_OUTPUTS (работает, к сожалению, только с генераторами Makefile).

Я успешно протестировал следующий пример с помощью цепочки инструментов GNU:

cmake_minimum_required(VERSION 2.6)

project(MapFileDep)

file(WRITE "main.cpp" "int main() { return 0; }")

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(
        CMAKE_EXE_LINKER_FLAGS 
        "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=output.map"
    )
endif()

add_executable(${PROJECT_NAME} "main.cpp")

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set_source_files_properties(
        "main.cpp" 
        PROPERTIES OBJECT_OUTPUTS "output.map"
    )
endif()

альтернатива

А здесь более продвинутая альтернатива (также охватывающая вариант использования @jww):

Добавьте что-то, что генерирует/создает/копирует файл output.map (если его там нет), и используйте целевое свойство LINK_DEPENDS чтобы CMake знал о повторном связывании при изменении output.map:

add_custom_command(
    OUTPUT "output.map"
    COMMAND "${CMAKE_COMMAND}" -E touch "output.map"
)

add_executable(${PROJECT_NAME} "main.cpp" "output.map")

set_target_properties(
    ${PROJECT_NAME} 
    PROPERTIES 
        LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/output.map"
)