cmake: execute a command after subdirectories files are built - cmake

I have the following structure:
main direcotry
|
--> subdirecotry1
--> subdirectory2
|
--> subdirecotry21
--> subdirecotry22
--> subdirecotry23
--> subdirecotry24
...
in the main cmake I have:
add_subdirectory("subdirecotry1")
add_subdirectory("subdirecotry2")
and I have command to be executed after all subdirectories are built using:
add_custom_command(
OUTPUT ${OUTPUT}
DEPNEDS subdirecotry1/ouptput.exe subdirecotry2/subdirecotry21/ouptput.exe subdirecotry2/subdirecotry22/ouptput.exe ...
COMMAND ---some command here---
)
Since I have too many small files generated in the subdirectories of subdirectory2, is there way to avoid stating all files in DEPNEDS and just say dependency on all files in that subdirectory ?

Related

CMake source_group and generated files interaction

For a project I am autogenerating multiple Fortran source files using add_custom_command. To my knowledge this results in CMake creating a GENERATED source file that I can add to a target such as a library or executable. However, since the file does not exist at CMake compile time CMake cannot use the source_group command to group these generated files for the IDE (Visual Studio).
Is there another way to achieve the same result as source_group that I cannot find? For example when using CMake with Qt you can set the AUTOGEN_SOURCE_GROUP to change the source group for the automoc and autorcc generated files.
Example.
# Creates a command to generate the 'a.f90' file using 'mytool.exe' and 'a.f90.in'.
add_custom_command(
OUTPUT a.f90
COMMAND mytool.exe a.f90.in
DEPENDS a.f90.in
)
add_executable(example a.f90 b.f90 c.f90) # Where b.f90 and c.f90 are not generated
source_group("Source Files/Not Generated" FILES "b.f90 c.f90")
source_group("Source Files/Generated" FILES a.f90) # Does nothing
This results in the following visual studio filters,
Source Files
|- Non Generated Files
|- b.f90
|- c.f90
|- a.f90
instead of
Source Files
|- Non Generated Files
|- b.f90
|- c.f90
|- Generated Files
|- a.f90
To help others who might be trying the same thing. Here's my workaround. I couldn't find a way to group autogenerated files using add_custom_command. This leaves a possible solution. If you are fine with not having the files autogenerated when your code is compiled you may instead use the execute_process command. With execute_process the command will be run when CMake creates the build tree instead of when you compile your source code. Since the files will already exist may be added as normal source files and can be grouped using source_group.
Example
# Generates 'a.f90'
execute_process(COMMAND mytool.exe a.f90.in ${CMAKE_CURRENT_BINARY_DIR}/a.f90)
add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/a.f90" b.f90 c.f90)
source_group("Source Files/Not Generated" FILES "b.f90 c.f90")
source_group("Source Files/Generated" FILES a.f90)
With this the visual studio filters look like
Source Files
|- Generated
|- a.f90
|- Not Generated
|- b.f90
|- c.f90

CMake: custom command to copy files matching a pattern and preserve directory structure

I have the following project layout:
project/
├─ CMakeLists.txt
├─ main.cpp
╘═ my_lib/
├─ CMakeLists.txt
╞═ some_package1/
│ ├── header.hpp
│ └── impl.cpp
╘═ some_package2/
├── header.hpp
└── impl.cpp
my_lib is added as a subdirectory by the CMakeLists.txt from project.
What I would like to have is a target in my_lib CMakeLists.txt which, when built, executes a command that copies all headers in my_lib to a destination directory, while preserving directory structure. The destination directory would be defined by the project CMakeLists.txt.
Basically, if I could somehow get add_custom_command to do this:
file(COPY ${CMAKE_SOURCE_DIR}/my_lib DESTINATION ${COPY_DEST_DIR} FILES_MATCHING PATTERN "*.hpp")
I would be extremely happy. But I haven't found a way to do that. This is very similar to an install target, except I need it done before anything gets even compiled.
I tried doing the following:
set(MY_LIB_HEADER_FILES
some_package1/header.hpp
some_package2/header.hpp
)
add_custom_target(copy_headers)
add_custom_command(
TARGET copy_headers
COMMAND ${CMAKE_COMMAND} -E copy "${MY_LIB_HEADER_FILES}" ${COPY_DEST_DIR}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/my_lib
)
But that doesn't preserve directory structure, which in just this example case would lead to one header being overwritten by the other. I haven't been able to find a workaround to that.
The only solution I can imagine is a hack in which I loop over every file in ${MY_LIB_HEADER_FILES}, remove whatever follows the last forward slash, create that directory, and then copy the file over to it. But that really isn't something I want to resort to and come to think of it, I'm not even sure how I'd go about it considering it must be done in an add_custom_command call.
Surely there is a solution, right?
One of the ways to achieve this is to write a "CMake script" file that will contain your file(COPY ....) command and to execute it within add_custom_command. In brief, your code snippet would look like this:
#create script file during configure phase...
file(WRITE ${CMAKE_BINARY_DIR}/cp.cmake
"file(COPY ${CMAKE_SOURCE_DIR}/my_lib DESTINATION ${COPY_DEST_DIR} FILES_MATCHING PATTERN *.hpp)\n"
)
#execute the script during the build phase...
add_custom_command(
TARGET my_lib
POST_BUILD
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/cp.cmake
)
file(WRITE .... statement will create a new cmake script file within the root build folder named cp.cmake.
Note 1:
The $ preceding variables CMAKE_SOURCE_DIR and COPY_DEST_DIR are not escaped, meaning that the cp.cmake will contain their evaluated values.
Note 2:
It is assumed that your library creates a target named my_lib and add_custom_command is added as a POST_BUILD event for that target.
In the end, here is the cmake documentation about add_custom_command, file command and running CMake in script mode

Move duplicated CmakeLists.txt functionality to a common file

I have multiple projects that have identical/duplicated code in their respective CMakeLists.txt. At the very least I need a place to store string definitions that I can pull into the CMakeLists.txt files. What's the best way to do this? My directory structure
common_defs/
src_files
hdr_files
CMakeLists.Txt - file that has common defs
independent_dir1/
src_files
hdr_files
CMakeLists.Txt --> Imports/Includes from ../common_defs/CMakeLists.txt
independent_dir2/
src_files
hdr_files
CMakeLists.Txt --> Imports/Includes from ../common_defs/CMakeLists.txt
independent_dir1 and independent_dir2 will be built independently from each other. Building in common_defs should not trigger builds in the independent_dirs
Create a file in common_defs/common_defs.cmake with common strings and definitions, than add to your CMakeLists.txt:
// add path common_defs to include search path
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../common_defs")
// include module from file common.cmake searched in search path
include(common_defs)

CMAKE Forcing copy of specified files in post build even if no change in source files

I have a project laid out like so:
CMakeLists.txt
|
|--------subdir1
| |--CMakeLists.txt
| |--sourcefiles
| |--filetocopy1
|
|--------subdir2
|--CMakeLists.txt
|--sourcefiles
|--filetocopy2
I want to copy filetocopy1 and filetocopy2 to a specified output directory in the build folder. So in both, I have something like
add_custom_command(
TARGET nameoftargetinsubdir1
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/filetocopy1"
"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
)
The problem is that if the filetocopy1 or filetocopy2 change, but the source files don't, then invoking make in the build folder doesn't copy the files. Is there some way to force it to copy those files? I'm getting the feeling I might have to put the copy commands in the top level CMakeLists.txt file.
The main purpose of POST_BUILD custom commands is being run whenever target executable/library is rebuilt. If you don't need such behavior, use common custom commands with OUTPUT and DEPENDS option, combined with add_custom_target:
# If someone needs file "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/filetocopy1",
# this command will create it if the file doesn't exist or is older than
# "${CMAKE_CURRENT_SOURCE_DIR}/filetocopy1".
add_custom_command(
OUTPUT "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/filetocopy1"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/filetocopy1"
"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/filetocopy1"
)
# Custom target for activate the custom command above
add_custom_target(copy_file1 DEPENDS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/filetocopy1")
# Whenever target 'nameoftargetinsubdir1' is requested, the custom target will be evaluated.
add_dependencies(nameoftargetinsubdir1 copy_file1)
If you simply want to copy these files to another place, I recommend to use the following command:
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/filetocopy1 ${CMAKE_BINARY_DIR}/ COPYONLY)
https://cmake.org/cmake/help/v3.10/command/configure_file.html
This command is simple and effective. And it will copy your file to the destination, whenever cmake is invoked.

Add a dependency not in a subdirectory using CMake

Let's say there's following directory structure:
root
|
+--projects
| |
| +-test
| |
| +-CMakeFiles.txt
|
+--libs
|
+-testlib
|
+-CMakeFiles.txt
test contains CMakeFiles.txt and testlib also contains CMakeFiles.txt. "test" produces an executable and "testlib" produces a static library.
I want "test" to link with "testlib" without using symlinks and without moving "testlib" library into a subdirectory within "test".
Because "testlib" isn't a subdirectory of "test", I can't do
add_subdirectory("../../libs/testlib")
In test's CMakeFiles.txt - CMake will complain about "testlib" not being in the "test" subdirectory.
Also, because system has several different compilers, I can't simply install "testlib" libraries into some kind of central directory, so I want test to compile a local copy of testlib and link with it (i.e. as if testlib was a subdirectory). I also want the "test" project to automatically rebuild "testlib" if it has been changed.
So, how can I deal with it? I am using CMake 2.8.4 on Windows XP SP3.
You could either provide a top-level CMakeLists.txt in root, or provide a binary directory to the add_subdirectory command; e.g.
add_subdirectory("../../libs/testlib" "${CMAKE_CURRENT_BINARY_DIR}/testlib_build")
This creates a subdirectory called testlib_build in your current build directory which contains the generated project files for testlib, but not the source.
For further info, run
cmake --help-command ADD_SUBDIRECTORY
The only way I see to do this - create CMakeLists.txt in root and put the following code there:
add_subdirectory(projects/test)
add_subdirectory(lib/testlib)
When you have done this, you can do target_link_libraries(test testlib) in test/CMakeLists.txt, and it will be automatically rebuilt if you change something in testlib.