Why is add_custom_target always considered out of date? - cmake

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.

Related

Why do we need one more add_custom_command in cmake? [duplicate]

In CMake semantics there is some sort of distinction between "targets" and commands" that is baffling me. In Makefiles, there is no such distinction:
targetname:dependency
command
i.e. Targets correspond to a generated file of the same name.
In CMake you have commands like "add_custom_command" and "add_custom_target" that have overlapping functionality, and even in the official documentation the semantics are confused, i.e. in "Mastering CMake, 5th edition", page 110 under "Adding a custom target":
The DEPENDS argument sets up a dependency between the custom target
and the custom commands.
My understanding is that targets (generated files) have dependencies (other files, generated or no), and a command to actually do the generation. It is nonsensical to say a target depends on a command. To make matters worse, there are two flavors of "add_custom_command" that either attach an additional command to an existing target, or spit the command out into the ether.
Can someone please explain why this distinction even exists?
Targets
In general, targets comprise executables or libraries which are defined by calling add_executable or add_library and which can have many properties set.
They can have dependencies on one another, which for targets such as these just means that dependent ones will be built after their dependencies.
However, you can also define "custom targets" via add_custom_target. From the docs:
Adds a target with the given name that executes the given commands. The target has no output file and is ALWAYS CONSIDERED OUT OF DATE even if the commands try to create a file with the name of the target. Use ADD_CUSTOM_COMMAND to generate a file with dependencies. By default nothing depends on the custom target. Use ADD_DEPENDENCIES to add dependencies to or from other targets.
So these are different from "normal" targets in that they don't represent things which will produce an exe or lib, but they still benefit from all the properties that targets can have, including having or being dependencies. They appear as a target which can be built (e.g. make MyCustomTarget or msbuild MyCustomTarget.vcxproj). When you build them, you're simply invoking the commands that have been set for them. If they have dependencies on other targets (normal or custom), then these will be built first.
Custom Commands
A custom command defined via add_custom_command is quite different in that it's not a "buildable" object, and doesn't have settable properties in the way that a target does - it's not a named object which can be explicitly referred to again after it's added in the CMakeLists.txt.
It is basically a command (or set of commands) which will be invoked before building a dependent target. That's all that "depends" really means here (at least that's how I view it) - it's just saying that if A depends on B, then B will be built/executed before A is built.
The dependees of a custom command can be either set explicitly using the add_custom_command(TARGET target ... form, or implicitly by creating targets which include the files generated via the add_custom_command(OUTPUT output1 ... form.
In the first case, every time target is built, the custom command is executed first.
In the second case, it's a little more complex. If the custom command has targets which depend on its output file (and the output file doesn't already exist), it is invoked before these dependent objects are built. The dependencies are implicitly created when you do e.g. add_library(MyLib output1.h ... ) where output1.h is a file generated via add_custom_command(OUTPUT output1.h ... ).
add_custom_command adds a callable function that can have defined outputs (using the OUTPUT and BYPRODUCTS arguments). It can also have dependencies that will be run before the function is called.
Notice that it does NOT do things that you may think it does due to strange documentation (the makefile examples are very misleading). In particular, it does not have any guarantees about numbers of times it executes. For example, imagine this:
add_custom_command(OUTPUT /tmp/touched COMMAND echo touch COMMAND touch /tmp/touched)
add_custom_target(touched-one ALL DEPENDS /tmp/touched)
add_custom_target(touched-two ALL DEPENDS /tmp/touched)
How many times will "touch" be printed? You don't know, since it's not specified anywhere; make -j2 will print it twice, probably, but it's timing-dependent:
Scanning dependencies of target touched-two
Scanning dependencies of target touched-one
[ 50%] Generating touched
touch
[100%] Generating touched
touch
[100%] Built target touched-two
[100%] Built target touched-one
But Ninja will only print it once, probably:
# rm -rf * && cmake -GNinja ../c ; cmake --build . -- -j 5
[1/1] Generating touched
touch
Usually, you'll do an add_custom_command to do some work and that defines an OUTPUT, and then you'll have an add_custom_target that depends on the output of the custom command. Anyone who wants the output depends on the target, and that does give you the guarantees you want.
Caveat: see this bug for an great example of why building cross-platform metabuild tools is REALLY HARD.

Setting CMAKE_SYSROOT by generator expression

In our project we are setting CMAKE_SYSROOT depending on the selected configuration. It is so because configuration expresses (amongst others) target platform (cross-compilation - but not only, also slight behavior differences).
We would like to express this with generator expression to be friendly towards multi-configuration IDEs.
However, we haven't found a way to do so. First, you will notice that CMAKE_SYSROOT doesn't even mention such a possibility. We still tried to set it to something like this (not exact value - just a sample!):
set(CMAKE_SYSROOT $<IF:$<CONFIG:hw1>,path1,path2>)
hoping that the value is used in a context where generator expressions are supported. But apparently, it is not. Instead, it seems that the verbatim value is provided in --sysroot argument (--sysroot="\$<IF:\$<CONFIG:hw1>,path1,path2>"). Adding quotes around the value doesn't change anything.
What other options do we have?
Let me also add a note on the CMAKE_TOOLCHAIN_FILE which is mentioned in the documentation of CMAKE_SYSROOT.
I don't see the CMAKE_TOOLCHAIN_FILE being set to anything after grep-ing through files generated by cmake -DCMAKE_BUILD_TYPE=hw1 ../ and our own sources.
Apparently, the file where we set the CMAKE_SYSROOT is not pointed to by CMAKE_TOOLCHAIN_FILE. Yet, still, the --sysroot argument is being set to the expected value. (Only not by generator expression!) So, it does work somehow.
I expect we will have the same issue with other variables as well:
CMAKE_SYSTEM_NAME,
CMAKE_SYSTEM_PROCESSOR,
CMAKE_CXX_COMPILER,
CMAKE_C_COMPILER
the last two depend on the CMAKE_SYSROOT anyway (in our case).
If you really want to pass different --sysroot flags to the linker on a multi-configuration generator you'll just have to pass it via target_link_options using a generator expression. But then you might have to update rpath items yourself, but I'm not sure about that.
Variables are not used at build time and the documentation for generator expressions state:
Generator expressions are allowed in the context of many target properties...
I didn't see anything in the set command that prevents CMAKE_SYSROOT being set outside a tool-chain file. I'm guessing that the phrase This variable may only be set in a toolchain file should be This variable is normally used in a toolchain file.
It almost seems like that you are trying to use build type as a switch between two different tool chains. If that is the case then I don't see how that could work correctly with a multi-configuration generator. Most of everything you want to set is determined and used at configuration time not build time.

In CMake how to create targets with identical names?

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

CMake: Remove header dependency

Is there any way to make CMake "forget" about a file in the dependency tree? My original problem (to avoid the XY situation) is the following: I want to timestamp the build of a set of tools which have complicated dependencies among them and to other tools. Right now, I want to use a pure timestamp, but later I might want add some info from the repository (SVN). Whatever system I end up implementing needs to have the following characteristics (my "X"):
No unnecessary rebuilding: the executables should not be rebuilt on every make if the only change would be the timestamp.
Update on any change: if any tool is going to be rebuilt or relinked, either by changes to its code or to one of its dependencies, the timestamp needs to be updated.
My current solution goes along the lines of creating a custom command+target that invokes CMake at make time (so the command calls CMake itself with -P script.cmake) to generate a timestamp.h file. The main files of my tools would include that file, and the projects would depend on the target so that it gets rebuilt first.
However, this has its drawbacks: if I do update the timestamp file on every call to make, then CMake's dependency scanner would know about that file even if I do not list it as an explicit dependency of my tools. Thus, every make would trigger at least a recompilation of the respective "main" files and the corresponding relink. With tens of tools, this means slowing down the build when I may be working on just two or three of them at once.
So, I was thinking that my solution would be to somehow make CMake forget about that file when building its dependency tree for the "main" file of each tool. I would keep the dependency on the custom target that does depend on the file, so that it would be regenerated first on each call to make. However, the build tool would not consider that file as relevant to determine whether it is necessary to actually rebuild each individual tool. Thus, tools only with other changes would be rebuilt (satisfying my first criterion), and any change that causes a rebuild of a tool would obviously use the version just generated (fulfilling the second criterion).
To my chagrin, I have not found a way to make the dependency scanner forget about this file, so my solution cannot be put to use. How would I go about doing such a thing? Is it even possible, or is it completely the wrong way to go about this? I am using CMake 3.4, and my code is currently C++, but I would like a solution that did not rely on C/C++ specifics, since I have a different project (written in Fortran) in which I would also like to have build timestamping.
I've had almost the same problem than you are. Simply solved by pushing the timestamp header file into standalone target containing only this header generator command. After that you have several choices:
1.. Exclude that project from the build by the IDE you are using. For example, for the Visual Studio you can do it by several ways:
1.1. Project->Project Dependencies...->uncheck project with that header (not always works: Error while removing project dependency in VS2010)
1.2. Build->Configuration Manager...->uncheck project with that header
2.. Create an environment variable and use the condition with that variable around the add_dependencies command in the CMakeLists.txt file.
3.. Generate 2 standalone solutions through the cmake generator with included and with excluded add_dependencies in the CMakeLists.txt file.
I've used particulary [1.2]. When i need build and debug, then i uncheck the dependecy. By default, dependecy always checked, so there is no problem to miss timestamp build for a build server.
Note:
The timestamp header will be included in all projects you want to include that header (for example, through the add_library and add_executable) and you still can observe it in the IDE under a project item menu even if a project depends on the timestamp project indirectly. This is useful if you don't want to search for the timestamp project with the header to open it from there and want to open it from any project which has included that header.
So, in case of removing the timestamp header from the add_library or add_executable you won't have that opportunity.

Why does CMake make a distinction between a "target" and a "command"?

In CMake semantics there is some sort of distinction between "targets" and commands" that is baffling me. In Makefiles, there is no such distinction:
targetname:dependency
command
i.e. Targets correspond to a generated file of the same name.
In CMake you have commands like "add_custom_command" and "add_custom_target" that have overlapping functionality, and even in the official documentation the semantics are confused, i.e. in "Mastering CMake, 5th edition", page 110 under "Adding a custom target":
The DEPENDS argument sets up a dependency between the custom target
and the custom commands.
My understanding is that targets (generated files) have dependencies (other files, generated or no), and a command to actually do the generation. It is nonsensical to say a target depends on a command. To make matters worse, there are two flavors of "add_custom_command" that either attach an additional command to an existing target, or spit the command out into the ether.
Can someone please explain why this distinction even exists?
Targets
In general, targets comprise executables or libraries which are defined by calling add_executable or add_library and which can have many properties set.
They can have dependencies on one another, which for targets such as these just means that dependent ones will be built after their dependencies.
However, you can also define "custom targets" via add_custom_target. From the docs:
Adds a target with the given name that executes the given commands. The target has no output file and is ALWAYS CONSIDERED OUT OF DATE even if the commands try to create a file with the name of the target. Use ADD_CUSTOM_COMMAND to generate a file with dependencies. By default nothing depends on the custom target. Use ADD_DEPENDENCIES to add dependencies to or from other targets.
So these are different from "normal" targets in that they don't represent things which will produce an exe or lib, but they still benefit from all the properties that targets can have, including having or being dependencies. They appear as a target which can be built (e.g. make MyCustomTarget or msbuild MyCustomTarget.vcxproj). When you build them, you're simply invoking the commands that have been set for them. If they have dependencies on other targets (normal or custom), then these will be built first.
Custom Commands
A custom command defined via add_custom_command is quite different in that it's not a "buildable" object, and doesn't have settable properties in the way that a target does - it's not a named object which can be explicitly referred to again after it's added in the CMakeLists.txt.
It is basically a command (or set of commands) which will be invoked before building a dependent target. That's all that "depends" really means here (at least that's how I view it) - it's just saying that if A depends on B, then B will be built/executed before A is built.
The dependees of a custom command can be either set explicitly using the add_custom_command(TARGET target ... form, or implicitly by creating targets which include the files generated via the add_custom_command(OUTPUT output1 ... form.
In the first case, every time target is built, the custom command is executed first.
In the second case, it's a little more complex. If the custom command has targets which depend on its output file (and the output file doesn't already exist), it is invoked before these dependent objects are built. The dependencies are implicitly created when you do e.g. add_library(MyLib output1.h ... ) where output1.h is a file generated via add_custom_command(OUTPUT output1.h ... ).
add_custom_command adds a callable function that can have defined outputs (using the OUTPUT and BYPRODUCTS arguments). It can also have dependencies that will be run before the function is called.
Notice that it does NOT do things that you may think it does due to strange documentation (the makefile examples are very misleading). In particular, it does not have any guarantees about numbers of times it executes. For example, imagine this:
add_custom_command(OUTPUT /tmp/touched COMMAND echo touch COMMAND touch /tmp/touched)
add_custom_target(touched-one ALL DEPENDS /tmp/touched)
add_custom_target(touched-two ALL DEPENDS /tmp/touched)
How many times will "touch" be printed? You don't know, since it's not specified anywhere; make -j2 will print it twice, probably, but it's timing-dependent:
Scanning dependencies of target touched-two
Scanning dependencies of target touched-one
[ 50%] Generating touched
touch
[100%] Generating touched
touch
[100%] Built target touched-two
[100%] Built target touched-one
But Ninja will only print it once, probably:
# rm -rf * && cmake -GNinja ../c ; cmake --build . -- -j 5
[1/1] Generating touched
touch
Usually, you'll do an add_custom_command to do some work and that defines an OUTPUT, and then you'll have an add_custom_target that depends on the output of the custom command. Anyone who wants the output depends on the target, and that does give you the guarantees you want.
Caveat: see this bug for an great example of why building cross-platform metabuild tools is REALLY HARD.