diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -122,6 +122,21 @@ -ex "python register_libcxx_printer_loader()" \ +.. _include-what-you-use: + +include-what-you-use (IWYU) +=========================== + +libc++ provides an IWYU `mapping file `, +which drastically improves the accuracy of the tool when using libc++. To use the mapping file with +IWYU, you should run the tool like so: + +.. code-block:: bash + + $ include-what-you-use -Xiwyu /path/to/libcxx/include/libcxx.imp file.cpp + +If you would prefer to not use that flag, then you can replace ``/path/to/include-what-you-use/share/libcxx.imp``` +file with the libc++-provided ``libcxx.imp`` file. .. _assertions-mode: diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -779,6 +779,7 @@ istream iterator latch + libcxx.imp limits limits.h list diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp new file mode 100644 --- /dev/null +++ b/libcxx/include/libcxx.imp @@ -0,0 +1,45 @@ +[ + { include: [ "<__bits>", "private", "", "public" ] }, + { include: [ "<__hash_table>", "private", "", "public" ] }, + { include: [ "<__hash_table>", "private", "", "public" ] }, + { include: [ "<__locale>", "private", "", "public" ] }, + { include: [ "<__node_handle>", "private", "", "public" ] }, + { include: [ "<__node_handle>", "private", "", "public" ] }, + { include: [ "<__node_handle>", "private", "", "public" ] }, + { include: [ "<__node_handle>", "private", "", "public" ] }, + { include: [ "<__split_buffer>", "private", "", "public" ] }, + { include: [ "<__split_buffer>", "private", "", "public" ] }, + { include: [ "<__std_stream>", "private", "", "public" ] }, + { include: [ "<__threading_support>", "private", "", "public" ] }, + { include: [ "<__threading_support>", "private", "", "public" ] }, + { include: [ "<__threading_support>", "private", "", "public" ] }, + { include: [ "<__threading_support>", "private", "", "public" ] }, + { include: [ "<__tree>", "private", "", "public" ] }, + { include: [ "<__tree>", "private", "", "public" ] }, + { include: [ "@<__algorithm/.*>", "private", "", "public" ] }, + { include: [ "@<__bit/.*>", "private", "", "public" ] }, + { include: [ "@<__charconv/.*>", "private", "", "public" ] }, + { include: [ "@<__chrono/.*>", "private", "", "public" ] }, + { include: [ "@<__compare/.*>", "private", "", "public" ] }, + { include: [ "@<__concepts/.*>", "private", "", "public" ] }, + { include: [ "@<__coroutine/.*>", "private", "", "public" ] }, + { include: [ "@<__debug_utils/.*>", "private", "", "public" ] }, + { include: [ "@<__filesystem/.*>", "private", "", "public" ] }, + { include: [ "@<__format/.*>", "private", "", "public" ] }, + { include: [ "@<__functional/.*>", "private", "", "public" ] }, + { include: [ "@<__fwd/.*>", "private", "", "public" ] }, + { include: [ "@<__ios/.*>", "private", "", "public" ] }, + { include: [ "@<__iterator/.*>", "private", "", "public" ] }, + { include: [ "@<__memory/.*>", "private", "", "public" ] }, + { include: [ "@<__memory_resource/.*>", "private", "", "public" ] }, + { include: [ "@<__numeric/.*>", "private", "", "public" ] }, + { include: [ "@<__random/.*>", "private", "", "public" ] }, + { include: [ "@<__ranges/.*>", "private", "", "public" ] }, + { include: [ "@<__string/.*>", "private", "", "public" ] }, + { include: [ "@<__support/.*>", "private", "", "public" ] }, + { include: [ "@<__thread/.*>", "private", "", "public" ] }, + { include: [ "@<__tuple/.*>", "private", "", "public" ] }, + { include: [ "@<__type_traits/.*>", "private", "", "public" ] }, + { include: [ "@<__utility/.*>", "private", "", "public" ] }, + { include: [ "@<__variant/.*>", "private", "", "public" ] }, +] diff --git a/libcxx/utils/CMakeLists.txt b/libcxx/utils/CMakeLists.txt --- a/libcxx/utils/CMakeLists.txt +++ b/libcxx/utils/CMakeLists.txt @@ -32,6 +32,12 @@ "${LIBCXX_SOURCE_DIR}/include/__format/escaped_output_table.h" COMMENT "Generate the escaped output header") +add_custom_target(libcxx-generate-iwyu-mapping + COMMAND + "${Python3_EXECUTABLE}" + "${LIBCXX_SOURCE_DIR}/utils/generate_iwyu_mapping.py" + COMMENT "Generate the mapping file for include-what-you-use") + add_custom_target(libcxx-generate-files DEPENDS libcxx-generate-public-header-transitive-inclusion-tests libcxx-generate-public-header-tests @@ -39,4 +45,5 @@ libcxx-generate-extended-grapheme-cluster-tables libcxx-generate-extended-grapheme-cluster-tests libcxx-generate-escaped-output-table + libcxx-generate-iwyu-mapping COMMENT "Create all the auto-generated files in libc++ and its tests.") diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py new file mode 100644 --- /dev/null +++ b/libcxx/utils/generate_iwyu_mapping.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +import os, pathlib, sys + +def generate(private, public): + return f'{{ include: [ "{private}", "private", "<{public}>", "public" ] }}' + + +def panic(file): + print(f'========== {__file__} error ==========', file=sys.stderr) + print(f'\tFile \'{file}\' is a top-level detail header without a mapping', file=sys.stderr) + sys.exit(1) + + +def generate_map(include): + detail_files = [] + detail_directories = [] + c_headers = [] + + for i in include.iterdir(): + if i.is_dir() and i.name.startswith('__'): + detail_directories.append(f'{i.name}') + continue + + if i.name.startswith('__'): + detail_files.append(i.name) + continue + + if i.name.endswith('.h'): + c_headers.append(i.name) + + result = [] + for i in detail_directories: + result.append(f'{generate(f"@<{i}/.*>", i[2:])},') + + for i in detail_files: + public = [] + match i: + case '__assert': continue + case '__availability': continue + case '__bit_reference': continue + case '__bits': public = ['bits'] + case '__bsd_locale_defaults.h': continue + case '__bsd_locale_fallbacks.h': continue + case '__config_site.in': continue + case '__config': continue + case '__debug': continue + case '__errc': continue + case '__hash_table': public = ['unordered_map', 'unordered_set'] + case '__locale': public = ['locale'] + case '__mbstate_t.h': continue + case '__mutex_base': continue + case '__node_handle': public = ['map', 'set', 'unordered_map', 'unordered_set'] + case '__split_buffer': public = ['deque', 'vector'] + case '__std_stream': public = ['iostream'] + case '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread'] + case '__tree': public = ['map', 'set'] + case '__undef_macros': continue + case '__verbose_abort': continue + case _: panic() + + for p in public: + result.append(f'{generate(f"<{i}>", p)},') + + result.sort() + return result + +def main(): + monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) + assert(monorepo_root.exists()) + include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include')) + + mapping = generate_map(include) + data = '[\n ' + '\n '.join(mapping) + '\n]\n' + with open(f'{include}/libcxx.imp', 'w') as f: + f.write(data) + + +if __name__ == '__main__': + main()