CMake source_group and generated files interaction - cmake

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

Related

CMake link directory passing when compiling shared library

Say I have C project with the following structure (simplified):
|- CMakeLists.txt <- This is root CMake
|- lib
|- <some source files>
|- CMakeLists.txt <- CMake file for building the library
|- demo
|- <some source files>
|- CMakeLists.txt <- CMake for building demo apps
|- extra_lib
|- <some source files>
|- CMakeLists.txt <- CMake for building supplementary library
Now, I want to build my library (living in lib) as a shared library to be used by demo apps from demo directory.
Additional library, that can not be a part of my library (it is essentially a wrapper for some C++ external library) is also to be compiled as a shared library and then linked to my library.
I have a problem with including dependencies for additional library. In its CMakeLists.txt I've defined link_directories to point location where .so libs are stored and then target_link_libraries to point which should be linked. At the end I did export target.
include_directories(${EXTERNAL_DIR}/include)
link_directories(${EXTERNAL_DIR}/lib)
add_library(extra_lib SHARED extra_lib.cpp)
target_link_libraries(extra_lib
some_lib
)
export(TARGETS extra_lib FILE extra_lib.cmake)
The point is that when I try to compile lib and link it against extra_lib I get an error that some_lib is not found what I guess means that link_directories is local to the extra_lib.
Now, question is how can I make it propagate together with dependencies? I'd like it to work in the way that adding extra_lib as subdirectory and as a dependency for my lib would automatically add linked directories from extra_lib to the lib linking process.
The linking process would look like:
(some external library) --> extra_lib --> lib --> demo app
First off, the CMake docs state that commands like include_directories and link_directories are rarely necessary. In fact, it is almost always better to use target_include_directories and target_link_libraries instead.
Secondly, the reason your approach fails is because you need to let CMake know about the existence of some_lib. You can do this like so:
add_library(some_lib SHARED IMPORTED)
set_target_properties(some_lib
PROPERTIES
IMPORTED_LOCATION ${EXTERNAL_DIR}/lib/libsome_lib.so)
Then, afterwards:
target_link_libraries(extra_lib some_lib)

CMake post-build-event: copy compiled libraries

The binary directory structure of my project is currently like this (Windows):
bin/mainProject/{Debug,Release}
bin/library1/{Debug,Release}
bin/library2/{Debug,Release}
...
bin/libraryN/{Debug,Release}
I'd like to copy the libraries library1lib.dll, ... libraryNlib.dll to the bin/mainProject/{Debug,Release} directory once they are build.
For CMake, I think this is doable using a post-build event, hence I've tried adding this to each of the libraries' CMakeLists.txt:
add_custom_command(TARGET library1 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/library1lib.dll
${CMAKE_BINARY_DIR}/mainProject/${CMAKE_BUILD_TYPE}/
)
Currently, there are two issues:
${CMAKE_BUILD_TYPE} seems to be not defined, at least I get an empty string for that variable in the output window.
Is there a possibility to make that post-build event more generic? Like replacing the actual dll name with some variable?
You can make this more generic by using generator expressions:
add_custom_command(
TARGET library1
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:library1>
$<TARGET_FILE_DIR:mainProject>/$<TARGET_FILE_NAME:library1>
)
Alternative
You could - if every dependency is build within your CMake project - also just give a common output path for all executables and DLLs with something like:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Out")
Note: The absolute path is required here because it would otherwise be relative to each targets default output path. And note that the configuration's sub-directory is appended by CMake automatically.
References
How to copy DLL files into the same folder as the executable using CMake?

CMake include_directories vs file GLOB

I've been trying to migrate a project from VS to CMake, but I'm not sure my project structure is quite fit to a simple migration:
project/
|- CMakeLists.txt
|- build/
|- (cmake stuff)
|- src/
|- main.cpp
|- tests.cpp // also contains a main()
|- class1.hpp
|- class1.cpp
|- class2.hpp
|- class2.cpp
|- ...
|- included/
| - (external libs)
My CMakeLists.txt attempt so far has been:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
add_executable(webnectar src/main.cpp
src/test.cpp)
enable_testing()
add_test(tests project)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/included)
But I get linking errors with my own classes., I don't understand why.
In several other SO questions I've seen people using file GLOBs to include all sources from a subfolder, which I guess would be a solution. Still, I wish I understood why include_directories is not enough and why (if it would work) file GLOB is OK.
Also, using file GLOB would mess with my build because both test.cpp and main.cpp have a main function.
Although it would look like a different matter (for a different question), please consider this question as more general in the sense of how could I fix all these issues with either a CMake syntax or with a more suitable file structure.
Regarding include_directories This directive corresponds to -I compiler flag and allows compiler to find header files, i.e. those which are included in #include ....
You should mention all your source files in the arguments of add_executable. That's unavoidable.
You could form the complete list of sources with FILE(GLOB..):
FILE(GLOB webnectar_SOURCES RELATIVE src/ *.cpp)
and then use it in add_executable(webnectar ${webnectar_SOURCES}).
However, this would not be the best and safest option, because it contains a significant flaw. The list of files is formed during the "configuring" stage of the build process (e.g. cmake -D<....> -D<.....> .) and then it's never rebuilt until CMake-related files (CMakeLists.txt, CMakeCache.txt and so on) somehow change. So if you first run cmake... and then add a new file, it won't be noticed, and Makefiles won't be regenerated.
Additionally, if some extra files (e.g. left after an interrupted merge) fit the mask you will get some quite unexpected results.
So it's safer to form and maintain an explicit list of sources, that is,
set(webnectar_SOURCES
src/main.cpp
src/class1.cpp
src/class2.cpp
...
)
and then use it in add_executable(webnectar ${webnectar_SOURCES}). The name of variable can be any but some IDEs like KDevelop prefer a standard naming <artifact>_SOURCES, so they can mantain the list automatically for you (or at least try to maintain :) )

CMake: adding custom resources to build directory

I am making a small program which requires an image file foo.bmp to run
so i can compile the program but to run it, i have to copy foo.bmp to 'build' subdirectory manually
what command should i use in CMakeLists.txt to automatically add foo.bmp to build subdirectory as the program compiles?
In case of this might help, I tried another solution using file command. There is the option COPY that simply copy a file or directory from source to dest.
Like this:
FILE(COPY yourImg.png DESTINATION "${CMAKE_BINARY_DIR}")
Relative path also works for destination (You can simply use . for instance)
Doc reference: https://cmake.org/cmake/help/v3.0/command/file.html
To do that you should use add_custom_command to generate build rules for file you needs in the build directory. Then add dependencies from your targets to those files: CMake only build something if it's needed by a target.
You should also make sure to only copy files if you're not building from the source directory.
Something like this:
project(foo)
cmake_minimum_required(VERSION 2.8)
# we don't want to copy if we're building in the source dir
if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# list of files for which we add a copy rule
set(data_SHADOW yourimg.png)
foreach(item IN LISTS data_SHADOW)
message(STATUS ${item})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${item}"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${item}" "${CMAKE_CURRENT_BINARY_DIR}/${item}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${item}"
)
endforeach()
endif()
# files are only copied if a target depends on them
add_custom_target(data-target ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/yourimg.png")
In this case I'm using a "ALL" custom target with a dependency on the yourimg.png file to force the copy, but you can also add dependency from one of your existing targets.

cmake creates a ton of files

I'm new to cmake and have just started playing around with it. My problem is that when I invoke cmake like in the tutorial it generates a massive amount of files.
Is there a way to invoke cmake so that all is left after is one unix makefile in the root directory of my project?
The files CMake generates are all useful and shouldn't be deleted.
You could probably write a script which deletes these at the end of running CMake, but I'd strongly recommend that you let CMake work the way it's designed to.
If you keep your source tree separate from your build tree (do an "out of source build" as CMake calls it), there should be no problems. So e.g.
- project_root_dir
|
|- CMakeLists.txt
|- src_dir
- build_dir
If you cd build_dir, then do cmake ../project_root_dir, all the files CMake generates will be in build_dir and won't pollute your source tree.