2009-03-30 5 views

ответ

32

С CMake 2.8 используйте команду file(COPY ...).

С помощью старых версий CMake этот макрос копирует файлы из одного каталога в другой. Если вы не хотите заменять переменные в скопированных файлах, измените аргумент configure_file @ONLY.

# Copy files from source directory to destination directory, substituting any 
# variables. Create destination directory if it does not exist. 

macro(configure_files srcDir destDir) 
    message(STATUS "Configuring directory ${destDir}") 
    make_directory(${destDir}) 

    file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*) 
    foreach(templateFile ${templateFiles}) 
     set(srcTemplatePath ${srcDir}/${templateFile}) 
     if(NOT IS_DIRECTORY ${srcTemplatePath}) 
      message(STATUS "Configuring file ${templateFile}") 
      configure_file(
        ${srcTemplatePath} 
        ${destDir}/${templateFile} 
        @ONLY) 
     endif(NOT IS_DIRECTORY ${srcTemplatePath}) 
    endforeach(templateFile) 
endmacro(configure_files) 
+0

При использовании режима cmake -E легко скопировать файл или каталог. Большое спасибо –

+0

Отредактировано, потому что это принятый ответ, а другой ответ с файлом (команда COPY чиста. –

+3

Да, но можете ли вы запустить файл (COPY ...) как пользовательскую команду, которая зависит от цели? – juzzlin

13

Использовать execute_process и вызвать cmake -E. Если вы хотите получить глубокую копию, вы можете использовать команду copy_directory. Еще лучше, вы можете создать symlink (если ваша платформа поддерживает его) с помощью команды create_symlink. Последнее может быть достигнуто следующим образом:

execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/path/to/www 
                  ${CMAKE_BINARY_DIR}/path/to/www) 

От: http://www.cmake.org/pipermail/cmake/2009-March/028299.html

+3

Единственная проблема с этим заключается в том, что он нарушает концепцию внекорневой сборки, если в каталоге создаются временные файлы. –

24

Команда configure будет копировать только файлы, когда cmake запускается. Другой вариант - создать новую цель и использовать опцию custom_command. Вот тот, который я использую (если вы запускаете его более одного раза, вам придется изменить строку add_custom_target, чтобы сделать ее уникальной для каждого вызова).

macro(copy_files GLOBPAT DESTINATION) 
    file(GLOB COPY_FILES 
    RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 
    ${GLOBPAT}) 
    add_custom_target(copy ALL 
    COMMENT "Copying files: ${GLOBPAT}") 

    foreach(FILENAME ${COPY_FILES}) 
    set(SRC "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") 
    set(DST "${DESTINATION}/${FILENAME}") 

    add_custom_command(
     TARGET copy 
     COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST} 
    ) 
    endforeach(FILENAME) 
endmacro(copy_files) 
+1

+1 Потому что вы можете использовать это как шаг POST_BUILD – BeRecursive

+0

. Я адаптировал ваш (удивительный) ответ, чтобы иметь более модульный скрипт. См. мой ответ! – Salamandar

101

Начиная с версии 2.8, file command имеет копию аргумент:

file(COPY yourDir DESTINATION yourDestination) 

Обратите внимание, что:

Относительные входные пути вычисляются по отношению к текущему каталогу источника и относительный пункт назначения оценивается в отношении каталога текущей сборки

+1

это работает для каталогов? – batman

+3

Это выглядит многообещающе. Можете ли вы объяснить, как вы его запускаете или запускаете каждый раз? –

+2

Это действительно работает для каталогов. – m01

2

Thank! Это действительно полезный совет, чтобы использовать кучу add_custom_target и add_custom_command. Я написал следующую функцию для использования во всех проектах. Также указано правило установки. Я использую его прежде всего для экспорта файлов заголовков интерфейсов.

# 
# export file: copy it to the build tree on every build invocation and add rule for installation 
# 
function (cm_export_file FILE DEST) 
    if (NOT TARGET export-files) 
    add_custom_target(export-files ALL COMMENT "Exporting files into build tree") 
    endif (NOT TARGET export-files) 
    get_filename_component(FILENAME "${FILE}" NAME) 
    add_custom_command(TARGET export-files COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${DEST}/${FILENAME}") 
    install(FILES "${FILE}" DESTINATION "${DEST}") 
endfunction (cm_export_file) 

Использование выглядит следующим образом:

cm_export_file("API/someHeader0.hpp" "include/API/") 
cm_export_file("API/someHeader1.hpp" "include/API/") 
+0

Это выглядит интересно. он копирует целые каталоги? –

11

Поскольку никто не упомянул CMake -E copy_directory как пользовательские цели, вот что я использовал:

add_custom_target(copy-runtime-files ALL 
    COMMAND cmake -E copy_directory ${CMAKE_SOURCE_DIR}/runtime-files-dir ${CMAKE_BINARY_DIR}/runtime-files-dir 
    DEPENDS ${MY_TARGET}) 
+0

Короткие и легкие, Великий. Если вы отпустите 'DEPENDS $ {MY_TARGET}', это может выполняться параллельно с процессом компиляции. Имейте в виду, что файлы копируются каждый раз, когда выполняется 'make', поэтому у него могут быть ограничения с очень большими папками. –

+0

Я получаю «Ожидаемое имя команды, получивший некотируемый аргумент с текстом»/runtime-files-dir ». Для этого :( – Sorona

1

На основании ответа от Сета Джонсона, вот что я написал для большего удобства.

# Always define the target 
add_custom_target(copy_resources ALL COMMENT "Copying resources…") 

# Copy single files 
macro(add_files_to_environment files) 
    add_custom_command(TARGET copy_resources POST_BUILD 
     COMMAND ${CMAKE_COMMAND} -E copy ${ARGV} ${CMAKE_CURRENT_BINARY_DIR}) 
endmacro() 

# Copy full directories 
macro(add_directory_to_environment distant local_name) 
    file(GLOB_RECURSE DistantFiles 
     RELATIVE ${distant} 
     ${distant}/*) 
    foreach(Filename ${DistantFiles}) 
     set(SRC "${distant}/${Filename}") 
     set(DST "${CURRENT_BUILD_DIR}/${local_name}/${Filename}") 
     add_custom_command(TARGET copy_resources POST_BUILD 
      COMMAND ${CMAKE_COMMAND} -E copy ${SRC} ${DST}) 

     message(STATUS "file ${Filename}") 
    endforeach(Filename) 
endmacro() 

EDIT: Это не работает должным образом. Это работает безупречно.

# Copy single files 
macro(resource_files files) 
    foreach(file ${files}) 
     message(STATUS "Copying resource ${file}") 
     file(COPY ${file} DESTINATION ${Work_Directory}) 
    endforeach() 
endmacro() 

# Copy full directories 
macro(resource_dirs dirs) 
    foreach(dir ${dirs}) 
     # Replace/at the end of the path (copy dir content VS copy dir) 
     string(REGEX REPLACE "/+$" "" dirclean "${dir}") 
     message(STATUS "Copying resource ${dirclean}") 
     file(COPY ${dirclean} DESTINATION ${Work_Directory}) 
    endforeach() 
endmacro()