How to avoid name clashes in cmake subprojects? - cmake

So I have setup a metaproject, which means I have one directory (the root directory) containing multiple subdirectories, each of which is a cmake project (with a valid cmakelists). The cmakelists in the root directory imports the subprojects using the cmake add_subdirectory command.
Each subproject defines it's own targets (libraries and executables) as well as targets "check" which executes the test suite for that project and "docs" which runs doxygen.
My problem is that CMake does not understand that the check and docs targets are local to each project, and therefore complains about name clashes.
So my question is, is there any way to get cmake to understand that these targets are local to each project?

CMake doesn't allow duplicate target names. The rationale is provided in the docs for policy CMP0002:
Unique names may be referenced unambiguously both in CMake
code and on make tool command lines.
Logical names are used by Xcode and VS IDE generators
to produce meaningful project names for the targets.
Your could try setting CMP0002 to OLD (done via cmake_policy(SET CMP0002 OLD)) which would at least get rid of the CMake error, but I'd recommend against that - it certainly won't work for MSVC/Xcode.
The only option I can see short of hand-coding unique names would be to write a CMake function which generates a unique name per "check" target - for example it could append the name of the target which is being checked, yielding names like check_my_lib_one, check_my_exe_one, etc.
This function could also be used to collect a list of all registered check_<Target> instances and add them to a single target called check which would invoke each subordinate check_<Target>, so running make check runs them all.

Related

CMake: Error including library from another package [duplicate]

I am writing a C++ library (header-only) and am using CMake to generate my (Visual Studio) project and solution files. I'm also writing a test suite, which is part of the same CMake project.
My problem occurs when I call target_include_directories() on the target that represents my header-only library, so that consumers of my library may find its header files. I get the following error message (even though generation is NOT aborted).
CMake Error in CMakeLists.txt:
Target "Fonts" INTERFACE_INCLUDE_DIRECTORIES property contains path:
"D:/Projects/GPC/fonts/include"
which is prefixed in the source directory.
(D:/Projects/GPC/Fonts being the top-level directory of my library project. Btw the problem remains if I move my header files to the top directory.)
The offending line in my CMakeLists.txt is this (adapted for simplicity):
target_include_directories(Fonts INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
I do not understand what I'm doing wrong. Without target_include_directories(), code of consumer projects simply can't include my header files (unless in installed form, but I haven't gotten to that yet, and in any case I want to be able to use my library from its build tree, without installation.)
I feel like I'm missing something basic here; yet I've searched for hours without finding a solution or explanation.
The origin of the problem is not the target_include_directories command itself, but the attempt to install a target that has a public or interface include directory prefixed in the source path (i.e. the include directory is a subdirectory of your ${PROJECT_SOURCE_DIR}.)
While it is perfectly fine and desirable to use absolute paths when building the library from scratch, a third party library that pulls in a prebuilt version of that library will probably want to use a different include path. After all, you do not want all of your users to mirror the directory structure of your build machine, just to end up in the right include path.
CMake's packaging mechanism provides support for both of these use cases: You may pull in a library directly from the build tree (that is, check out the source, build it, and point find_package() to the directory), or from an install directory (run make INSTALL to copy built stuff to the install directory and point find_package() to that directory). The latter approach needs to be relocatable (that is, I build and install on my machine, send you the resulting directory and you will be able to use it on your machine from a different directory structure), while the former is not.
This is a very neat feature, but you have to account for it when setting up the include directories. Quoting the manual for target_include_directories:
Include directories usage requirements commonly differ between the
build-tree and the install-tree. The BUILD_INTERFACE and
INSTALL_INTERFACE generator expressions can be used to describe
separate usage requirements based on the usage location. Relative
paths are allowed within the INSTALL_INTERFACE expression and are
interpreted relative to the installation prefix. For example:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
$<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
)
The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions do all the magic:
$<INSTALL_INTERFACE:...>
Content of ... when the property is exported using install(EXPORT), and empty otherwise.
$<BUILD_INTERFACE:...>
Content of ... when the property is exported using export(), or when the target is used by another target in the same buildsystem.
Expands to the empty string otherwise.

CMake how to get binary target complete directory and name on Windows

Is there a way in CMake to find a binary target complete name (mybin.exe) by inspecting target properties? Like
get_target_property(EXENAME targetname OUTPUT_NAME) (or RUNTIME_OUTPUT_NAME)
Or I have to use a custom command like in How to get library full-native name on cmake?
With get_target_property seems I'm only able to get the "logical" target name out of it (mybin), with no other information. Am I missing something?
Thank you
There's a reason this is not possible without generator expressions: There are multi configuration generators such as the Visual Studio generators that create a build system for multiple build configurations (Release, Debug, ...) in a single CMake configuration run (cmake -S ... -B ...). It's even the default to create binaries in a directory with a name matching the configuration built.
Depending on what you want to do with the information, there are some alternatives:
You may be able to use generator expressions, e.g. if you need the information as part of add_custom_command, add_custom_target, add_test or similar. Several target properties also allow for use of generator expressions.
You may be able to establish the desired directory structure during an install step, see the install() command.
You may be able to get the build system to generate the files in a specific location e.g. by setting the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable in the toplevel CMakeLists.txt. Note that this will still result in configuration dependent subdirectories being created for multi configuration generators, unless the variable value contains a generator expression. (You could, simply be adding $<0:>, but this could easily result in binaries of different configurations overwriting one another.)
If you cannot specify this in the toplevel CMakeLists.txt, via command line or cmake presets, you could still use a path relative to CMAKE_BINARY_DIR; this should make the binaries easy to locate.
In the end that is a matter of doing:
add_custom_command(TARGET ${your_target}
POST_BUILD
WORKING_DIRECTORY ${your_dir}
COMMAND echo "$<TARGET_FILE:${your_target}>" > "exename.txt"
DEPENDS ${your_target} ${another_target}
VERBATIM
)
so that exename.txt contains the full path to the executable target
Didn't find a way to do st like:
set(EXENAME "$<TARGET_FILE:${your_target}>")
anyway...

Is it possible to force CMake to run add_compile_definitions() each time?

I have an embedded project (using ESP-IDF which builds projects with CMake), where I have a props.json file that contains several settings (e.g. "device type"). For example based on the actual value of "deviceType" the CMake open and read props.json by calling execute_process() and jq, then defines C preprocessor macros, such as: DEVICE_TYPE_A by using add_compile_definitions().
The problem is that, this will run only when I modify the CMakeLists.txt or clean the whole project, but I don't want to recompile each components when I change the props.json only the files that I wrote (so, depend on the settings). I'd like to make CMake read the file each time I build the project without cleaning it.
I did my research, so I know there are add_custom_target() and add_custom_command() that behave that way, however add_compile_definitions() cannot be called in a script. Is there a solution to achieve this or should I just use a header file configured by configure_file() and leave add_compile_definitions() alone?
This is actually pretty easy and you don't need to manually reconfigure CMake. Just add the following to the CMakeLists.txt in the directory containing your props.json file:
set_property(DIRECTORY . APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS props.json)
This will add props.json to the list of files that the CMake-generated build scans when determining whether to re-run the CMake configure step. See the docs on CMAKE_CONFIGURE_DEPENDS for more detail.
In general, you should never need to manually re-run CMake1 after the first configure. If you do, it is an indication that you have not communicated all of the necessary information for CMake to generate a correct build system.
1 There is one notable exception: Xcode is known to be buggy when re-running the CMake configure step automatically.

Cmake override find_package for a given target

We have a CMakeLists.txt that links (for instance) opencv to our various binaries. This is done as follow:
find_package(OpenCV REQUIRED core imgproc highgui contrib)
target_link_library(XXX opencv_core)
We also would like to allow the person building the library to provide its own opencv library. It seems that this could be done setting -DCMAKE_PREFIX_PATH to the right path.
cmake -DCMAKE_PREFIX_PATH=".../mybuild/include;.../mybuild/lib" .
However I would like to be sure the library used is exactly the one specified by the client (i.e. if there is nothing in /mybuild/lib the configuration fails).
How can I allow somebody building the library to override the library used ? (if nothing is specified it should fall back to find_package-s)
In short
If the package provides <package>Config.cmake script, user may specify <package>_DIR CMake variable for locate this script.
Searching other places in that case may be disabled with NO_DEFAULT_PATH option for find_package().
If a package is searched with Find<package>.cmake script, there is no (generic) way for disable searching other places if user provides hint variable but it is wrong.
Explanations
Firstly, CMAKE_PREFIX_PATH provides additional installation tree for all packages. As this variable is applied to all find_package() calls, it is not wise to require all packages to be found under it.
When talk about the ways for specify installation directory for specific package, we need to distinguish two kinds of "find" scripts:
<package>Config.cmake (or some alternative names, see find_package documentation).
These scripts are shipped with the packages themselves. And there is universal way for user to specify location of such packages: CMake variable <package>_DIR, which should point to the directory with *Config.cmake script.
While default behaviour of find_package() is treating <package>_DIR variable as an additional hint, passing NO_DEFAULT_PATH option disables all implicit paths:
if(<package>_DIR) # Variable is set by the user or by previous `cmake` run.
# Search only under given directory.
find_package(<package> NO_DEFAULT_PATH)
else()
# Search everywhere (as documented for 'find_package').
find_package(<package>)
endif()
Find<package>.cmake.
This script either is shipped with CMake or should be shipped with the project.
Most of such scripts allows to hint about package location with variable (CMake or environment one) like <package>_DIR, <package>_ROOT or so.
However, almost all such scripts treat hint variable only as additional search place, so if variable is set to wrong value, they simply ignore it. And without modifying the script you cannot change that behavior.

Add dependency to the CMake-generated build-system itself

In short: I know how to add dependencies to targets, in a CMake-generated build system. But I would like to add dependencies to the generated build-system itself.
Longer question: In the CMake-generated build process of cgal, we would like CMake to automatically re-run the configuration step, when certain files are modified. Unneeded details are hidden below:
As a matter of fact, we generate using CMake the build system for the CGAL libraries/examples/demos, but also at the same time the build system for our Doxygen-generated documentation. The Doxyfile is generated from multiple files.
When the CMake generator is "Makefile", there is a special target in the Makefile, that is named rebuild_cache, but that target (at the Makefile level) is not a CMake-target. And anyway, I look for a solution that is cross-platform, that is: usable with all CMake generators. I have the impression that what I want is not yet doable with CMake. Can you please confirm, so that I can fill a documented feature-request?
Since CMake 3.0, you can add such a file to the directory property CMAKE_CONFIGURE_DEPENDS. This property holds a list of files; if any of them changes, CMake will trigger re-configuration.
Here is a small example. Assuming your Doxyfile is generated from Doxyfile.in.1 and Doxyfile.in.2 in the current source directory, the property could be used like this:
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS
Doxyfile.in.1
Doxyfile.in.2
)
If you're using CMake 2.x, the property CMAKE_CONFIGURE_DEPENDS is not available, but you can use the following trick:
Pass the files through configure_file(), even if you just COPYONLY them someplace and don't use the resulting copies. configure_file() introduces precisely the buildsystem dependency you're looking for.
This works, but it adds the overhead of copying the file.
(Note: This trick was also the original content of this answer, since I was not aware of CMAKE_CONFIGURE_DEPENDS at time of answering).