74

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
  • 730,956
  • 141
  • 904
  • 1,278
Jiang Bian
  • 1,933
  • 3
  • 16
  • 14

7 Answers7

145

Since version 2.8, the file command has a COPY sub-command:

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

starball
  • 20,030
  • 7
  • 43
  • 238
Chty
  • 1,451
  • 2
  • 9
  • 2
44

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
  • 45,029
  • 5
  • 38
  • 50
  • 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
44

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

With CMake versions below 2.8, the following 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)
starball
  • 20,030
  • 7
  • 43
  • 238
Chin Huang
  • 12,912
  • 4
  • 46
  • 47
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
  • 14,762
  • 6
  • 59
  • 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
  • 18,329
  • 31
  • 104
  • 137
Jiang Bian
  • 1,933
  • 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
  • 31,634
  • 25
  • 118
  • 222
Salamandar
  • 589
  • 6
  • 16