From 35fce6fed29805a5d504f5a1609044d1b4959d05 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Chen Date: Tue, 7 Mar 2023 10:20:51 +0800 Subject: [PATCH] Collect libc++ headers that have no file name extensions Test: LD_LIBRARY_PATH=prebuilts/clang/host/linux-x86/clang-r475365b/lib \ out/soong/host/linux-x86/nativetest64/header-checker-unittests/header-checker-unittests Bug: 271382846 Change-Id: Ica435ac635f6ab4f500e31ae1c38c2928b6dc6ac --- .../src/utils/source_path_utils.cpp | 32 +++++++++++++++++-- .../src/utils/source_path_utils_test.cpp | 31 +++++++++++++----- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/vndk/tools/header-checker/src/utils/source_path_utils.cpp b/vndk/tools/header-checker/src/utils/source_path_utils.cpp index 8639f1655..d112087eb 100644 --- a/vndk/tools/header-checker/src/utils/source_path_utils.cpp +++ b/vndk/tools/header-checker/src/utils/source_path_utils.cpp @@ -29,13 +29,32 @@ namespace utils { static const std::vector header_extensions{ ".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}; -static bool HasHeaderExtension(llvm::StringRef &file_name) { +static const std::vector libcxx_include_dir{"libcxx", "include"}; + +static bool HasHeaderExtension(llvm::StringRef file_name) { return std::find_if(header_extensions.begin(), header_extensions.end(), [file_name](const std::string &e) { return file_name.endswith(e); }) != header_extensions.end(); } +static bool PathEndsWith(llvm::StringRef path, + const std::vector &suffix) { + auto path_it = llvm::sys::path::rbegin(path); + auto suffix_it = suffix.rbegin(); + while (suffix_it != suffix.rend()) { + if (path_it == llvm::sys::path::rend(path)) { + return false; + } + if (*path_it != *suffix_it) { + return false; + } + ++path_it; + ++suffix_it; + } + return true; +} + static std::string GetCwd() { llvm::SmallString<256> cwd; if (llvm::sys::fs::current_path(cwd)) { @@ -117,6 +136,11 @@ std::string NormalizePath(std::string_view path, const RootDirs &root_dirs) { static bool CollectExportedHeaderSet(const std::string &dir_name, std::set *exported_headers, const RootDirs &root_dirs) { + // Bazel creates temporary files in header directories. To avoid race + // condition, this function filters headers by name extensions. + // An exception is that libc++ headers do not have extensions. + bool collect_headers_without_extensions = + PathEndsWith(dir_name, libcxx_include_dir); std::error_code ec; llvm::sys::fs::recursive_directory_iterator walker(dir_name, ec); // Default construction - end of directory. @@ -136,7 +160,11 @@ static bool CollectExportedHeaderSet(const std::string &dir_name, walker.no_push(); continue; } - if (!HasHeaderExtension(file_name)) { + if (!file_name.contains(".")) { + if (!collect_headers_without_extensions) { + continue; + } + } else if (!HasHeaderExtension(file_name)) { continue; } diff --git a/vndk/tools/header-checker/src/utils/source_path_utils_test.cpp b/vndk/tools/header-checker/src/utils/source_path_utils_test.cpp index 96e637300..8bb238fdf 100644 --- a/vndk/tools/header-checker/src/utils/source_path_utils_test.cpp +++ b/vndk/tools/header-checker/src/utils/source_path_utils_test.cpp @@ -24,14 +24,20 @@ namespace header_checker { namespace utils { TEST(SourcePathUtilsTest, CollectAllExportedHeaders) { - // Prepare a header directory. TemporaryDir temp_dir; - const std::filesystem::path header_dir = temp_dir.path; + std::error_code ec; + // Prepare a header directory containing links, hidden files, etc. + const std::filesystem::path header_dir = + std::filesystem::path(temp_dir.path) / "include"; + ASSERT_TRUE(std::filesystem::create_directory(header_dir, ec)); + ASSERT_FALSE(ec); const std::filesystem::path header = header_dir / "header.h"; ASSERT_TRUE(android::base::WriteStringToFile("// test", header)); - std::error_code ec; + const std::filesystem::path no_ext_header = header_dir / "header"; + ASSERT_TRUE(android::base::WriteStringToFile("// test", no_ext_header)); + const std::filesystem::path subdir = header_dir / "subdir"; ASSERT_TRUE(std::filesystem::create_directory(subdir, ec)); ASSERT_FALSE(ec); @@ -55,15 +61,24 @@ TEST(SourcePathUtilsTest, CollectAllExportedHeaders) { const std::filesystem::path non_header_link = subdir / "header_link.txt"; std::filesystem::create_symlink(header, non_header_link, ec); ASSERT_FALSE(ec); + // Prepare a header directory like libc++. + const std::filesystem::path libcxx_dir = + std::filesystem::path(temp_dir.path) / "libcxx" / "include"; + ASSERT_TRUE(std::filesystem::create_directories(libcxx_dir, ec)); + ASSERT_FALSE(ec); + + const std::filesystem::path libcxx_header = libcxx_dir / "array"; + ASSERT_TRUE(android::base::WriteStringToFile("// test", libcxx_header)); // Test the function. - std::vector exported_header_dirs{header_dir}; - std::vector root_dirs{{header_dir, "include"}}; + std::vector exported_header_dirs{header_dir, libcxx_dir}; + std::vector root_dirs{{header_dir, "include"}, + {libcxx_dir, "libcxx"}}; std::set headers = CollectAllExportedHeaders(exported_header_dirs, root_dirs); - std::set expected_headers{"include/header.h", - "include/subdir/header_link.h", - "include/subdir_link/header_link.h"}; + std::set expected_headers{ + "include/header.h", "include/subdir/header_link.h", + "include/subdir_link/header_link.h", "libcxx/array"}; ASSERT_EQ(headers, expected_headers); }