link-what-you-include
Maintain a coherent build system target model.
This is a tool that can be used to check that a C++ build system has correctly specified the dependencies between targets based on what files the source code includes. It is analogous to Include What You Use (IWYU) but targeting inter-library dependencies rather than inter-file dependencies.
A core organizing principle of modern build systems is the target model, which is a graph of interconnected targets representing libraries, executables, and other artifacts. Each target specifies the requirements needed to build itself and also the requirements needed to be used by another target. When performing a build, the usage requirements of targets are propagated down the graph to dependent targets. This target model is a concise and powerful way to specify the relationships between the components but it can be difficult to maintain it's accuracy over the lifetime of a project. For example it is easy to make a change to the source that removes the last remaining dependency on a library but neglects to remove that dependency from the target model. The compile commands will then have unnecessary include directories, and the link command will list an unnecessary library but the build will succeed. Similarly, it is easy to start using an external library that one of your existing dependencies uses in it's interface and neglect to add that library to the target model. Since the include directories and libraries are already present in the build commands because of the transitive dependency, again the build will still succeed. Over time, mistakes like this accumulate and the effectiveness of the target model is diminished.
Both of the common mistakes mentioned above can be caught by link-what-you-include. The tool works by reading a JSON file containing target information acquired from the build system, scanning the source code for each target, mapping the set of included headers to the set of dependent libraries, and comparing these dependencies to what is reported in the JSON file. Currently, the JSON file is in a bespoke format and can only be generated for a compatible cmake based buildsytem with the provided cmake module. The eventual goal is to use CPS files instead.
Status
This tool is under development and may not be ready for production use. It is being used internally against itself and in one reasonably large project at Esri.
How to build
A compiler with support for the C++23 standard is required. The following are known to work:
- clang 21.1.8
- gcc 14.2.0
- msvc 19.51.36247.0
The following must be available:
- clang. Only the tooling libraries are needed. Must be version 18. Version 18.1.8 is known to work.
- simdjson. Versions 4.2 and greater are expected to work, but due to upstream restrictions, we require either 4.2.x or 4.6.x.
The following are optional:
- catch2. Only needed if BUILD_TESTING is enabled. Versions 3.7 and greater are expected to work.
- clang-tidy. The CI system runs clang-tidy and we have a lot of checkers enabled. You might want to run this locally if you are developing a change. Version 21 and greater are expected to work. The CI uses version 21.1.8.
Provision dependencies on Ubuntu 26.04
$ sudo apt install clang-18 libclang-18-dev libsimdjson-dev catch2
$ export Clang_ROOT=/usr/lib/llvm-18
Provision dependencies on macOS 26
$ brew install llvm@21 llvm@18 catch2 simdjson
$ export CXX=$(brew --prefix llvm@21)/bin/clang++
$ export Clang_ROOT=/opt/homebrew/opt/llvm@18
$ export Catch2_ROOT=/opt/homebrew/Cellar/catch2/3.15.1
$ export simdjson_ROOT=/opt/homebrew/Cellar/simdjson/4.6.4
Provision dependencies from source
This is relatively straight forward. Consider using the following scripts as a guide.
Build using CMake as usual.
$ cmake -GNinja -S. -Bbuild -DCMAKE_BUILD_TYPE=Debug
$ cmake --build build
$ ctest --test-dir build
If you would like to run clang-tidy as part of the build, configure with
ENABLE_CLANG_TIDY,
$ cmake -GNinja -S. -Bbuild \
-DCMAKE_BUILD_TYPE=Debug \
-DENABLE_CLANG_TIDY=ON
Or you can explicitly specify CMAKE_CXX_CLANG_TIDY.
$ cmake -GNinja -S. -Bbuild \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_CLANG_TIDY="clang-tidy-21;--warnings-as-errors=*;--use-color"
How to use with a cmake based build system
CMake 4.3 or newer is required.
The tool expects targets to define their public facing headers using
File Sets
in order to accurately compare the source file include graph to the target
model link graph.
If a target does not define any public facing headers, any header under the
BASE_DIR of one of its INTERFACE_HEADER_SETS will be associated with the
target. Since multiple targets could use the same include directory, one or
more include prefix strings can be provided to disambiguate.
Write a lwyi-config.json file to associate prefix strings with a target, and to exclude any targets from the validation. An example config file exists for this project, and a schema file describes the expected fields.
Include link_what_you_include-config.cmake
or use find_package(link_what_you_include) and call link_what_you_include(target)
for every target you want to participate in the verification process. Configure the
build system with a single-config generator. Then run the lwyi executable and point
it at the configured build directory.
$ lwyi -d /path/to/the/build/dir
Contributing
Esri welcomes contributions from anyone and everyone. Please see our guidelines for contributing.
License
Copyright 2025 Esri
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
A copy of the license is available in the repository's LICENSE.txt file.