blob: 13f897b07ffb47fa086a493dde3a66b14ef491f2 [file] [log] [blame]
#===----------------------------------------------------------------------===##
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
#===----------------------------------------------------------------------===##
# Test that we don't remove transitive includes of public C++ headers in the library accidentally.
# When we remove a transitive public include, clients tend to break because they don't always
# properly include what they use. Note that we don't check which system (C) headers are
# included transitively, because that is too unstable across platforms, and hence difficult
# to test for.
#
# This is not meant to block libc++ from removing unused transitive includes
# forever, however we do try to group removals for a couple of releases
# to avoid breaking users at every release.
# RUN: %{python} %s %{libcxx}/utils
import sys
sys.path.append(sys.argv[1])
from libcxx.test.header_information import lit_header_restrictions, public_headers
import re
# To re-generate the list of expected headers, temporarily set this to True, and run this test.
# Note that this needs to be done for all supported language versions of libc++:
# for std in c++03 c++11 c++14 c++17 c++20 c++23 c++26; do <build>/bin/llvm-lit --param std=$std ${path_to_this_file}; done
regenerate_expected_results = False
BLOCKLIT = '' # block Lit from interpreting a RUN/XFAIL/etc inside the generation script
if regenerate_expected_results:
print(f"""\
//--- generate-transitive-includes.sh.cpp
// RUN{BLOCKLIT}: mkdir %t
""")
all_traces = []
for header in sorted(public_headers):
if header.endswith('.h'): # Skip C compatibility or detail headers
continue
normalized_header = re.sub('/', '_', header)
print(f"""\
// RUN{BLOCKLIT}: echo "#include <{header}>" | %{{cxx}} -xc++ - %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes --preprocess > /dev/null 2> %t/trace-includes.{normalized_header}.txt
""")
all_traces.append(f'%t/trace-includes.{normalized_header}.txt')
print(f"""\
// RUN{BLOCKLIT}: %{{python}} %{{libcxx}}/test/libcxx/transitive_includes_to_csv.py {' '.join(all_traces)} > %{{libcxx}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv
""")
else:
for header in public_headers:
if header.endswith('.h'): # Skip C compatibility or detail headers
continue
# Escape slashes for the awk command below
escaped_header = header.replace('/', '\/')
print(f"""\
//--- {header}.sh.cpp
{lit_header_restrictions.get(header, '')}
// TODO: Fix this test to make it work with filesystem, localization or wide characters disabled
// UNSUPPORTED{BLOCKLIT}: no-filesystem, no-localization, no-wide-characters
// When built with modules, this test doesn't work because --trace-includes doesn't
// report the stack of includes correctly.
// UNSUPPORTED{BLOCKLIT}: modules-build
// This test uses --trace-includes, which is not supported by GCC.
// UNSUPPORTED{BLOCKLIT}: gcc
// This test is not supported when we remove the transitive includes provided for backwards
// compatibility. When we bulk-remove them, we'll adjust the includes that are expected by
// this test instead.
// UNSUPPORTED{BLOCKLIT}: transitive-includes-disabled
// TODO: Figure out why <stdatomic.h> doesn't work on FreeBSD
// UNSUPPORTED{BLOCKLIT}: LIBCXX-FREEBSD-FIXME
// RUN{BLOCKLIT}: mkdir %t
// RUN{BLOCKLIT}: %{{cxx}} %s %{{flags}} %{{compile_flags}} --trace-includes -fshow-skipped-includes --preprocess > /dev/null 2> %t/trace-includes.txt
// RUN{BLOCKLIT}: %{{python}} %{{libcxx}}/test/libcxx/transitive_includes_to_csv.py %t/trace-includes.txt > %t/actual_transitive_includes.csv
// RUN{BLOCKLIT}: cat %{{libcxx}}/test/libcxx/transitive_includes/%{{cxx_std}}.csv | awk '/^{escaped_header} / {{ print }}' > %t/expected_transitive_includes.csv
// RUN{BLOCKLIT}: diff -w %t/expected_transitive_includes.csv %t/actual_transitive_includes.csv
#include <{header}>
""")