Specifying uncached compile-time constants in CMakeLists file - caching

In one of my CMakeList files I specified an option which conditionally defines a compile-time constant in a generated header file.
However, I recognized that the value of the option is being cached by cmake.
This leads to the unintentional behaviour that I need to delete the cmake cache everytime I change the option and issue cmake ..
Currently this is the only option being used. Later on I would like to use more options.
It is really confusing to me that the CMakeLists.txt does not represent the actual build setting due to the caching mechanism.
E.g. an build flag set in the CMakeLists.txt but still unset in the cache.
I don't want to disable caching, I just want that my build is always in sync with the build flag set in the CMakeLists.txt. I understand that cmake's caching mechanism is saving lot of time during large builds. Which is actually good.
Does there exist some means to force an option to be up-to-date on cmake .?
I tried to turn the option into a set instruction. The cmake still uses the cached value instead of the actual one.
What am I doing wrong?
Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
option(MY_BUILD_FLAG "bla" OFF)
configure_file(TestConfig.h.in TestConfig.h)
Here is my change which I unsuccessfully tried out:
cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
# Here you can set several build flags ON or OFF
set(MY_BUILD_FLAG "bla" OFF)
configure_file(TestConfig.h.in TestConfig.h)

I understand that cmake's caching mechanism is saving lot of time during large builds.
This is incorrect. The purpose of cmake cache variables is to persist variables across information for subsequent reconfigurations of the same build directory.
The fact that e.g. .o files remain in the build directory unless explicitly cleared and aren't rebuilt, if the sources for compiling it is an entirely different mechanism.
Note that you may in fact see improvements of the CMake configuration time, since e.g. results of try_compile are cached. This may actually result in a perceived improved build time, if you often rewrite the cmake files and therefore trigger an automatic cmake reconfiguration of your project before the actual build starts. However if you do not change the cmake logic, the use of CMake cache variables doesn't improve build times at all (or conditionally applying other logic resulting in a different amount of work for compiler or linker).
Note: Another notable use for cache variables is to provide project configuration options to the user. I'm not elaborating on this, since this doesn't affect build times without additional CMake logic dependent on the value influencing the amount of code to build.

Related

How do the changes to install() in CMake 3.21 affect its typical use?

Installation with CMake has always (well, so far) been a tricky process, involving multiple command invocations and notions such as version files, export sets and so on.
Now, it's true that there may have been some more changes to install() and related commands between 2017 and now, but - in CMake 3.21's release notes I see 4 changes to the install() command and at least one change to IMPORTED_TARGETS. Specifically, some of this regards dependency management.
So, how should we change our CMakeLists.txt files, our project configuration files, and the directions to developers wishing to depend on our CMake projects, to avail ourselves of these new capabilities?

What is the CMake cache?

What is CMake cache?
I'm reading the cmake manual and have occasionally come across the term cmake cache. For instance this paragraph:
-C <initial-cache>
Pre-load a script to populate the cache.
When cmake is first run in an empty build tree, it creates a
CMakeCache.txt file and populates it with customizable settings for
the project. This option may be used to specify a file from which to
load cache entries before the first pass through the project’s cmake
listfiles. The loaded entries take priority over the project’s default
values. The given file should be a CMake script containing SET
commands that use the CACHE option, not a cache-format file.
What is this cache?
Are there different types of cache?
Or would a better question be: what is cache in general?
Also, what is the importance of cache?
And are there certain caveats when dealing with cache?
For example, does the cache reset when you turn restart your computer?
CMake cache refers to a set of persistent variables - persisted in a file named CMakeCache.txt in the build directory. These include things like user configurable options, which define some behavior of your project. For example, you may run cmake -D CMAKE_BUILD_TYPE=Release . in the build directory and find that variable saved in CMakeCache.txt.
CMake only has one type of cache. It is created and saved into CMakeCache.txt after the first configuring the build, and under normal use does not reset itself.

What is the difference between .ilk and .iobj files?

I noticed that Visual Studio generates *.ilk files for debug builds and *.iobj files for release builds. As I understand, both of these file types are used as input for incremental linker. What is the difference between them? Can they be used together? How can I disable these files in project settings?
According to this answer, .iobj files are produced to support incremental link-time code generation (aka LTCG, and what used to be called, I believe, 'whole program optimization') and LTCG is normally only enabled for release builds.
One optimisation that LTCG can perform is inline a function from another compilation unit (i.e. source file). The compiler (of course) can't do this. There are no doubt others.
.ilk files, on the other hand, support incremental linking for debug builds, to get fast link times. This is not the same as incremental LTCG, where the linker tries to make use of cross-compilation-unit optimisations that it has done before, again to speed things up, but in a different way.
It follows that to suppress generation of .iobj files, turn off 'incremental link time code generation' for your project, and to suppress generation of .ilk files, turn off 'incremental linking'. I believe that both of these are linker options. But why bother? - they speed up development. Instead, I delete these files when I archive [a version of] my project.
Incremental linking is normally turned off for release builds, although I'm not sure why. Perhaps the two options are mutually incompatible, I've never tried enabling them both at once. Or maybe MS figured that we were fed up with them cluttering up our hard disks with build products, who knows?

CMake - Build custom build paths for different configurations

I have a project whose make process generates different build artifacts for each configuration, e.g. if initiated with make a=a0 b=b0 it would build object files into builds/a0.b0, generate a binary myproject.a0.b0, and finally update an ambiguous executable link to point to the most recently built project ln -s myproject.a0.b0 myproject. For this project, this is a useful feature mainly because:
It separates the object files for different configurations (so when I rebuild in another configuration I don't have to recompile every single source with new defines and configurations set, (unfortunately) a very common procedure).
It retains the binaries for each configuration (so it's not required to rebuild to use a different configuration if it has already been built).
It makes a copy (or link) to the last built binary which is useful in testing.
Right now this is implemented in an ugly decades-old non-portable Makefile. I'd like to reproduce the same behavior in CMake to allow easier building on other platforms but I have not been able to reproduce it in any reasonable manner. It seems like adding targets with add_library/executable, but doing this for each possible permutation of input parameters seems wrong. And I'm not sure I could get the utilization correct, allowing make, make a=a0, make b=b0 a=a0 as opposed to what specifying a cmake target would require: make myproject-a0.b0.
Is this possible to do in cmake? Namely:
Specify the build directory based on input parameters.
Accept the parameters as make arguments which can be left out (defaulted) to select the appropriate target at the level of the makefile (so it's not required to rerun cmake for a new configuration).

How do I suppress Xcode from generating a folder named after the build configuration in cmake?

I have a cmake configuration that works great for my project on Windows and Linux. We're tinkering with MacOS right now and we're at the point where Xcode spits out the libraries built one directory off from what we define. Instead of it being dropped in ~/bin it is dropped in ~/bin/Debug, for example. As best I can tell Xcode is taking upon itself to add this folder to the path and I don't want that.
How can I disable Xcode from doing this from within my cmake configuration?
You'll need to specify the target properties ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>, LIBRARY_OUTPUT_DIRECTORY_<CONFIG>, and/or RUNTIME_OUTPUT_DIRECTORY_<CONFIG> for each config type and each target you want to affect.
To affect all targets, you can set variables named as these with CMAKE_ prepended. Any relevant target added after these have been set will be affected.
So, for example you could either do:
add_library(MyLib ${Sources})
set_target_properties(MyLib PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
or you could do:
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
add_library(MyLib ${Sources})
Having said that, I normally find it's best to let multi-configuration generators like XCode and MSVC just add the config-specific directories. Unless you plan to also change the default names of exes and libs, these multi-config IDEs will overwrite one config's outputs with another's. So, it's hard to tell whether you're looking at a Debug or Release exe for example.
For single-config generators, I think it's common to have separate build trees per configuration to keep the distinction clear.
Basically, I wouldn't fight against the generator. CMake automates so much of the build process that I never find this slight difference between generators to be a problem. You rarely have to consider whether the output path contains a config dir or not.

Resources