Can CMakeLists.txt depend on a file parsed by a function? - cmake

I am rather new to CMake, starting off for the first time with a larger project consisting of many subprojects.
For particular reasons (described below for the curious) I already have a set of include files that contain info about the source files needed for each CMake target (lib or exe) – and, for now, I prefer to (re)use these files (reason also described below)
Writing a function to parse these files and add their content as source files to the targets was a surprisingly easy task.
But – now the Problem:
Obviously I want to have each targets CMakeLists.txt depend on the particular include file, that generates the list of source files, so that changes on the include file will be detected as if it were changes to CMakeLists.txt itself, but I simply can’t find any references on how to accomplish that.
N.B.: I found AddFileDependencies but that is for adding dependencies on source files, not the CMakeLists.txt. However, CMake itself can figure out dependencies to included .cmake file somehow, so I figured, it should be possible to do somehow.
Background for the curious:
For this project (quite a number of libraries used by quite a number of executable targets, all organized as subprojects) I was using QMake (without actually using Qt itself) for setting up makefiles. Doing so I was able to use Qt Creator while still being able to generate Visual Studio Solution/Project files automagically. We’re also still in progress of evaluating different IDEs and the choice has not been made yet. But the most important reason to use a generator like QMake / CMake was not being forced to set up the VS files for all these subprojects manually.
Although I needed to trick QMake sometimes to do what I wanted to, things went quite well - even for the VS solution - except for one thing: Visual Studio messes up dependencies on Flex/Bison and other files using custom build rules. It keeps recompiling the Flex/Bison/other files saying „command line changed“ – which I gave up trying to fix.
For this reason I thougt, I’d try CMake as a generator instead, which looks very promising so far – although not having builtin precompiled header support in CMake is somewhat ridiculous these days (off topic, I know).
Since Qt Creators CMake support is by far not as good as the support for QMake projects, I firgured, using the approach of parsing the .pri files containing the source file list would enable me using QMake and CMake side by side – especially since the remaining project settings are rather less complicated than on most open source projects.

There's a nice trick which does exactly what you need. It's based on the idea I found in the git-revision module of #rpavlik see this so question
This is the overall idea:
Create a dummy timestamp file
Add a custom command which touches the timestamp whenever the input .pri file changes
include the timestamp file in your CMakeLists.txt
A possible implementation:
set(input_pri_file <path-to-the-input-pri-file>)
set(timestamp_file ${CMAKE_CURRENT_BINARY_DIR}/timestamp.cmake)
add_custom_command(
OUTPUT ${timestamp_file}
COMMAND ${CMAKE_COMMAND} -E touch ${timestamp_file}
MAIN_DEPENDENCY ${input_pri_file}
VERBATIM
COMMENT "Updating timestamp.cmake"
)
if(NOT EXISTS "${timestamp_file}")
file(WRITE ${timestamp_file} "") # create initial empty file
endif()
include(${timestamp_file})
# create the file list from input_pri_file
....
# use the file list
add_executable(main ${filelist})
Here's what happens when the .pri file changes:
the change triggers the execution of the custom command
which updates the timestamp
because the CMakeLists includes the timestamp it is dependent on it
so updating the timestamp triggers a re-configuration of the CMakeLists.txt

I use the configure_file() if I have some input that should retrigger CMake's configuration process. See e.g. How to make CMake reconfiguration depend on custom file? and configure_file()'s unit test
So in your case it would look something like:
configure_file(SomeInput.pri ${CMAKE_CURRENT_BINARY_DIR}/SomeInput.pri)
Then you use ${CMAKE_CURRENT_BINARY_DIR}/SomeInput.pri to generate the sources. Just make sure you do not add COPYONLY, because then configuration won't retrigger on changes of SomeInput.pri.
EDIT: Alternatively use - a relative new addition - the CMAKE_CONFIGURE_DEPENDS directory property.

Related

Code generator generating its own CMake files and targets

Let's assume I have a script that generates a set of source files forming a target I want to link against in a CMakeLists.txt. If the file names are known to the latter then the usual add_custom_target() and add_custom_command() commands will make it possible to use the generated files as target sources.
Let's assume, though, that only the generator script knows the file names and locations. How can a target library be generated so that the parent CMakeLists.txt can link against it without its knowing the actual file names?
Note that the dependency topic isn't in this question's scope as the script knows itself when to regenerate or not. It's not the finest use of CMake, but it's sufficient in this use case.
Idea #1
The script also generates a generated.cmake file included by the parent one using include(generated.cmake). Problem: CMake doesn't find generated.cmake as it isn't existing at configuration time.
Idea #2
Similar to idea #1, but the script is called with the execute_process() so that generated.cmake is present at configuration time. Problem: The script is not called anymore at subsequent builds, thus ignoring possible changes to its input.
Idea #3
The script passes back a list of targets and files that is somehow considered by the parent CMakeLists.txt. So far I couldn't find a way to do so.
The solution I came with is eventually a mixture of all three ideas.
Solution to idea #1's problem
execute_process() actually ensures that generated_targets.cmake is present at configure time.
Solution to idea #2's and #3's problems
As stated in this answer to "Add dependency to the CMake-generated build-system itself", the CMAKE_CONFIGURE_DEPENDS directory property can be edited to add files whose touching re-triggers the configure step.
The key success factor is that this property can be set after the initial execute_process() call so that the script can identify and list its input dependencies (in an output file) that are then added to CMAKE_CONFIGURE_DEPENDS, hence also solving the input dependency problem.
Resulting pseudo code
# The script generates:
# - <output_dir>/cmake/input_files
# - <output_dir>/cmake/generated_targets.cmake
execute_process(
COMMAND myScript
--output-dir ${CMAKE_CURRENT_BINARY_DIR}/generated
)
# Mark the input files as configure step dependencies so that the execute_process
# commands are retriggered on input file change.
file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/input_files _input_files)
set_property(
DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
${_input_files}
)
# Add the generated CMake targets.
include(${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/generated_targets.cmake)

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.

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)

Why is cmake file GLOB evil?

The CMake doc says about the command file GLOB:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
Several discussion threads in the web second that globbing source files is evil.
However, to make the build system know that a source has been added or removed, it's sufficient to say
touch CMakeLists.txt
Right?
Then that's less effort than editing CMakeLists.txt to insert or delete a source file name. Nor is it more difficult to remember. So I don't see any good reason to advise against file GLOB.
What's wrong with this argument?
The problem is when you're not alone working on a project.
Let's say project has developer A and B.
A adds a new source file x.c. He doesn't changes CMakeLists.txt and commits after he's finished implementing x.c.
Now B does a git pull, and since there have been no modifications to the CMakeLists.txt, CMake isn't run again and B causes linker errors when compiling, because x.c has not been added to its source files list.
2020 Edit: CMake 3.12 introduces the CONFIGURE_DEPENDS argument to file(GLOB which makes globbing scan for new files: https://cmake.org/cmake/help/v3.12/command/file.html#filesystem
This is however not portable (as Visual Studio or Xcode solutions don't support the feature) so please only use that as a first approximation, else other people can have trouble building your CMake files under their IDE of choice!
It's not inherently evil - it has advantanges and disadvantages, covered relatively well in this answer here on StackOverflow. But if you use it carelessly, you could end up ignoring dependency changes and requiring clean rebuilds of large parts of your codebase.
I'm personally in favor of using it - in smaller projects, or on certain subdirectories in larger ones - to avoid having to enter every file manually into the build files. Edit: My preference has changed and I currently tend to avoid it.
On top of the reasons other people here posted, imho the worst issue with glob is that it can yield DIFFERENT file lists on different platforms. As I see it, that's a bug. In OSX glob ignores case sensitivity and in a ubuntu box it doesn't.
Globbing breaks all code inspection in things like CLion that otherwise understand limited subsets of CMakeLists.txt and do not and never will support globbing as it is unsafe.
Write script to dump the globbed list and paste it in, its very simple, and then CLion can actually find the referenced files and infer them as useful. Maybe even put such script into the tree so that the other devs can either run it without being a moron OR set git hooks to make it happen.
In no case should some random file dropped into some directory ever get automatically linked that's how trojans happen.
Also CLion without context jumping to known definitions and what not, is like hiking barefoot /// why bother.

How can I control build order in cmake without adding static dependencies?

I'm using OpenGL Loader Generator to generate GL function loading code for my project. It generates gl_loader.h and gl_loader.c. Some of my other source files depend on gl_loader.h, but not all of them, so I need cmake to (re)run glLoadGen if necessary, before compiling the rest of the code, otherwise the build stops with errors because it's trying to compile a file that depends on gl_loader.h before gl_loader.h has been built. I have added the GENERATED property to gl_loader.h/.c but this isn't quite the problem the property is designed to solve and it didn't work.
In this case I can simply add an OBJECT_DEPENDS property to all of my source files, because I will hardly ever need to rerun glLoadGen. But in other situations this would cause too much unnecessary recompilation, such as when several C source and header files are generated by GObjectBuilder (gob2). Manually working out which C files depend on which generated header is impractical.
Another possibility in this case is to run glLoadGen at configure time instead of build time, but that wouldn't be appropriate for the other scenario with gob2.
Is there any other way to tell cmake that it has to run glLoadGen before compiling the other code?
This seems like the ideal scenario for the GENERATED source file property. It basically tells CMake to not worry about the source file not existing at configure time (when CMake runs); it will be available when it's needed at build time (when make/vc/etc. runs).
I'm not familiar with OpenGL or its Loader Generator, but if you use the OUTPUT form of add_custom_command to invoke glLoadGen, the GENERATED property is automatically applied to the output files:
add_custom_command(OUTPUT gl_loader.h gl_loader.c
COMMAND glLoadGen [whatever args are needed]
COMMENT "Generating gl_loader.h and gl_loader.c")
...
add_executable(MyExe ${OtherSources} gl_loader.h gl_loader.c)
WIth this setup, when you build MyExe, the custom command should execute first (if required) producing the appropriate sources (gl_loader.h/.c)