CMake include resources in build [duplicate] - windows

I've got some config files (xml, ini, ...) in the config directory next to the source files. How can I copy all the files in the config directory into the build directory (next to the executable file) each time I make the project?

You can use add_custom_command.
Say your target is called MyTarget, then you can do this:
add_custom_command(TARGET MyTarget PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/config/ $<TARGET_FILE_DIR:MyTarget>)
This executes every time you build MyTarget and copies the contents of "/config" into the directory where the target exe/lib will end up.
As Mark Lakata points out in a comment below, replacing PRE_BUILD with POST_BUILD in the add_custom_command ensures that copying will only happen if the build succeeds.
Explanation
${CMAKE_COMMAND} is the path to CMake
-E makes CMake run commands instead of building
copy_directory is a Command-Line Tool
config is the directory (that falls under the root of the project) whose contents will be copied into the build target
$<TARGET_FILE_DIR:MyTarget> is a generator expression, described in the add_custom_command documentation.

In addition to the top answer,
To copy the directory itself instead of the contents, you can add /${FOLDER_NAME} to the end of the second parameter.
Like this:
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/config $<TARGET_FILE_DIR:${PROJECT_NAME}>/config)

CMake supports a shell type file copy. This link should be helpful for you - How to copy directory from source tree to binary tree?

Use symbolic links
CMake enables symbolic links via create_symlink:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_SOURCE_DIR}/config $<TARGET_FILE_DIR:${PROJECT_NAME}>/config)
It ensures that when you make a change to the files in the directory, build folder would subsequently be updated.

In my project i use INSTALL to specify in CMake, what and where i move my binary with conf file. After execution of cmake, use "make install".

Related

Creating an archive with CMake at a location that I choose

I'm trying to learn how to create archives with CMake. I wrote this piece of code:
cmake_minimum_required(VERSION 3.5.1)
project(hello)
message("Creating archieve in: " ${CMAKE_CURRENT_BINARY_DIR})
message("Source dir is: " ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(hello main.cpp)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(create_tar ALL COMMAND
${CMAKE_COMMAND} -E tar "cfvz" "archieve.tgz")
add_dependencies(create_tar hello)
My project structure is like this:
I have a main folder in which I have a CMakeLists.txt, a main.cpp and a build folder. I go into build and run the cmake file above by 'cmake ..' and then make. My archive is created in the build folder but as you can see I have specified that I want it in the CMAKE_CURRENT_SOURCE_DIR which is along with the main, cmakelists and build folder not in the actual build folder.
Please explain to me why is that happening and how can I make the archive be created in the CMAKE_CURRENT_SOURCE_DIR and not CMAKE_CURRENT_BINARY_DIR. Thanks.
Turning my comment into an answer
That would be WORKING_DIRECTORY parameter of the add_custom_target() command:
add_custom_target(
create_tar ALL
COMMAND ${CMAKE_COMMAND} -E tar cfvz "archieve.tgz"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
The CMAKE_ARCHIVE_OUTPUT_DIRECTORY is for changing the output directory of add_library(... STATIC ...)` targets.
And you can either run the cmake -E tar either the correct (sub-)directory by changing the WORKING_DIRECTORY accordingly (like "${CMAKE_CURRENT_SOURCE_DIR}/Dir") or give a list of files after -- command line option (see documentation of CMake Command Line Tool Mode).

Calling existing make command in cmake file

I have a large project with multiple subdirectories. In the parent directory, I have a CMakeLists.txt file which calls functions defined in other cmake files in the same parent directory. I have a custom Makefile in one of the subdirectories that contains some target "run". When I call cmake from the parent directory, I want the "run" target located in the subdirectory makefile to execute. How should I do this ?
I understand that some people have suggested to use add_custom_target and add_custom_command, but I am still confused as to how to apply these commands to accomplish this task.
If you know, which file(s) are produced by Makefile in the subdirectory, and want to depend on these files, use add_custom_command:
add_custom_command(OUTPUT <output-file>
COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)
This assumes that your CMakeLists.txt have a target, which depends or uses given file.
Otherwise, if you do not care which files are produced by Makefile, use add_custom_target:
add_custom_target(<target_name> COMMAND make run
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/<subdir>
)
In both cases WORKING_DIRECTORY specifies directory which should be current for command executed.
If you want the target (in the second case) to be executed by default, add ALL option before the COMMAND.

Modify source files during cmake build

I need to modify some of my project's sources during compilation. It'd be better if I get to modify them between preprocessing and compilation, but I know it's harder to achieve (The solution proposed here is not optimal for me) so I can settle with a pre-preprocessing step.
Since the source files are to be modified, I need to create a copy of them, modify that copy then run the build on this copy. My current solution is:
Prior to cmake invocation, I copy most of the project root contents' to a separate directory. This is required because there are many script invocations during the build so I need to keep most of the project hierarchy intact. Since there are many files and many of them will not be modified, I first copy all files as symbolic links (cp -sR), then hard copy all .c and .h files. Then I just cd to that directory and invoke cmake and make as usual.
The problem here is that since cmake is not aware that it's working on copies of the actual source, the generated Makefile doesn't check whether the actual source was updated. So I need a full rebuild (Full project tree copy and cmake invocation) whenever I modify a single source file.
This can probably be solved by adding a custom command for each hard copied source file that depends on the actual source file, and recopies it after being modified. I guess it's okay, but it really is... ugly, and requires lots of cmake additions. I don't think what I'm trying to do is so exotic, so I believe there is a better option that could work with little changes to my cmake. I'd also like to hear ideas regarding post preprocessor step invocation.
EDIT: A simplified example case.
This is the project tree:
CMakeLists.txt
src/
CMakeLists.txt
file1.c
file1.c
python/
script.py
The root CMakeLists.txt is add_subdirectory(src/). The src/CMakeLists.txt is add_executable(myexe file1.c file2.c).
I need to execute python python/script.py for each source file, so it should be called on src/file1.c and src/file2.c.
My current solution is a build script as follows:
rm -r build_dir
mkdir build_dir
cp -rt build_dir CMakeLists.txt src/ python/
cd build_dir
cmake .
make # ...
Plus an invocation of python/script.py (prebuild add_custom_command) which globs for the relevant files itself, then processes them.

Running a bash command via CMake

I'm trying to have CMake either run three bash commands or a bash script. However, I can't seem to get it to work.
The bash commands are:
cd ${CMAKE_SOURCE_DIR}/dependencies/library
make
cd ${CMAKE_BINARY_DIR}
Essentially, I would like CMake to build the library in that directory if it does not already exist.
Here's the CMake code I tried:
if(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
execute_process(COMMAND cd ${CMAKE_SOURCE_DIR}/dependencies/library)
execute_process(COMMAND make)
execute_process(COMMAND cd ${CMAKE_BINARY_DIR})
endif(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
However, it's not building anything. What am I doing wrong?
Also, while I'm here asking this: should the third command, to move to the binary folder, be included?
Thanks!
execute_process() is executed during configure time. But you want this to run at build time, thus add_custom_command() and add_custom_target() is what you're looking for.
In this special case you want to generate an output file, so you should go for add_custom_command() (both are essentially the same, but command produces one or multiple output files, while target does not.
The cmake snippet for this should look something like the following:
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/dependencies/library/lib.o
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dependencies/library
COMMAND make
)
You then have to add the output file in another target as dependency, and everything should (hopefully) work as expected.
You can also add DEPENDS statements to the add_custom_command() call to rebuild the object file in case some input sources have changed.

Prevent running cmake in the root directory

Sometimes I forget I'm in the build folder and I run the command in the root directory. Well, maybe some of you have experienced that this creates a mess in the entire file hierarchy, as you have to delete CMakeFiles/ folder, config files, and files related to CPack and CTest. Is there a way I can add something to the Makefile at the root directory that prevents me from running cmake accidentally? I tried to add a target 'cmake' but this didn't work.
aa
UPDATE
I found the same question posted in here. I ended up adopting to put a function in my .bashrc file as suggested in that page:
function cmake() {
# Don't invoke cmake from the top-of-tree
if [ -e "CMakeLists.txt" ]
then
echo "CMakeLists.txt file present, cowardly refusing to invoke cmake..."
else
/usr/bin/cmake $*
fi
}
You can check in your CMakeLists.txt if the source and binary directories are the same. Put something like this as the very first thing in your CMakeLists.txt:
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Source and build directories cannot be the same.")
endif()

Resources