CMake: пользовательская команда для копирования файлов, соответствующих шаблону, и сохранения структуры каталогов

#cmake

#cmake

Вопрос:

У меня следующий макет проекта:

 project/
├─ CMakeLists.txt
├─ main.cpp
╘═ my_lib/
   ├─ CMakeLists.txt
   ╞═ some_package1/
   │  ├── header.hpp
   │  └── impl.cpp
   ╘═ some_package2/
      ├── header.hpp
      └── impl.cpp
 

my_lib добавляется как подкаталог с помощью CMakeLists.txt from project .
Что я хотел бы иметь, так это цель, в my_lib CMakeLists.txt которой при сборке выполняется команда, которая копирует все заголовки в my_lib каталог назначения, сохраняя при этом структуру каталогов. Целевой каталог будет определен project CMakeLists.txt .

В принципе, если бы я мог как-то add_custom_command это сделать:

 file(COPY ${CMAKE_SOURCE_DIR}/my_lib DESTINATION ${COPY_DEST_DIR} FILES_MATCHING PATTERN "*.hpp")
 

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

Я попытался выполнить следующее:

 set(MY_LIB_HEADER_FILES
    some_package1/header.hpp
    some_package2/header.hpp
)

add_custom_target(copy_headers)
add_custom_command(
    TARGET copy_headers
    COMMAND ${CMAKE_COMMAND} -E copy "${MY_LIB_HEADER_FILES}" ${COPY_DEST_DIR}
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/my_lib
)
 

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

Единственное решение, которое я могу себе представить, — это хак, в котором я перебираю каждый файл ${MY_LIB_HEADER_FILES} , удаляю все, что следует за последней косой чертой, создаю этот каталог, а затем копирую в него файл. Но на самом деле это не то, к чему я хочу прибегнуть и подумать об этом, я даже не уверен, как бы я это сделал, учитывая, что это должно быть сделано в add_custom_command вызове.

Конечно, есть решение, верно?

Комментарии:

1. Вы пробовали ${CMAKE_COMMAND} -E copy_directories вместо copy ?

2. В конечном итоге я бы скопировал исходные файлы вместе с заголовками, поскольку copy_directories не предлагает возможности сопоставления файлов вообще. Однако, как было предложено в ответе, которого, по-видимому, больше нет, я мог бы затем использовать file(GLOB_RECURSE) для поиска исходных файлов в каталоге назначения и их удаления. Это далеко от идеала, но из-за отсутствия лучшего решения, вероятно, это то, что я в конечном итоге сделаю.

3. Я надеюсь, что вы найдете хорошее решение. Но вы также можете рассмотреть возможность реорганизации своей структуры каталогов. Я считаю полезным иметь «внешние» заголовочные файлы (файлы, которые конечным пользователям необходимы для использования скомпилированного кода) в отдельном каталоге от исходных и внутренних заголовочных файлов. Это значительно упрощает использование чего-то вроде copy_directories их установки.

4. @EricBackus это на самом деле то, чего я пытался достичь. Это может быть личным, но мне не нравится идея вручную сохранять отдельное местоположение для заголовков библиотеки (если я не неправильно понял, что вы имели в виду), поэтому я хочу, чтобы скрипт делал это автоматически. Однако к чему привела меня эта головоломка, так это к реорганизации всего моего кода, чтобы часть «копировать все, прежде чем что-либо будет скомпилировано» больше не требовалась. Несмотря на это, принятый ответ предоставляет хороший способ сделать это. 🙂

Ответ №1:

Один из способов добиться этого — написать файл «CMake script», который будет содержать вашу file(COPY ....) команду, и выполнить ее внутри add_custom_command . Вкратце, ваш фрагмент кода будет выглядеть следующим образом:

 #create script file during configure phase...
file(WRITE ${CMAKE_BINARY_DIR}/cp.cmake
  "file(COPY ${CMAKE_SOURCE_DIR}/my_lib DESTINATION ${COPY_DEST_DIR} FILES_MATCHING PATTERN *.hpp)n"
)

#execute the script during the build phase...
add_custom_command(
  TARGET my_lib
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/cp.cmake
)

 

file(WRITE .... инструкция создаст новый файл сценария cmake в корневой папке сборки с именем cp.cmake .

Примечание 1: $ Предыдущие переменные CMAKE_SOURCE_DIR и COPY_DEST_DIR не экранируются, что означает, что cp.cmake они будут содержать их оцененные значения.

Примечание 2. Предполагается, что ваша библиотека создает цель с именем my_lib и add_custom_command добавляется как POST_BUILD событие для этой цели.

В конце концов, вот документация cmake о add_custom_command, файловой команде и запуске CMake в режиме скрипта

Комментарии:

1. Это идеально. Спасибо, загружается. 👍