I have some shader files inside of a resource directory 'Shaders'. I want my app to copy this folder to the runtime directory everytime there are changes inside of one file in it before the build. How can I achieve this?
Right now I use this here:
add_custom_command(TARGET my_app PRE_BUILD
COMMAND rm ARGS -rf ${CMAKE_CURRENT_BINARY_DIR}/Shaders
COMMAND cp ARGS -a ${CMAKE_CURRENT_SOURCE_DIR}/my_app/Viewer/Shaders ${CMAKE_CURRENT_BINARY_DIR}
)
But this does only work when I change another file so a built is needed, not the shader files themselves. What can I do?
What I know figured out to be working is this here:
file(GLOB shaders "${CMAKE_CURRENT_SOURCE_DIR}/my_app/Viewer/Shaders/*")
message(status Copy shaders)
foreach(shader ${shaders})
message(status "From ${shader}")
get_filename_component(outputFileName ${shader} NAME)
message(status "To ${CMAKE_CURRENT_BINARY_DIR}/Shaders/${outputFileName}")
configure_file(${shader} ${CMAKE_CURRENT_BINARY_DIR}/Shaders/${outputFileName} COPYONLY)
endforeach()
Related
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.
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
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)
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})
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)
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
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/")
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()
I have a project with some asset (shader) files that are also frequently updated and need to be copied to a build destination folder every time my project is built.
Right now, the files are copied the first time, but then, when the project is rebuilt (from within Clion) the files are not continually copied. For instance, if I delete them from the directory they are copied to, they do not show up again.
Here is my Cmake file:
# Name for this project
set(PROJECT_NAME "3d_model")
# Choose the library for the final build
set(PROJECT_BUILD_DIR ${CMAKE_SOURCE_DIR}/bin/${PROJECT_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BUILD_DIR}/$<CONFIG>)
# Set sources
set(PROJECTS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/projects)
set(SOURCES
src/main.cpp
${INCLUDE_DIR}/glad/src/glad.c)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${CMAKE_DL_LIBS} glfw ${GLFW_LIBRARIES})
# Copy resources
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/assets DESTINATION ${PROJECT_BUILD_DIR}/)
You can see in the last line my attempt to get the projects assets to copy every time the project is built.
Is there a way to ensure this happens?
add_custom_command may be what you want
add_custom_command(TARGET ${ProjectName} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/assets ${PROJECT_BUILD_DIR}/
)
As an example suppose four folders(app1, app2, app3 and main) such as below
main
|__ CMakeLists.txt
\__ module1
|______ CMakeLists.txt
|______ sub1.cpp
|______ sub1.h
\__ library5
|______ CMakeLists.txt
|______ sub5.cpp
|______ sub5.h
\__app1
\__app2
\__app3
Which output of module1 is module1.dll and output of library5 is lib5.dll. Folder of app1 must contain module1.dll and lib5.dll, app2 needs lib5.dll and finally app3 needs module1.dll(number of apps, modules and libs are more than this example and as I explain below we don't want to change modules/libraries's CMakeLists.txt, just main's CMakeLists.txt is ours).
PS:
I have a cmake project which has several libraries and modules. They included in my project using add_subdirectory command (note that my project just made up from multiple modules and it has not any add_library or add_target).
I need to copy outputs of libraries/modules without changing their CMakeLists.txt (add_custom_command with POST_BUILD option actually is not a good choice because at this point I need to change CMakeLists.txt of libraries/modules which they are not just belong to my project). On the other hand it must done in outer(major) CMakeLists.txt which has others(libraries/modules).
I tried some other commands such as file (COPY ) and configure_file() but I think they operate in generating cmake-cache phase and just can copy resource files which are exist in pre-build phase.
Moreover, In another approach I write a bash script file to copy the files and call it in major CMakeLists.txt via bellow command.
add_custom_target (copy_all
COMMAND ${CMAKE_SOURCE_DIR}/copy.sh ${files}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
The files has the list of files. But the copy not performed! I manually test the script which works as desired. But I don't have any idea why it can not operate at call in CMakeLists.txt.
What can I do to copy sub-projects outputs to some locations from major CMakeLists.txt?
The Setup
To simplify it a little, let's say you have:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(PostBuildCopyFromRoot)
add_subdirectory(module)
module/CMakeLists.txt
file(WRITE "module.h" "int ModuleFunc();")
file(WRITE "module.cpp" "int ModuleFunc() { return 1; }")
add_library(module SHARED "module.cpp" "module.h")
target_include_directories(module PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
set_target_properties(module PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS 1)
app/app.mexw64
The Problem
If you now just add to following to the root CMakeLists.txt:
add_custom_command(
TARGET module
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"$<TARGET_FILE:module>"
"app/$<TARGET_FILE_NAME:module>"
)
You will get from CMake:
CMake Warning (dev) at CMakeLists.txt:8 (add_custom_command):
Policy CMP0040 is not set: The target in the TARGET signature of
add_custom_command() must exist. Run "cmake --help-policy CMP0040" for
policy details. Use the cmake_policy command to set the policy and
suppress this warning.
TARGET 'module' was not created in this directory.
Solutions
You can always overwrite command behaviors:
function(add_library _target)
_add_library(${_target} ${ARGN})
add_custom_command(
TARGET ${_target}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"$<TARGET_FILE:${_target}>"
"${CMAKE_SOURCE_DIR}/app/$<TARGET_FILE_NAME:${_target}>"
)
endfunction()
NOTE: Put the code snippets before the add_subdirectory() call
References
Copying executable and DLLs to User specified location using CMake in windows
Parent CMakeLists.txt overwriting child CMakeLists.txt output directory options
Proper usage of CMAKE_*_OUTPUT_DIRECTORY
Is there a way to include and link external libraries throughout my project only editing my top level CMakeList?
I have a cmake build system gone wild. Before supporting IDEs, everything was ok.
I need to copy files (shaders in this case) to the build directory. They need to be copied when they've changed, regardless of whether the main target is built or not.
I had success before, as I could add a custom command with ${CMAKE_CURRENT_BINARY_DIR}, add dependencies later and everything was fine.
The problem is, when using a generator expression for the command output, it creates a dependency from my custom command to the main target. This means adding a dependency backwards (which is needed to trigger the copy) throws an error because of cyclic dependencies.
This is what I have so far, which doesn't work because the custom target (thus custom command) is not triggered when the main target doesn't need rebuilding.
set(SHADER_IN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders)
file(GLOB_RECURSE SHADERS "${SHADER_IN_DIR}/*.glsl")
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders/)
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/.stamps)
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${STAMP_DIR})
set(STAMP_FILES "")
foreach(SHADER ${SHADERS})
get_filename_component(SHADER_FILENAME ${SHADER} NAME)
set(STAMP_FILE ${STAMP_DIR}/${SHADER_FILENAME}.stamp)
add_custom_command(
OUTPUT ${STAMP_FILE}
COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SHADER} $<TARGET_FILE_DIR:${PROJECT_NAME}>/shaders/${SHADER_FILENAME}
DEPENDS ${SHADER}
)
list(APPEND STAMP_FILES ${STAMP_FILE})
endforeach()
add_custom_target(Shaders
SOURCES ${SHADERS}
DEPENDS ${STAMP_FILES})
# Need to add dependency here! But I can't :(
So, is there any other way to get what output directory will be used in an IDE? All "solutions" I've read to force building a target have failed (they pretty much all rely on add_dependencies).
Thank you for saving my sanity.
In the end, instead of trying to find out where the IDE is going to output the binary, I forced output in a predictable bin/ dir.
set(BINARY_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})
foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
I am new to cmake file creation. I have c++ code in list of directory, each directory has its own CMakeLists.txt file. For compile and create executable in each directory, I have to go inside directory and execute following two command on terminal.
$ cmake .
$ make
Example directory structure:
Each directory 1, 2 ...41 has its own `CMakeLists.txt'.
Example inside each directory file structure:
For compile and create executable in each directory, i have to follow those tow command.
But now i have to write either python script/ cmake script to do above this action in each directory and capture the output and store in log file.
Kindly anyone to guide me to solve my issue. Thanks in advance.
My each directory CMakeLists.txt like this:
project(foundations)
cmake_minimum_required(VERSION 2.6)
include_directories($ENV{GMOCK_HOME}/include $ENV{GMOCK_HOME}/gtest/include)
link_directories($ENV{GMOCK_HOME}/mybuild $ENV{GMOCK_HOME}/gtest/mybuild)
add_definitions(-std=c++11)
set(sources main.cpp RetweetCollectionTest.cpp)
add_executable(test ${sources})
target_link_libraries(test pthread)
target_link_libraries(test gmock)
target_link_libraries(test gtest)
add_subdirectory https://cmake.org/cmake/help/v3.0/command/add_subdirectory.html is exactly what you need.
EDIT:
For example:
add_subdirectory(1 1)
Where the first parameter is source dir, and the second is binary dir. So, the names should not overlap.
Also, check this: https://stackoverflow.com/a/7788165/934691
But, if you don't want to rewrite your CMakeLists, a simple bash script like
for dir in ls ; do cd $dir; cmake . && make; cd ..; done
will be more appropriate for you.