Reputation: 512
I would like to copy files at postbuild with cmake to the build directory, but only if they dont exist yet.
I know that there is a "copy_if_different" switch for "add_custom_command", but I cant find something like "copy_if_doesnt_exist".
Currently I am stuck with this:
file(GLOB CONFIGURATION_DATA ${PROJECT_SOURCE_DIR}/data/configurations/*)
foreach(data ${CONFIGURATION_DATA})
#only copy if file doesnt exists
if(NOT EXISTS ?? how to get same path as - $<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations) )
add_custom_command(TARGET ${PROJECT_NAME_STR} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${data}
$<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations)
endif()
endforeach()
where I don't know how to get the destination file path
$<TARGET_FILE_DIR:${PROJECT_NAME_STR}>/data/configurations
in order to put it to if statement
Upvotes: 3
Views: 6267
Reputation: 42952
For the not directly supported cases the file(GENERATE ...)
command is very useful (since it does evaluate generator expressions).
So in your case I've successfully tested the following code example:
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0070)
cmake_policy(SET CMP0070 NEW)
endif()
project(CopyFileIfNotExists)
file(
GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CopyConfigurationData$<CONFIG>.cmake"
CONTENT
"if (NOT EXISTS \"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data/configurations\")
execute_process(
COMMAND \"${CMAKE_COMMAND}\" -E copy_directory
\"${PROJECT_SOURCE_DIR}/data/configurations\"
\"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data/configurations\"
)
endif()"
)
file(WRITE "main.cpp" "int main() { return 0; }")
add_executable(${PROJECT_NAME} "main.cpp")
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND "${CMAKE_COMMAND}" -P "CopyConfigurationData$<CONFIG>.cmake"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)
Alternative
Or if it's ok to run with every CMake (re-)configuration just add the following instead of a post-build step:
file(
GLOB
CONFIGURATION_DATA
RELATIVE "${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/data/configurations/*"
)
foreach(data IN LISTS CONFIGURATION_DATA)
file(
GENERATE
OUTPUT "$<TARGET_FILE_DIR:${PROJECT_NAME}>/${data}"
INPUT "${PROJECT_SOURCE_DIR}/${data}"
)
endforeach()
Alternative: Optimized Version
Utilizing file(COPY ...)
the shortest script based version I can think of that also optimizes already existing items out
"Copying preserves input file timestamps, and optimizes out a file if it exists at the destination with the same timestamp."
looks like this:
file(
GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CopyConfigurationData$<CONFIG>.cmake"
CONTENT "file(
COPY \"${PROJECT_SOURCE_DIR}/data/configurations\"
DESTINATION \"$<TARGET_FILE_DIR:${PROJECT_NAME}>/data\"
)"
)
Upvotes: 3