[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
@@ -0,0 +1,300 @@ +//===- DirectoryScanner.cpp ---===// +// +// 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 +// +//===--===// + +#include "clang/InstallAPI/DirectoryScanner.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TextAPI/DylibReader.h" + +using namespace llvm; +using namespace llvm::MachO; + +namespace clang::installapi { + +HeaderSeq DirectoryScanner::getHeaders(ArrayRef Libraries) { + HeaderSeq Headers; + for (const Library : Libraries) +llvm::append_range(Headers, Lib.Headers); + return Headers; +} + +llvm::Error DirectoryScanner::scan(StringRef Directory) { + if (Mode == ScanMode::ScanFrameworks) +return scanForFrameworks(Directory); + + return scanForUnwrappedLibraries(Directory); +} + +llvm::Error DirectoryScanner::scanForUnwrappedLibraries(StringRef Directory) { + // Check some known sub-directory locations. + auto GetDirectory = [&](const char *Sub) -> OptionalDirectoryEntryRef { +SmallString Path(Directory); +sys::path::append(Path, Sub); +return FM.getOptionalDirectoryRef(Path); + }; + + auto DirPublic = GetDirectory("usr/include"); + auto DirPrivate = GetDirectory("usr/local/include"); + if (!DirPublic && !DirPrivate) { +std::error_code ec = std::make_error_code(std::errc::not_a_directory); +return createStringError(ec, + "cannot find any public (usr/include) or private " + "(usr/local/include) header directory"); + } + + Library = getOrCreateLibrary(Directory, Libraries); + Lib.IsUnwrappedDylib = true; + + if (DirPublic) +if (Error Err = scanHeaders(DirPublic->getName(), Lib, HeaderType::Public, +Directory)) + return Err; + + if (DirPrivate) +if (Error Err = scanHeaders(DirPrivate->getName(), Lib, HeaderType::Private, +Directory)) + return Err; + + return Error::success(); +} + +static bool isFramework(StringRef Path) { + while (Path.back() == '/') +Path = Path.slice(0, Path.size() - 1); + + return llvm::StringSwitch(llvm::sys::path::extension(Path)) + .Case(".framework", true) + .Default(false); +} + +Library & +DirectoryScanner::getOrCreateLibrary(StringRef Path, + std::vector ) const { + if (Path.consume_front(RootPath) && Path.empty()) +Path = "/"; + + auto LibIt = + find_if(Libs, [Path](const Library ) { return L.getPath() == Path; }); + if (LibIt != Libs.end()) +return *LibIt; + + Libs.emplace_back(Path); + return Libs.back(); +} + +Error DirectoryScanner::scanHeaders(StringRef Path, Library , +HeaderType Type, StringRef BasePath, +StringRef ParentPath) const { + std::error_code ec; + auto = FM.getVirtualFileSystem(); + PathSeq SubDirectories; + for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie; + i.increment(ec)) { +StringRef HeaderPath = i->path(); +if (ec) + return createStringError(ec, "unable to read: " + HeaderPath); + +if (sys::fs::is_symlink_file(HeaderPath)) + continue; + +// Ignore tmp files from unifdef. +const StringRef Filename = sys::path::filename(HeaderPath); +if (Filename.starts_with(".")) + continue; + +// If it is a directory, remember the subdirectory. +if (FM.getOptionalDirectoryRef(HeaderPath)) + SubDirectories.push_back(HeaderPath.str()); + +if (!isHeaderFile(HeaderPath)) + continue; + +// Skip files that do not exist. This usually happens for broken symlinks. +if (FS.status(HeaderPath) == std::errc::no_such_file_or_directory) + continue; + +auto IncludeName = createIncludeHeaderName(HeaderPath); +Lib.addHeaderFile(HeaderPath, Type, + IncludeName.has_value() ? IncludeName.value() : ""); + } + + // Go through the subdirectories. + // Sort the sub-directory first since different file systems might have + // different traverse order. + llvm::sort(SubDirectories); + if (ParentPath.empty()) +ParentPath = Path; + for (const StringRef Dir : SubDirectories) +return scanHeaders(Dir, Lib, Type, BasePath, ParentPath); cyndyishida wrote: Thanks for reporting! fixed in: https://github.com/llvm/llvm-project/pull/100636 https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
@@ -0,0 +1,300 @@ +//===- DirectoryScanner.cpp ---===// +// +// 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 +// +//===--===// + +#include "clang/InstallAPI/DirectoryScanner.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TextAPI/DylibReader.h" + +using namespace llvm; +using namespace llvm::MachO; + +namespace clang::installapi { + +HeaderSeq DirectoryScanner::getHeaders(ArrayRef Libraries) { + HeaderSeq Headers; + for (const Library : Libraries) +llvm::append_range(Headers, Lib.Headers); + return Headers; +} + +llvm::Error DirectoryScanner::scan(StringRef Directory) { + if (Mode == ScanMode::ScanFrameworks) +return scanForFrameworks(Directory); + + return scanForUnwrappedLibraries(Directory); +} + +llvm::Error DirectoryScanner::scanForUnwrappedLibraries(StringRef Directory) { + // Check some known sub-directory locations. + auto GetDirectory = [&](const char *Sub) -> OptionalDirectoryEntryRef { +SmallString Path(Directory); +sys::path::append(Path, Sub); +return FM.getOptionalDirectoryRef(Path); + }; + + auto DirPublic = GetDirectory("usr/include"); + auto DirPrivate = GetDirectory("usr/local/include"); + if (!DirPublic && !DirPrivate) { +std::error_code ec = std::make_error_code(std::errc::not_a_directory); +return createStringError(ec, + "cannot find any public (usr/include) or private " + "(usr/local/include) header directory"); + } + + Library = getOrCreateLibrary(Directory, Libraries); + Lib.IsUnwrappedDylib = true; + + if (DirPublic) +if (Error Err = scanHeaders(DirPublic->getName(), Lib, HeaderType::Public, +Directory)) + return Err; + + if (DirPrivate) +if (Error Err = scanHeaders(DirPrivate->getName(), Lib, HeaderType::Private, +Directory)) + return Err; + + return Error::success(); +} + +static bool isFramework(StringRef Path) { + while (Path.back() == '/') +Path = Path.slice(0, Path.size() - 1); + + return llvm::StringSwitch(llvm::sys::path::extension(Path)) + .Case(".framework", true) + .Default(false); +} + +Library & +DirectoryScanner::getOrCreateLibrary(StringRef Path, + std::vector ) const { + if (Path.consume_front(RootPath) && Path.empty()) +Path = "/"; + + auto LibIt = + find_if(Libs, [Path](const Library ) { return L.getPath() == Path; }); + if (LibIt != Libs.end()) +return *LibIt; + + Libs.emplace_back(Path); + return Libs.back(); +} + +Error DirectoryScanner::scanHeaders(StringRef Path, Library , +HeaderType Type, StringRef BasePath, +StringRef ParentPath) const { + std::error_code ec; + auto = FM.getVirtualFileSystem(); + PathSeq SubDirectories; + for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie; + i.increment(ec)) { +StringRef HeaderPath = i->path(); +if (ec) + return createStringError(ec, "unable to read: " + HeaderPath); + +if (sys::fs::is_symlink_file(HeaderPath)) + continue; + +// Ignore tmp files from unifdef. +const StringRef Filename = sys::path::filename(HeaderPath); +if (Filename.starts_with(".")) + continue; + +// If it is a directory, remember the subdirectory. +if (FM.getOptionalDirectoryRef(HeaderPath)) + SubDirectories.push_back(HeaderPath.str()); + +if (!isHeaderFile(HeaderPath)) + continue; + +// Skip files that do not exist. This usually happens for broken symlinks. +if (FS.status(HeaderPath) == std::errc::no_such_file_or_directory) + continue; + +auto IncludeName = createIncludeHeaderName(HeaderPath); +Lib.addHeaderFile(HeaderPath, Type, + IncludeName.has_value() ? IncludeName.value() : ""); + } + + // Go through the subdirectories. + // Sort the sub-directory first since different file systems might have + // different traverse order. + llvm::sort(SubDirectories); + if (ParentPath.empty()) +ParentPath = Path; + for (const StringRef Dir : SubDirectories) +return scanHeaders(Dir, Lib, Type, BasePath, ParentPath); mikerice1969 wrote: Hi @cyndyishida Our static verification run reports that this loop always exits on the first iteration (so it is not really a loop). Is that really what you want here? If you only want to scan the first item maybe something other than a loop makes sense? https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
https://github.com/cyndyishida closed https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
cyndyishida wrote: ping https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
https://github.com/zixu-w approved this pull request. https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/94508 >From 95cc0c9a2b135706e80a5e73ef5e4257aa89984c Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Fri, 10 May 2024 09:19:22 -0700 Subject: [PATCH] [InstallAPI] Pick up input headers by directory traversal Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 2 + .../clang/InstallAPI/DirectoryScanner.h | 81 + clang/include/clang/InstallAPI/HeaderFile.h | 13 + clang/include/clang/InstallAPI/Library.h | 65 clang/include/clang/InstallAPI/MachO.h| 1 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DirectoryScanner.cpp | 300 ++ clang/lib/InstallAPI/Library.cpp | 40 +++ clang/test/InstallAPI/asm.test| 2 +- clang/test/InstallAPI/basic.test | 4 +- clang/test/InstallAPI/binary-attributes.test | 6 +- clang/test/InstallAPI/cpp.test| 4 +- clang/test/InstallAPI/diagnostics-dsym.test | 4 +- .../InstallAPI/directory-scanning-dylib.test | 57 .../directory-scanning-frameworks.test| 88 + clang/test/InstallAPI/functions.test | 2 +- clang/test/InstallAPI/variables.test | 2 +- clang/tools/clang-installapi/Options.cpp | 51 ++- clang/tools/clang-installapi/Options.h| 3 + 19 files changed, 703 insertions(+), 24 deletions(-) create mode 100644 clang/include/clang/InstallAPI/DirectoryScanner.h create mode 100644 clang/include/clang/InstallAPI/Library.h create mode 100644 clang/lib/InstallAPI/DirectoryScanner.cpp create mode 100644 clang/lib/InstallAPI/Library.cpp create mode 100644 clang/test/InstallAPI/directory-scanning-dylib.test create mode 100644 clang/test/InstallAPI/directory-scanning-frameworks.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index cdf27247602f2..e10fa71011f30 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1' def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X">; +def err_directory_scanning: Error<"could not read directory '%0': %1">; +def err_more_than_one_library: Error<"more than one framework/dynamic library found">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/DirectoryScanner.h b/clang/include/clang/InstallAPI/DirectoryScanner.h new file mode 100644 index 0..803328982ec87 --- /dev/null +++ b/clang/include/clang/InstallAPI/DirectoryScanner.h @@ -0,0 +1,81 @@ +//===- InstallAPI/DirectoryScanner.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The DirectoryScanner for collecting library files on the file system. +/// +//===--===// +#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H +#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H + +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/Library.h" + +namespace clang::installapi { + +enum ScanMode { + /// Scanning Framework directory. + ScanFrameworks, + /// Scanning Dylib directory. + ScanDylibs, +}; + +class DirectoryScanner { +public: + DirectoryScanner(FileManager , ScanMode Mode = ScanMode::ScanFrameworks) + : FM(FM), Mode(Mode) {} + + /// Scan for all input files throughout directory. + /// + /// \param Directory Path of input directory. + llvm::Error scan(StringRef Directory); + + /// Take over ownership of stored libraries. + std::vector takeLibraries() { return std::move(Libraries); }; + + /// Get all the header files in libraries. + /// + /// \param Libraries Reference of collection of libraries. + static HeaderSeq getHeaders(ArrayRef Libraries); + +private: + /// Collect files for dylibs in usr/(local)/lib within directory. + llvm::Error scanForUnwrappedLibraries(StringRef Directory); + + /// Collect files for any frameworks within directory. + llvm::Error scanForFrameworks(StringRef Directory); + + /// Get a library from the libraries collection. + Library (StringRef Path, std::vector ) const; + + /// Collect multiple frameworks from directory.
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
@@ -97,6 +97,14 @@ class HeaderFile { Other.Excluded, Other.Extra, Other.Umbrella); } + + bool operator<(const HeaderFile ) const { ributzka wrote: Including the umbrella header first increases the likelihood of successfully parsing all the headers in the framework. Extra headers always go last. https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
@@ -97,6 +97,14 @@ class HeaderFile { Other.Excluded, Other.Extra, Other.Umbrella); } + + bool operator<(const HeaderFile ) const { cyndyishida wrote: I could infer, but I don't actually know @ributzka do you remember? https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
@@ -97,6 +97,14 @@ class HeaderFile { Other.Excluded, Other.Extra, Other.Umbrella); } + + bool operator<(const HeaderFile ) const { zixu-w wrote: What's the reasoning for the ordering? Might be easier to understand in the future with some comments. https://github.com/llvm/llvm-project/pull/94508 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/94508 >From c547d990aca29ecfe6f51d37c5c3f8712dfc5e44 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Fri, 10 May 2024 09:19:22 -0700 Subject: [PATCH 1/2] [InstallAPI] Pick up input headers by directory traversal Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 2 + .../clang/InstallAPI/DirectoryScanner.h | 81 + clang/include/clang/InstallAPI/HeaderFile.h | 8 + clang/include/clang/InstallAPI/Library.h | 65 clang/include/clang/InstallAPI/MachO.h| 1 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DirectoryScanner.cpp | 300 ++ clang/lib/InstallAPI/Library.cpp | 40 +++ clang/test/InstallAPI/asm.test| 2 +- clang/test/InstallAPI/basic.test | 4 +- clang/test/InstallAPI/binary-attributes.test | 6 +- clang/test/InstallAPI/cpp.test| 4 +- clang/test/InstallAPI/diagnostics-dsym.test | 4 +- .../InstallAPI/directory-scanning-dylib.test | 57 .../directory-scanning-frameworks.test| 89 ++ clang/test/InstallAPI/functions.test | 2 +- clang/test/InstallAPI/variables.test | 2 +- clang/tools/clang-installapi/Options.cpp | 51 ++- clang/tools/clang-installapi/Options.h| 3 + 19 files changed, 699 insertions(+), 24 deletions(-) create mode 100644 clang/include/clang/InstallAPI/DirectoryScanner.h create mode 100644 clang/include/clang/InstallAPI/Library.h create mode 100644 clang/lib/InstallAPI/DirectoryScanner.cpp create mode 100644 clang/lib/InstallAPI/Library.cpp create mode 100644 clang/test/InstallAPI/directory-scanning-dylib.test create mode 100644 clang/test/InstallAPI/directory-scanning-frameworks.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index cdf27247602f2..e10fa71011f30 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1' def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X">; +def err_directory_scanning: Error<"could not read directory '%0': %1">; +def err_more_than_one_library: Error<"more than one framework/dynamic library found">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/DirectoryScanner.h b/clang/include/clang/InstallAPI/DirectoryScanner.h new file mode 100644 index 0..803328982ec87 --- /dev/null +++ b/clang/include/clang/InstallAPI/DirectoryScanner.h @@ -0,0 +1,81 @@ +//===- InstallAPI/DirectoryScanner.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The DirectoryScanner for collecting library files on the file system. +/// +//===--===// +#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H +#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H + +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/Library.h" + +namespace clang::installapi { + +enum ScanMode { + /// Scanning Framework directory. + ScanFrameworks, + /// Scanning Dylib directory. + ScanDylibs, +}; + +class DirectoryScanner { +public: + DirectoryScanner(FileManager , ScanMode Mode = ScanMode::ScanFrameworks) + : FM(FM), Mode(Mode) {} + + /// Scan for all input files throughout directory. + /// + /// \param Directory Path of input directory. + llvm::Error scan(StringRef Directory); + + /// Take over ownership of stored libraries. + std::vector takeLibraries() { return std::move(Libraries); }; + + /// Get all the header files in libraries. + /// + /// \param Libraries Reference of collection of libraries. + static HeaderSeq getHeaders(ArrayRef Libraries); + +private: + /// Collect files for dylibs in usr/(local)/lib within directory. + llvm::Error scanForUnwrappedLibraries(StringRef Directory); + + /// Collect files for any frameworks within directory. + llvm::Error scanForFrameworks(StringRef Directory); + + /// Get a library from the libraries collection. + Library (StringRef Path, std::vector ) const; + + /// Collect multiple frameworks from
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Cyndy Ishida (cyndyishida) Changes Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory. --- Patch is 34.57 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94508.diff 19 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticInstallAPIKinds.td (+2) - (added) clang/include/clang/InstallAPI/DirectoryScanner.h (+81) - (modified) clang/include/clang/InstallAPI/HeaderFile.h (+8) - (added) clang/include/clang/InstallAPI/Library.h (+65) - (modified) clang/include/clang/InstallAPI/MachO.h (+1) - (modified) clang/lib/InstallAPI/CMakeLists.txt (+2) - (added) clang/lib/InstallAPI/DirectoryScanner.cpp (+300) - (added) clang/lib/InstallAPI/Library.cpp (+40) - (modified) clang/test/InstallAPI/asm.test (+1-1) - (modified) clang/test/InstallAPI/basic.test (+2-2) - (modified) clang/test/InstallAPI/binary-attributes.test (+4-2) - (modified) clang/test/InstallAPI/cpp.test (+2-2) - (modified) clang/test/InstallAPI/diagnostics-dsym.test (+2-2) - (added) clang/test/InstallAPI/directory-scanning-dylib.test (+57) - (added) clang/test/InstallAPI/directory-scanning-frameworks.test (+89) - (modified) clang/test/InstallAPI/functions.test (+1-1) - (modified) clang/test/InstallAPI/variables.test (+1-1) - (modified) clang/tools/clang-installapi/Options.cpp (+38-13) - (modified) clang/tools/clang-installapi/Options.h (+3) ``diff diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index cdf27247602f2..e10fa71011f30 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1' def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X">; +def err_directory_scanning: Error<"could not read directory '%0': %1">; +def err_more_than_one_library: Error<"more than one framework/dynamic library found">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/DirectoryScanner.h b/clang/include/clang/InstallAPI/DirectoryScanner.h new file mode 100644 index 0..803328982ec87 --- /dev/null +++ b/clang/include/clang/InstallAPI/DirectoryScanner.h @@ -0,0 +1,81 @@ +//===- InstallAPI/DirectoryScanner.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The DirectoryScanner for collecting library files on the file system. +/// +//===--===// +#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H +#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H + +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/Library.h" + +namespace clang::installapi { + +enum ScanMode { + /// Scanning Framework directory. + ScanFrameworks, + /// Scanning Dylib directory. + ScanDylibs, +}; + +class DirectoryScanner { +public: + DirectoryScanner(FileManager , ScanMode Mode = ScanMode::ScanFrameworks) + : FM(FM), Mode(Mode) {} + + /// Scan for all input files throughout directory. + /// + /// \param Directory Path of input directory. + llvm::Error scan(StringRef Directory); + + /// Take over ownership of stored libraries. + std::vector takeLibraries() { return std::move(Libraries); }; + + /// Get all the header files in libraries. + /// + /// \param Libraries Reference of collection of libraries. + static HeaderSeq getHeaders(ArrayRef Libraries); + +private: + /// Collect files for dylibs in usr/(local)/lib within directory. + llvm::Error scanForUnwrappedLibraries(StringRef Directory); + + /// Collect files for any frameworks within directory. + llvm::Error scanForFrameworks(StringRef Directory); + + /// Get a library from the libraries collection. + Library (StringRef Path, std::vector ) const; + + /// Collect multiple frameworks from directory. + llvm::Error scanMultipleFrameworks(StringRef Directory, + std::vector ) const; + /// Collect files from nested frameworks. + llvm::Error scanSubFrameworksDirectory(StringRef Directory, + std::vector ) const; + + /// Collect files from framework path. + llvm::Error scanFrameworkDirectory(StringRef Path, Library ) const; + + /// Collect
[clang] [InstallAPI] Pick up input headers by directory traversal (PR #94508)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/94508 Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory. >From c547d990aca29ecfe6f51d37c5c3f8712dfc5e44 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Fri, 10 May 2024 09:19:22 -0700 Subject: [PATCH] [InstallAPI] Pick up input headers by directory traversal Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 2 + .../clang/InstallAPI/DirectoryScanner.h | 81 + clang/include/clang/InstallAPI/HeaderFile.h | 8 + clang/include/clang/InstallAPI/Library.h | 65 clang/include/clang/InstallAPI/MachO.h| 1 + clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/DirectoryScanner.cpp | 300 ++ clang/lib/InstallAPI/Library.cpp | 40 +++ clang/test/InstallAPI/asm.test| 2 +- clang/test/InstallAPI/basic.test | 4 +- clang/test/InstallAPI/binary-attributes.test | 6 +- clang/test/InstallAPI/cpp.test| 4 +- clang/test/InstallAPI/diagnostics-dsym.test | 4 +- .../InstallAPI/directory-scanning-dylib.test | 57 .../directory-scanning-frameworks.test| 89 ++ clang/test/InstallAPI/functions.test | 2 +- clang/test/InstallAPI/variables.test | 2 +- clang/tools/clang-installapi/Options.cpp | 51 ++- clang/tools/clang-installapi/Options.h| 3 + 19 files changed, 699 insertions(+), 24 deletions(-) create mode 100644 clang/include/clang/InstallAPI/DirectoryScanner.h create mode 100644 clang/include/clang/InstallAPI/Library.h create mode 100644 clang/lib/InstallAPI/DirectoryScanner.cpp create mode 100644 clang/lib/InstallAPI/Library.cpp create mode 100644 clang/test/InstallAPI/directory-scanning-dylib.test create mode 100644 clang/test/InstallAPI/directory-scanning-frameworks.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index cdf27247602f2..e10fa71011f30 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1' def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X">; +def err_directory_scanning: Error<"could not read directory '%0': %1">; +def err_more_than_one_library: Error<"more than one framework/dynamic library found">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/DirectoryScanner.h b/clang/include/clang/InstallAPI/DirectoryScanner.h new file mode 100644 index 0..803328982ec87 --- /dev/null +++ b/clang/include/clang/InstallAPI/DirectoryScanner.h @@ -0,0 +1,81 @@ +//===- InstallAPI/DirectoryScanner.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The DirectoryScanner for collecting library files on the file system. +/// +//===--===// +#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H +#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H + +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/Library.h" + +namespace clang::installapi { + +enum ScanMode { + /// Scanning Framework directory. + ScanFrameworks, + /// Scanning Dylib directory. + ScanDylibs, +}; + +class DirectoryScanner { +public: + DirectoryScanner(FileManager , ScanMode Mode = ScanMode::ScanFrameworks) + : FM(FM), Mode(Mode) {} + + /// Scan for all input files throughout directory. + /// + /// \param Directory Path of input directory. + llvm::Error scan(StringRef Directory); + + /// Take over ownership of stored libraries. + std::vector takeLibraries() { return std::move(Libraries); }; + + /// Get all the header files in libraries. + /// + /// \param Libraries Reference of collection of libraries. + static HeaderSeq getHeaders(ArrayRef Libraries); + +private: + /// Collect files for dylibs in usr/(local)/lib within directory. + llvm::Error scanForUnwrappedLibraries(StringRef Directory); + + /// Collect files for any frameworks within directory. + llvm::Error scanForFrameworks(StringRef Directory); + +