CMake has code to walk the build graph and generate dot files.
We have a large and complex codebase, and it would be extremely useful for us to be able to walk the build graph and execute arbitrary code that has access to CMake-level information. For example, we could:
Interrogate custom target properties to write a Bill of Materials
Ensure that there’s nothing in the build graph that isn’t cleared by our legal team
Automatically generate install rules for a target and its dependencies
Detect unnecessary links
Detect include directories that break the dependencies implied by target links
Etc, etc…
Some of that code could potentially be upstreamed, for example the BoM generation or detection of odd-looking include patterns. However, some of it will always be specific to our codebase.
We could implement a plugin loading mechanism, similar to how clang-tidy handles custom checks. In clang-tidy, developers build against a specific version of LLVM and override a specific class. They compile their code into a shared library. There are very few guarantees about ABI stability and you are expected to build against the version your want to run. At run-time, there is a --load /path/to/your/plugin.so flag which you pass, and clang-tidy will execute your custom code as part of its normal workflow.
I wonder if something similar could be implemented for CMake.
So, questions:
Has this been discussed before? I couldn’t find anything
In principle, and without getting into technical details, might this plugin approach to build graph walking be accepted upstream?
It sounds like you want the file API. Basically you write a request, then after CMake generation, it writes some JSON files providing all the build graph information that you can then crawl in the manner you describe.
So the build graph traversal code that’s used for the dot file generation is a bit of a dead end? If dot file generation was being added today, it would be a stand-alone piece of code that uses the file api?
Probably? I can’t speak for the CMake developers, perhaps one of them will chime in. But the file API is the recommended way for IDEs and other tools to get build graph information from CMake.
Actually, I’m not sure the file api quite gives us the information we need. It seems a layer too close to the build system.
Let’s take dot file generation as an example. It needs to know the type of each link between targets (public, private, or interface), because graphviz wants to represent those links differently. It seems that the file API exposes “dependencies” for each target, but that’s effectively a flat list of target names. If you want to know what kind of links they are it seems you’d have to go through the backtrace and re-parse the CMake code to find the public/private/interface specifier. Have I misunderstood something here?
The dot file generator (and the build graph traversal C++ code) allows you to query CMake target properties directly, which is the level at which the dot file generator wants to work.
Okay good, so that helps with the dot file generation example.
I think in general we need access to any arbitrary property of any target of the build graph. For example, we might want to compare LINK_LIBRARIES to INCLUDE_DIRECTORIES, or write MY_CUSTOM_TARGET_PROPERTY to the bill of materials.
It seems information from more target properties is being written to the file API. Are there plans to write all target properties to the file API? What about custom target properties?
It seems the file API is taking target properties, parsing them, and outputting some derived quantities. In theory we could take these target properties and work our way back to their declaration in the CMakeLists, but that does seem like we’re going a long way around. Is the file API really the right approach here?
No. We have no intention or desire to add or maintain support for dynamically loaded plugins. We just finally ripped out the old load_command support in CMake 4.0, and do not want to add anything like that again.
Almost all of the example use cases above have been proposed as first-class features of CMake itself and have associated issue tracker entries. SBOM support is in active progress (and Qt has actually implemented it based on existing CMake features).
might this plugin approach to build graph walking be accepted upstream?
No. We have no intention or desire to add or maintain support for dynamically loaded plugins. […]
Fair enough! If we have some obscure project-specific use-case that requires interacting with target properties in this way, we’ll fork. If we come up with anything more general we’ll try and upstream a self-contained utility rather than a plugin interface.
Thanks for the quick response.
Almost all of the example use cases above have been proposed as first-class features of CMake itself and have associated issue tracker entries.
Is there a ticket for installing a branch of the tree without having to manually specify all dependencies? If so, I couldn’t find it - would you mind please linking it here?