Include What You Use

C++ User Gruppe Aachen
2. April 2025

Goals

  • about "include what you use"
  • only a SMALL Introduction
    • what it does
    • why to use it (this tool)
    • how to use it
    • and some truth (it's not a commercial)
    • NOT making you an expert
  • slides as reference

The What

  • Linter for header includes (#include)
  • based on clang (and therefore LLVM)
  • exists already ~10 years
    • IWYU 0.4 = clang 3.6
      clang release 25. Feb. 2015
    • IWYU 0.5 = clang 3.7
      clang release 28. Aug. 2015
    • IWYU 0.23 = clang 19

https://github.com/include-what-you-use/include-what-you-use/blob/master/README.md#clang-compatibility

example code


						// includes cstdint on my system
						// but also not used in code 
						#include <ratio>
						
						int main() {
							volatile uint8_t fake_out = 42;
						}
					

main.cpp @ code/01

IWYU output


						Warning: include-what-you-use reported diagnostics:

						/PATH/src/main.cpp should add these lines:
						#include <stdint.h>  // for uint8_t
						
						/PATH/src/main.cpp should remove these lines:
						- #include <ratio>  // lines 3-3
						
						The full include-list for /PATH/src/main.cpp:
						#include <stdint.h>  // for uint8_t
						---
												
					

CMake variable


						<LANG>_INCLUDE_WHAT_YOU_USE						
					

src @ https://cmake.org/cmake/help/latest/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.html

more CMake


						find_program(IWYU_PATH NAMES include-what-you-use iwyu)

						if(IWYU_PATH)
							set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE 
							${IWYU_PATH}
							-Wno-unknown-warning-option    # ignore unknown options
							-Xiwyu --max_line_length=120   # 120 chars wide
							-Xiwyu --comment_style=long    # more details 
							-Xiwyu --no_fwd_decls  			   # no forward declaration suggestions
							)  
						endif()	
					

CMakeLists.txt @ code/01

<> VS "" cpp


						#include <cstdint>

						#include "inside_redir.hpp"
						#include <outside_redir.hpp>
						
						int main() {
							volatile uint8_t fake_out = 42;
							Inside inside{};
							Outside outside{};
						}
					

main.cpp @ code/02

<> VS "" header


						// inside_redir.hpp
						#include "inside.hpp"
					

						// inside.hpp
						struct Inside {	};
					

						// outside_redir.hpp
						#include "outside.hpp"
					

						// outside.hpp
						struct Outside {	};
					

*.hpp @ code/02

<> VS "" CMAKE


						target_include_directories(example        PUBLIC "inc_inside")
						target_include_directories(example SYSTEM PUBLIC "inc_outside")	
					

CMakeLists.txt @ code/02

IWYU output


						/PATH/src/main.cpp should add these lines:
						#include <outside.hpp>  // for Outside
						#include "inside.hpp"   // for Inside
						
						/PATH/src/main.cpp should remove these lines:
						- #include <outside_redir.hpp>  // lines 4-4
						- #include "inside_redir.hpp"  // lines 3-3
						
						The full include-list for /PATH/src/main.cpp:
						#include <cstdint>      // for uint8_t
						#include <outside.hpp>  // for Outside
						#include "inside.hpp"   // for Inside					
					

LINTER PRAGMAS


						// IWYU pragma: keep
						
						// IWYU pragma: begin_keep
						// IWYU pragma: end_keep
					

						// in own header!
						// IWYU pragma: export
					

src @ https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md

IWYU output

					
					

code: *.hpp @ code/03

list

not complete!


						IWYU pragma: keep
						IWYU pragma: always_keep
						IWYU pragma: export
						IWYU pragma: no_include
						IWYU pragma: no_forward_declare
						IWYU pragma: private
						IWYU pragma: private, include "public.h"
						IWYU pragma: friend ".*favorites.*"
					

src @ github.com/include-what-you-use/[...]/docs/IWYUPragmas.md#which-pragma-should-i-use

real use case

nice example of a library using it: CLI11

https://github.com/CLIUtils/CLI11/blob/main/include/CLI/CLI.hpp

Doesn't

clang-tidy

have the same feature?

clang-tidy VS iwyu

  • clang-tidy has "misc-include-cleaner"
  • since clang 17.0 (9 Sep. 2023) = ~2 years
  • not many options

https://github.com/include-what-you-use/include-what-you-use/blob/master/README.md#clang-compatibility

the killerfeature

  • You control your own files
  • some libs use iwyu pragmas
  • other libs not so much.....
  • sometimes distros/versions make problems (internal header)
  • and patching all headerfiles? nope!

MAPPING FILES

mapping file


						[
						{
						   "include":["<outside.hpp>", "private", "<outside_redir.hpp>", "public"]
						},
						{
						   "include":["\"inside.hpp\"", "private", "\"inside_redir.hpp\"", "public"]
						} 
						]
					

inoutmapping.imp @ code/04

more CMake


						find_program(IWYU_PATH NAMES include-what-you-use iwyu)

						if(IWYU_PATH)
							set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE 
							${IWYU_PATH}
							-Wno-unknown-warning-option    	# ignore unknown options
							-Xiwyu --max_line_length=120   	# 120 chars wide
							-Xiwyu --comment_style=long 		# more details 
							-Xiwyu --no_fwd_decls						# no forward declaration suggestions
							-Xiwyu --mapping_file=${PROJECT_SOURCE_DIR}/inoutmapping.imp # mapping file
							)  
						endif()
					

CMakeLists.txt @ code/04

Helpful for

  • forwarding library header (like ThreadX <tx_api.h>)
  • wrong suggested system header (like <bits/chrono>)

bash command


						cd /usr/include/c++/14.2.1/ && \
						grep -r headername | \
						perl -nle 'm/^([^:]+).*@headername\{([^,]*)\}/ && \
						print qq@  { "include": ["<$1>", "private", "<$2>", "public"] },@' | \
						sort -u
					

modified based on gcc.libc.imp

this cmd @ 04/mapping_script.sh

New
artificial
Problems

  • not allowed to add IWYU to CMakeLists.txt
  • no parser for IWYU (bitbucket...)

compilation database

compile_commands.json (the file)
CMAKE_EXPORT_COMPILE_COMMANDS (cmake var.)

iwyu_tool


						iwyu_tool \
						-p "PATH/TO/com_cmd.json" \
						--output-format clang \
						"PATH/TO/SOURCES -- \
						-Xiwyu --max_line_length=120 \
						-Xiwyu --comment_style=long \
						-Xiwyu --no_fwd_decls \
						-Xiwyu --mapping_file=mapping_file.imp
						

But one thing
grind my gears

NEVER ever use same names as std header!
no filesystem.hpp, filesystem.h etc because of <filename><filesystem>
I learned it the hard way ("associate names", a feature)
same for "memory", "utility" etc.

END & QUESTIONS?

after talk extension

answers/references to questions after the talk

Does the mapping files support regex?

yes!
filenames start with "@" for regex syntax
src and more details @ IWYUMappings.md#include-mappings

What about clangd

Manually managing includes in a C++ translation unit, especially in the face of transitive inclusions, requires a lot of effort. Include Cleaner aims to provide diagnostics to keep includes in an IWYU-clean state.
https://clangd.llvm.org/design/include-cleaner