In CMake how to create targets with identical names? - cmake

I have a question regarding CMake and I need help to solve the following error I'm getting:
CMake Error at :::: (add_custom_target):
add_custom_target cannot create target "generate" because another target
with the same name already exists. The existing target is a custom target
created in source directory :::::.
Here the target names of the two same level CMakeLists.txt are the same and I want to keep them identical, without any conflict. Can anyone help me out?

According with CMake policy CMP0002 (introduced by CMake 2.6, emphasis mine):
Targets names created with add_executable, add_library, or add_custom_target are logical build target names. Logical target names must be globally unique [...]
The following note deserves a mention and could probably help you anyway:
Custom targets must simply have globally unique names (unless one uses the global property ALLOW_DUPLICATE_CUSTOM_TARGETS with a Makefiles generator).
It means that there exists a global property named ALLOW_DUPLICATE_CUSTOM_TARGETS that is probably what you are looking for. It has a limited use and you should read carefully the documentation, but it's worth a try.
The most relevant part follows:
Makefile generators are capable of supporting duplicate custom target names. [...] However, setting this property will cause non-Makefile generators to produce an error and refuse to generate the project.
To be able to use duplicate custom targets put the following line in your CMakeLists.txt:
set(ALLOW_DUPLICATE_CUSTOM_TARGETS TRUE)
If it solves your issue mainly depends on the actual problem, so I cannot say.

This could be a good help:
OUTPUT_NAME sets the real name of a target when it is built and can be used to help create two targets of the same name even though CMake requires unique logical target names.
https://cmake.org/cmake/help/v3.0/command/set_target_properties.html

Related

CMake: How to manage multiple dependency to the same submodule?

I am trying to build a correct CMake structure for a simple project with several nested submodules. Similarly to this post, I am facing a situation where the main executable and one of the submodules both depend on another submodule:
executable_A/
CMakeListst.txt
library_B/
CMakeLists.txt
library_C/
CMakeLists.txt
library_C/
CMakeLists.txt
Multiple builts of the same target would then result in a cmake error:
add_library cannot create target "library_C" because another target with the
same name already exists. The existing target is an interface library
created in source directory ".....".
See documentation for policy CMP0002 for more details.
The issue had been closed with the following solution, that consists in cheking if the concerned target had already been built before building it again:
# When include 'C' subproject
if(NOT TARGET library_C)
add_subdirectory(C)
endif()
I agree with one of the commenters of the original posts in thinking that it is not a satisfactory solution in every case: in the (unlikely) case of executable_A and library_B depending on different versions of library_C, a mismatch would occur. Is there a way, using submodules, of avoiding this scenario ? Is it possible, for example, to "rename" the library_C target built from library_B to library_C_B, so that no naming conflicts occur ?

How can I avoid clashes with targets "imported" with FetchContent_MakeAvailable?

Suppose I'm writing an app, and managing its build with CMake; and I also want to use a library, mylib, via the FetchContent mechanism.
Now, my own CMakeLists.txt defines a bunch of targets, and so does mylib's CMakeLists.txt. If I were to install mylib, then find_package(mylib), I would only get its exported targets, and even those would be prefixed with mylib:: (customarily, at least). But with FetchContent, both my app's and mylib's (internal and export-intended) targets are in the "global namespace", and may clash.
So, what can I do to separate those targets - other than meticulously name all of my own app's targets defensively?
I would really like it if it were possible to somehow "shove" all the mylib targets into a namespace of my choice.
Note: Relates to: How to avoid namespace collision when using CMake FetchContent?
In the current CMake (<=3.24) world, there are no features for adjusting the names of the targets in other black-box projects, whether included via find_package, add_subdirectory, or FetchContent. Thus, for now, it is incumbent on you to avoid name-clashes in targets, install components, test names, and anywhere else this could be a problem.
Craig Scott says as much in his (very good) talk at CppCon 2019, see here: https://youtu.be/m0DwB4OvDXk?t=2186
The convention he proposes is to use names that are prefixed with SomeProj_. He doesn't suggest to literally use ${PROJECT_NAME}_, and I wouldn't either, because doing so makes the code harder to read and grep (which is extremely useful for understanding a 3rd-party build).
To be a good add_subdirectory or FetchContent citizen, however, it is not enough to simply namespace your targets as SomeProj_Target; you must also provide an ALIAS target SomeProj::Target. There are a few reasons for this:
Your imported targets from find_package will almost certainly be named SomeProj::Target. It should be possible for consumers of your library to switch between FetchContent and find_package easily, without changing other parts of their code. The ALIAS target lets you expose the same interface in both cases. This will become especially pressing when CMake 3.24 lands with its new find_package-to-FetchContent redirection features.
CMake's target_link_libraries function treats names that contain :: as target names always and will throw configure-time error if the target does not exist. Without the ::, it will be treated as a target preferentially, but will turn into a linker flag if the target doesn't exist. Thus, it is preferable to link to targets with :: in their names.
Yet, only IMPORTED and ALIAS targets may have :: in their names.
Points (2) and (3) are good enough for me to define aliases.
Unfortunately, many (most?) CMake builds are not good FetchContent citizens and will flaunt this convention. Following this convention yourself reduces the chance of integration issues between your project and any other, but obviously does nothing to prevent issues between two third party projects that might define conflicting targets. In these cases, you're just out of luck.
An example of defining a library called Target that will play nice with FetchContent:
add_library(SomeProj_Target ${sources})
add_library(SomeProj::Target ALIAS SomeProj_Target)
set_target_properties(
SomeProj_Target
PROPERTIES
EXPORT_NAME Target
OUTPUT_NAME Target # optional: makes the file libTarget.so on disk
)
install(TARGETS SomeProj_Target EXPORT SomeProj_Targets)
install(EXPORT SomeProj_Targets NAMESPACE SomeProj::)
For a more complete example that plays nice with install components, include paths, and dual shared/static import, see my blog post.
See these upstream issues to track the progress/discussion of these problems.
#22687 Project-level namespaces
#16414 Namespace support for target names in nested projects
As #AlexReinking , and, in fact, Craig Scott, suggest - there's no decent current solution.
You can follow the following CMake issues through which the solution will likely be achieved:
#22687 Project-level namespaces (more current)
#16414 Namespace support for target names in nested projects (longer discussion which influenced the above, recommended reading)

Why is add_custom_target always considered out of date?

According to the documentation, add_custom_target() creates a target that "ALWAYS CONSIDERED OUT OF DATE". However, the documentation also says that add_dependencies() can add dependencies between top-level targets, including one added by add_custom_target(). If add_custom_target() is always executed, is there any practical purpose to using it with add_dependencies()?
As far as CMake is concerned, add_custom_target does not produce anything that it could track to determine whether the target is out-of-date.
Contrast that with add_custom_command, where you have the ability to specify an OUTPUT produced by the command. As far as CMake knows, a custom target is just a black box, where anything could happen. That's what makes them so difficult to integrate correctly into a build.
Note that by default, custom targets are skipped altogether, you can only build them explicitly (eg. by calling make <my_target_name>). You can make them part of the default build target by either specifying the ALL option when calling add_custom_target or make another target, which is already part of the default build target, depend on your custom target.
You usually cannot add this dependency by depending on one of its output artifacts, since, as far as CMake is concerned, the custom target does not produce anything. That's why you have to use the more archaic add_dependencies instead.
If add_custom_target() is always executed, is there any practical purpose to using it with add_dependencies()?
Without ALL option add_custom_target() isn't built automatically.
Call add_dependencies(A B) makes sure that a target B will be built before a target A, so a target A may safetly use files, created for target B.
CMake article about add_custom_target() command is not very clear, so a similar question arose for me as well. We have two aspects of adding a custom target to a buildsystem:
is this target needed to be used in our buildsystem? "Used" in a sense of "materialized" - when a custom target is not only added to a buildsystem definition, but also corresponding logic is added to the generated buildsystem, so this logic will be executed during build.
when this target should be (re)built (assuming we have already decided that this custom target must be used in our buildsystem)?
Considering the first question, if we want a custom target to be used in our buildsystem we should use either "All" option or add_dependencies() command. I think that the phrase from docs:
By default nothing depends on the custom target.
implies that if we do not use "All" option or make any other target dependent on a custom target - this custom target logic will not appear in the generated buildsystem.
Regarding the second aspect, the phrase:
Add a target with no output so it will always be built.
says that a custom target is always being built when we (re)build our project (taking into account we have already made use of it using "All"/add_dependencies()), because since custom targets produce no output that build dependency resolution logic can track, it is impossible to determine when such target should be rebuilt (so it is assumed that a custom target should always be built).
Summarizing the written above: we should use a custom target with add_dependencies() command when this target is needed not only to be defined in a buildsystem, but also used in the generated buildsystem, because a custom target is always executed only if it has been already materialized in the generated buildsystem.

Get build command or all compiler flags that will be used to build a target

Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
It doesn't seem practical to try to gather and maintain a list of all properties that could add flags. Besides, CMake must have this info somewhere, since it has to eventually generate a build system.
From the CMake docs it looks like this feature once existed and was provided by calling build_command() but this was replaced:
Note In CMake versions prior to 3.0 this command returned a command
line that directly invokes the native build tool for the current
generator.
Is there a new command that gives the old behavior of build_command()?
Is there a sensible way to get a CMake variable containing the build command or all the compiler flags that CMake will associate with a target?
The answer is no (CMake 3.23 is latest at time of writing), not during the CMake configure step.
In general, such a thing is ill-defined, which is likely why it was removed from CMake and will likely not be re-added. The complications arising from generator expressions, multi-config generators, generators that don't construct command lines (like VS/msbuild), source-file-specific properties, and the simple fact that after the command is called, relevant state might change, all make such efforts quixotic.
Honestly, this is such an odd thing to want at configure time, I wonder if this isn't an XY problem. It's unlikely that one target depends on another in such a way that the entire eventual command line is needed (rather than a particular property) to create it.
I know this is many years later now, but what were you trying to do?
CMake provides many ways post-generation to get information about the compiler command lines.
There's the CMake File API, meant for IDE integration,
The CMAKE_EXPORT_COMPILE_COMMANDS option that creates a Clang-compatible compile_commands.json, and then there's
The CMAKE_<LANG>_COMPILER_LAUNCHER variables that would let you instrument a full command line with a custom script while the build is running.
One of these might be useful. The latter is commonly used with ccache, but can be (ab)used with any arbitrary program as long as the output file is eventually generated.
Note that the latter two only work with the Makefile and Ninja generators.
If you want the final output of how the source files will actually be compiled you will want to look at the generated files. I don't really know a better way currently:
Example:
Here is an example output from Ninja Multi
build\CMakeFiles\impl-Release.ninja
This file will list all of the compile definitions, compiler flags, include directories, object directory, etc.
Under the path "cmake-build-debug/CMakeFiles/" you'll find a folder named as "TopFolderOfYourProject.dir", where the cmake generates all its build system files, including a file "build.make". In this file you can see something like this:
CMakeFiles/somepath/somesourcefile.c
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=xxx\cmake-build-debug\CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building C object CMakeFiles/somepath/somesourcefile.c.obj"
Besides this, you can find extra info about the flags in the file "flags.make", it contains all extra compiler flags specified by developers.
And in "includes_C.rsp/includes_CXX.rsp" you can see the including path.
Build flags are, actually, associated with source files, because you can have differrent flags for different files. On the other hand, for the most cases these flags are equivalent.
Anyways, to get all build flags for a source file you can use COMPILE_FLAGS property:
get_source_file_property(RESULT file.cpp COMPILE_FLAGS)

Cmake not setting RPATH when adding link_library with -L

When setting link libraries in the following manner
target_link_libraries (SOME_TARGET -L/somedir -lfoo)
cmake doesn't handle RPATHs. Is using '-L' and '-l' not best practice, or actually plain wrong? When creating my own Find*.cmake I usually use find_library() but the find script I got doesn't do this and resorts to the above form using '-L' and '-l'.
The documentation doesn't really explain how RPATHs are gathered, also the documentation isn't really clear how it handles "-l" and "-L" the only pointer you get is
"Item names starting with -, but not -l or -framework, are treated as
linker flags"
Specifying toolchain-dependent flags like -l and -L is generally not recommended, as it breaks portability and might have different effects than you expect.
The correct way to set the linker path would be the link_directories command.
The idiomatic solution in CMake is to use find_library for locating the library and then pass the full path to the linker, so you do not need to worry about link directories at all.
Now, the RPATH is a different beast, as it also determines where dynamic libraries can be located at runtime. Usually, the default settings work reasonably fine here. If you ever find yourself in the unfortunate situation where it does not, there is a number of target properties and CMake variables influencing this:
There are a few properties used to specify RPATH rules. INSTALL_RPATH
is a semicolon-separated list specifying the rpath to use in installed
targets (for platforms that support it). INSTALL_RPATH_USE_LINK_PATH
is a boolean that if set to true will append directories in the linker
search path and outside the project to the INSTALL_RPATH.
SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic
generation of an rpath allowing the target to run from the build tree.
BUILD_WITH_INSTALL_RPATH is a boolean specifying whether to link the
target in the build tree with the INSTALL_RPATH. This takes precedence
over SKIP_BUILD_RPATH and avoids the need for relinking before
installation. INSTALL_NAME_DIR is a string specifying the directory
portion of the “install_name” field of shared libraries on Mac OSX to
use in the installed targets. When the target is created the values of
the variables CMAKE_INSTALL_RPATH, CMAKE_INSTALL_RPATH_USE_LINK_PATH,
CMAKE_SKIP_BUILD_RPATH, CMAKE_BUILD_WITH_INSTALL_RPATH, and
CMAKE_INSTALL_NAME_DIR are used to initialize these properties.
(From the set_target_properties docs)
Also, you might want to have a look at the CMake Wiki page for RPATH handling.
The whole RPATH business is unfortunately rather complex and a thorough explanation would require far more space than is appropriate for a StackOverflow answer, but I hope this is enough to get you started.
Basically, You're using target_link_libraries() wrong. According to documentation, You should provide target, libraries and maybe some CMake specific linkage flags.
For example something like that:
target_link_libraries(my_build_target somedir/foo.so)
If You're using Your own crafted Find*.cmake solutions, it's usualy being done like this:
find_library(foo)
//build main target somewhere here
//now link it:
target_link_libraries(my_build_target ${FOO_LIBRARIES})
NOTE: I assume Your crafted Find*.cmake files follows these guidelines and fills CMake variables like SOMELIB_LIBRARIES, and/or SOMELIB_INCLUDE_DIRS, etc.
NOTE2: for my personal opinion, target_link_directories() is pain in a butt and You should avoid using it if not really needed. It's difficult to maintain and uses paths relative to current source directory.