CMake non-configurable option - c++

In CMake, how can I define an option that is not configurable by the user, but automatically calculated?
I would like to do the following:
if (FOO AND NOT BAR)
option(BOO "Foo and not bar" ON)
endif()
And then I can use BOO in different CMake files:
if (BOO)
# do something
endif()
And also in sources:
#ifdef BOO
// do something
#endif
So BOO behaves like a regular option, but is automatically calculated and not configurable by user running cmake.
EDIT: I now realize that options are not implicitly available in sources, but need to be defined explicitly with target_add_definitions or other means. So now it becomes obvious that the solution is to define BOO as a CMake variable, rather than an option.

Your "non-user-configurable" option sounds like a variable, which you can create like:
if(FOO AND NOT BAR)
set(BOO TRUE)
else()
set(BOO FALSE)
endif()
To use this variable in C++ code, you need to tell CMake to create a C++ file which defines this information. Take a look at CMake's configure_file function. Here's the official documentation, and here's part of the official CMake tutorial which walks through a simple usage of this function. I would type out some example code, but it would be a lot of boilerplate, and the linked documents do the job and should be better at answering your questions.
There is an alternative to configure_file: using target_compile_definitions. The tradeoff to make is between simplicity of implementation and build times. If the value of a compile definitions changes upon reconfiguration, then CMake has to assume that every source file of the target needs to be recompiled, since it has no information about how that definition is being used (ie. target_compile_definitions is easy to implement, but can lead to much slower build times in specific scenarios). When you use configure_file, only the files that include the file that defines those definitions need to be recompiled. There's also potentially an argumen to be made about "readability": if your target gets installed, it's easier for someone reading the installed headers to find the definition versus having to read generated CMake files to find it.

This could be done using a normal variable, but in some scenarios this information will not be available everywhere, e.g. if the subdirectory structure created by add_subdirectory does not ensure the information is required only in the CMakeLists.txt file where the info is introduced or in one of it's descendant directories.
In this case you should be using a cache variable with type internal INTERNAL. This has the added benefit of allowing you to persist the info for use during reconfiguration. You could also use FORCE to overwrite the value of any cache variable.
Example
if (... BOO not yet set properly ...)
set(BOO_VALUE ...)
set(BOO ${BOO_VALUE} CACHE INTERNAL "") # internal implies FORCE
endif()
Note that this won't make the preprocessor define available. You still need to use something like
target_compile_definitions(mytarget PRIVATE "BOO=${BOO}")

You can just use variable with set(BOO <what you want>).
You can find the documentation here: https://cmake.org/cmake/help/latest/command/set.html
But there is no option that will restrict the value of your variable for an internal settings. Only you.

Related

CMakeTutorias: target_compile_definitions(...) usage

I have been following the CMakeTutorials and I have a question at Step10:
In this step, the use of target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
is introduced.
So first question: What exactly are compile_definitions?
Second question: In the top level CMakeLists.txt, before the changes of Step10, there is this command: option(USE_MYMATH "Use tutorial provided math implementation" ON). With this command, I understand that a variable USE_MYMATH is set to ON, and this variable is used both in the CMakeLists.txt (to choose if the tutorial library will be added to the build) and to the source code (tutorial.cxx) by the precompiler.
What the changes of Step10 bring is that, the USE_MYMATH variable is no longer used for that, but it is now created by the same command (option(USE_MYMATH "Use tutorial provided math implementation" ON)) in the CMakeLists of the custom MathFunctions library. What I do not understand is why target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") is also introduced.
Based on what I understood before Step10, the option() command should set the variable USE_MYMATH, and can be used afterwards both in the CMakeLists and in the source code by the precompiler. However, if in Step10 I do not include target_compile_definitions, then the source code of the library handles the source code as undefined. Why is that?

Use autotools installation prefix

I am writing a C++ program using gtkmm as the window library and autotools as my build system. In my Makefile.am, I install the icon as follows:
icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = $(top_srcdir)/appname.svg
EDIT: changed from prefix to datadir
This results in appname.svg being copied to $(datadir)/icons/hicolor/scalable/apps when the program is installed. In my C++ code, I would like to access the icon at runtime for a window decoration:
string iconPath = DATADIR + "/icons/hicolor/scalable/apps/appname.svg";
// do stuff with the icon
I am unsure how to go about obtaining DATADIR for this purpose. I could use relative paths, but then moving the binary would break the icon, which seems evident of hackery. I figure that there should be a special way to handle icons separate from general data, since people can install 3rd party icon packs. So, I have two questions:
What is the standard way of installing and using icons with autotools/C++/gtkmm?
Edit: gtkmm has an IconTheme class that is the standard way to use icons in gtkmm. It appears that I add_resource_path() (for which I still need the installation prefix), and then I can use the library to obtain the icon by name.
What is the general method with autotools/C++ to access the autotools installation prefix?
To convey data determined by configure to your source files, the primary methods available are to write them in a header that your sources #include or to define them as macros on the compiler command line. These are handled most conveniently via the AC_DEFINE Autoconf macro. Under some circumstances, you might also consider converting source files to templates for configure to process, but except inasmuch as Autoconf itself uses an internal version of that technique to build config.h (when that is requested), I wouldn't normally recommend it.
HOWEVER, the installation prefix and other installation directories are special cases. They are not finally set until you actually run make. Even if you set them via the configure's command-line options, you can still override that by specifying different values on the make command line. Thus, it is not safe to rely on AC_DEFINE for this particular purpose, and in fact, doing so may not work at all (will not work for prefix itself).
Instead, you should specify the appropriate macro definition in a command-line option that is evaluated at make time. You can do this for all targets being built by setting the AM_CPPFLAGS variable in your Makefile.am files, as demonstrated in another answer. That particular example sets the specified symbol to be a macro that expands to a C string literal containing the prefix. Alternatively, you could consider defining the whole icon directory as a symbol. If you need it only for one target out of several then you might prefer setting the appropriate onetarget_CPPFLAGS variable.
As an aside, do note that $(prefix)/icons/hicolor/scalable/apps is a nonstandard choice for the installation directory for your icon. That will typically resolve to something like /usr/local/icons/hicolor/scalable/apps. The conventional choice would be $(datadir)/icons/hicolor/scalable/apps, which will resolve to something like /usr/local/share/icons/hicolor/scalable/apps.
In your Makefile.am, use the following
AM_CPPFLAGS = -DPREFIX='"$(prefix)"'
See Defining Directories in autoconf's manual.

CMake+git: check file sha rather than timestamp

As far as I know, CMake checks the time stamp of a source file to detect if it is outdated and needs to be rebuild (and with it, all files including it). When switching branches in a large git repository, this can causes problems.
Let's say I have one source folder and two build directories (build1 and build2), which correspond to two different branches (branch1 and branch2)
project
+-- src
+-- branch1_build
+-- branch2_build
Say my two branches have few differences, in few files; mostly, they only differ for some configuration option, all encapsulated in a config.h file, generated by the CONFIGURE_FILE command in cmake. The source files for the two config.h files (the config.h.in, as it is often called) are different. For instance, one branch introduces a new subfolder, which can be activated with a config-time option, which gets put in config.h.in with something like #cmakedefine HAVE_NEW_FEATURE_FOLDER. In such a scenario, when switching branches in the source folder, this happens: cmake recognizes that something changed in the config.h.in file, so it runs again; by running again, it generates a new config.h file; since config.h has a new time stamp, all files that includes it (directly or indirectly) end up being recompiled.
Now, if I alternatively switch between branch1 and branch2 in the source folder (cause I'm working on both branches every day), two consecutive make commands issued in the same build folder (either branch1_build or branch2_build) will trigger a full recompilation, since, although config.h has not changed in content, its time stamp has changed, so cmake flags it has changed.
My question is: what options do I have to avoid this? Or, better phrased, how can I avoid recompiling a source-build tree pair that is in fact unchanged since the last build, while also minimizing the changes to the source code?
The only solution I can think of is to execute CONFIGURE_FILE on config.h.in, with output config.h.tmp; compare config.h.tmp with config.h, and, only if different, copy config.h.tmp to config.h. However, this seems clumsy, and overcomplicated. I hoped cmake already had a mechanism for this, perhaps hidden under some options/variations of CONFIGURE_FILE...
Assuming this is not yet possible, I was wondering how complicated it would be for cmake to check the sha (rather than the timestamp) of a particular file when deciding whether it is outdated or not, and comparing it with the sha of a previous build (yes, the word outdated has date in it, but let's not get into enlish vocabulary discussions here). I imagine this is more expensive, so I would think that, if possible at all, this behavior should not be the default, and the user should use sparingly this feature, by explicitly tagging a file as check_sha_not_time kind of file. In the example above, the user would tag config.h as check_sha_not_time, and avoid recompilation of pretty much the whole library.
Note 0: I know little of how cmake internally works, so my suggestion of using sha rather than timestamp could be completely crazy and/or impossible given cmake implementation. I apologize for that. But that's why one asks things here, cause he/she doesn't know, right?
Note 1: I also tried using ccache, but unsuccessfully. Perhaps I need to use some particular flag or configuration option in ccache to trigger this capability.
Note 2: I want to avoid duplicating the source folder.

CMake - Automatically Parsing Dependencies of Precompiled Header?

As of yet, at least to my knowledge, there is no standard way in CMake to specify the addition of a precompiled header (PCH) to a project in a cross-platform manner because the way PCHs are handled by C++ compilers is very different among vendors. For G++, this is usually this is worked around by simply adding a custom command which takes care of invoking the compiler with the appropriate input and has it generate the PCH.
My current problem is that CMake will not parse the dependencies of the dependencies you specify for the custom command. For instance, assume the following structure:
pch.h
|- dependA.h
|- dependB.h
...
Only providing pch.h as a dependency will lead to the generation of the appropriate target in the corresponding makefile, which tracks changes to pch.h. However, CMake does not parse the includes inside pch.h and will therefore not recognize changes to dependA.h and dependB.h. This extends furhter if there are dependencies for dependsA.h and so on.
Note: I'm aware that the fact that PCH dependencies can and do change regularly puts the whole process in question. However, this is just the way it is and I can't really do anything about it.
Since the task isn't too hard, there are a couple of obvious ideas that come to mind:
Solution A:
Enter all the dependencies by hand. Obviously this works, but is tedious as hell and doesn't scale at all.
Solution B:
If possible, write a CMake function that automates the process and parse the includes "manually".
Solution C:
Do something similar using a different language, for instance Python, and just provide CMake a list of dependencies to add to the custom command.
Solution D:
Use gcc/g++'s feature to parse and print out the dependency tree of the PCH and parse the output to extract the list of dependencies.
My question is: does anyone know a more convenient and faster way to get this done?
The IMPLICIT_DEPENDS option of the add_custom_command might do the trick:
add_custom_command(
OUTPUT outFile
COMMAND ...
IMPLICIT_DEPENDS CXX "pch.h")
The IMPLICIT_DEPENDS option makes the generated build system scan the implicit dependencies of the given input file at build time. It is only supported for Makefile generators, though.

Can I use SCons aliasing for choosing SConscripts to run?

I'm using SCons to build a very large project, with many buildable sub-projects. I can easily use keyword commands like scons group=ai to build the AI sub-projects with if statements (choosing the right SConscripts based on the keyword command), but I want to make it as easy as possible for others to use scons. Ideally, I'd like to use it like so: scons ai to build the AI components. However, the only single-word command functionality I've found in SCons so far is aliasing, and all the examples are about changing the target. This is not what I want. Since I have a very large project with multiple sub-SConscript files to build the subprojects, I want to call the SConscripts selectively. I've tried code like so:
env.Alias("ai", SConscript("ai/SConscript", 'env'))
but this calls the AI SConscript every time, regardless of whether I use the "ai" alias or a different one. Does anyone know if it is possible to use aliasing this way to selectively call SConscripts based on the alias?
As you mentioned, the Alias() function is only used for targets. I can think of 2 ways to solve this
Alias() can be called multiple times for the same alias with different targets, so you could call it for all targets in each SConscript, then you could build everything in a SConscript. Here's an example of what I mean:
ai/SConscript:
# targets, etc
env.Alias("ai", target1)
env.Alias("ai", target2)
...
env.Alias("ai", targetn)
Another option would be to put some logic in your root SConstruct so it only calls sub-project SConscript's based on a command line argument. This option would require you to use a command line argument of this form: group=ai