75

Copying directory from source tree to binary tree. For example: How to copy www to bin folder.

work
├─bin
└─src
    ├─doing
    │  └─www
    ├─include
    └─lib

Thanks.

Jonathan Leffler
  • 698,132
  • 130
  • 858
  • 1,229
Jiang Bian
  • 1,913
  • 3
  • 16
  • 14

7 Answers7

141

Since version 2.8, the file command has a copy argument:

file(COPY yourDir DESTINATION yourDestination)

Note that:

Relative input paths are evaluated with respect to the current source directory, and a relative destination is evaluated with respect to the current build directory

Antonio
  • 18,335
  • 12
  • 89
  • 190
Chty
  • 1,411
  • 2
  • 9
  • 2
45

With CMake 2.8, use the file(COPY ...) command.

With older CMake versions, this macro copies files from one directory to another. If you don't want to substitute variables in the copied files, then change the configure_file @ONLY argument (for example to COPYONLY).

# 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)
Top-Master
  • 5,262
  • 5
  • 23
  • 45
Chin Huang
  • 11,862
  • 4
  • 43
  • 44
39

As nobody has mentioned cmake -E copy_directory as a custom target, here's what I've used:

add_custom_target(copy-runtime-files ALL
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/runtime-files-dir ${CMAKE_BINARY_DIR}/runtime-files-dir
    DEPENDS ${MY_TARGET})
rknuus
  • 118
  • 1
  • 9
juzzlin
  • 41,671
  • 5
  • 31
  • 42
  • Short and easy, great. If you drop `DEPENDS ${MY_TARGET}` this can run in parallel to the compiling process. Keep in mind that files are copied every time `make` is running, so it might have limitations with very big folders. – Simon Warta Feb 19 '15 at 15:11
  • I get `Expected a command name, got unquoted argument with text "/runtime-files-dir".` for this :( –  Jan 24 '16 at 11:59
  • This is the preferred solution for me because it works with usage of $ – Captain GouLash Jun 19 '19 at 08:31
27

The configure command will only copy files when cmake is run. Another option is to create a new target, and use the custom_command option. Here's one that I use (if you run it more than once, you'll have to modify the add_custom_target line to make it unique for each call).

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)
Seth Johnson
  • 13,971
  • 6
  • 56
  • 85
16

Use execute_process and call cmake -E. If you want a deep copy, you can use the copy_directory command. Even better, you could create a symlink (if your platform supports it) with the create_symlink command. The latter can be achieved like this:

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

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

Bhushan
  • 17,383
  • 27
  • 100
  • 136
Jiang Bian
  • 1,913
  • 3
  • 16
  • 14
  • 3
    The only issue with this is it breaks the concept of out-of-source builds if temp files are produced in the directory. – Jason Mock Sep 29 '11 at 18:09
2

Thank! That is really helpful advice to use bunch of add_custom_target and add_custom_command. I wrote the following function to use everywhere in my projects. Is also specifies the installation rule. I use it primarily to export interface header files.

#
# 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)

Usage looks like this:

cm_export_file("API/someHeader0.hpp" "include/API/")
cm_export_file("API/someHeader1.hpp" "include/API/")
prokher
  • 490
  • 5
  • 18
1

Based on the answer from Seth Johnson; wrote for more convenience:

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

# Copy 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()
legends2k
  • 29,543
  • 23
  • 115
  • 207
Salamandar
  • 523
  • 3
  • 16