From ab971dc5d38808fc884d39112b68675cf9ce3868 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Wed, 21 Feb 2024 14:56:02 -0800 Subject: [PATCH] [InstallAPI] Hookup Input files & basic ASTVisitor This patch takes in json files as input to determine that header files to process, and in which order, to pass along for CC1 invocations. This patch also includes an ASTVisitor to collect simple global variables. --- clang/include/clang/InstallAPI/Context.h | 22 ++++- clang/include/clang/InstallAPI/Frontend.h | 48 ++++++++++ clang/include/clang/InstallAPI/HeaderFile.h | 23 +++++ clang/include/clang/InstallAPI/Visitor.h | 51 ++++++++++ clang/lib/InstallAPI/CMakeLists.txt | 3 + clang/lib/InstallAPI/Frontend.cpp | 58 ++++++++++++ clang/lib/InstallAPI/Visitor.cpp | 94 +++++++++++++++++++ clang/test/InstallAPI/basic.test | 5 + clang/test/InstallAPI/variables.test | 63 +++++++++++++ .../clang-installapi/ClangInstallAPI.cpp | 76 +++++++++++++-- clang/tools/clang-installapi/Options.cpp | 29 ++++++ clang/tools/clang-installapi/Options.h | 8 ++ 12 files changed, 472 insertions(+), 8 deletions(-) create mode 100644 clang/include/clang/InstallAPI/Frontend.h create mode 100644 clang/include/clang/InstallAPI/Visitor.h create mode 100644 clang/lib/InstallAPI/Frontend.cpp create mode 100644 clang/lib/InstallAPI/Visitor.cpp create mode 100644 clang/test/InstallAPI/variables.test diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index 7d105920734fd..3e2046642c7fe 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -9,6 +9,9 @@ #ifndef LLVM_CLANG_INSTALLAPI_CONTEXT_H #define LLVM_CLANG_INSTALLAPI_CONTEXT_H +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" #include "llvm/TextAPI/InterfaceFile.h" #include "llvm/TextAPI/RecordVisitor.h" #include "llvm/TextAPI/RecordsSlice.h" @@ -24,8 +27,23 @@ struct InstallAPIContext { /// Library attributes that are typically passed as linker inputs. llvm::MachO::RecordsSlice::BinaryAttrs BA; - /// Active target triple to parse. - llvm::Triple TargetTriple{}; + /// All headers that represent a library. + HeaderSeq InputHeaders; + + /// Active language mode to parse in. + Language LangMode = Language::ObjC; + + /// Active header access type. + HeaderType Type = HeaderType::Unknown; + + /// Active TargetSlice for symbol record collection. + std::shared_ptr Slice; + + /// FileManager for all I/O operations. + FileManager *FM = nullptr; + + /// DiagnosticsEngine for all error reporting. + DiagnosticsEngine *Diags = nullptr; /// File Path of output location. llvm::StringRef OutputLoc{}; diff --git a/clang/include/clang/InstallAPI/Frontend.h b/clang/include/clang/InstallAPI/Frontend.h new file mode 100644 index 0000000000000..7ee87ae028d07 --- /dev/null +++ b/clang/include/clang/InstallAPI/Frontend.h @@ -0,0 +1,48 @@ +//===- InstallAPI/Frontend.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 +// +//===----------------------------------------------------------------------===// +/// +/// Top level wrappers for InstallAPI frontend operations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INSTALLAPI_FRONTEND_H +#define LLVM_CLANG_INSTALLAPI_FRONTEND_H + +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/InstallAPI/Context.h" +#include "clang/InstallAPI/Visitor.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// Create a buffer that contains all headers to scan +/// for global symbols with. +std::unique_ptr +createInputBuffer(const InstallAPIContext &Ctx); + +class InstallAPIAction : public ASTFrontendAction { +public: + explicit InstallAPIAction(llvm::MachO::RecordsSlice &Records) + : Records(Records) {} + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { + return std::make_unique(CI.getASTContext(), Records); + } + +private: + llvm::MachO::RecordsSlice &Records; +}; +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_FRONTEND_H diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index fc64a43b3def5..70e83bbb3e76f 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -15,6 +15,7 @@ #include "clang/Basic/LangStandard.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" #include #include @@ -32,6 +33,20 @@ enum class HeaderType { Project, }; +inline StringRef getName(const HeaderType T) { + switch (T) { + case HeaderType::Public: + return "Public"; + case HeaderType::Private: + return "Private"; + case HeaderType::Project: + return "Project"; + case HeaderType::Unknown: + return "Unknown"; + } + llvm_unreachable("unexpected header type"); +} + class HeaderFile { /// Full input path to header. std::string FullPath; @@ -52,6 +67,14 @@ class HeaderFile { static llvm::Regex getFrameworkIncludeRule(); + HeaderType getType() const { return Type; } + StringRef getIncludeName() const { return IncludeName; } + StringRef getPath() const { return FullPath; } + + bool useIncludeName() const { + return Type != HeaderType::Project && !IncludeName.empty(); + } + bool operator==(const HeaderFile &Other) const { return std::tie(Type, FullPath, IncludeName, Language) == std::tie(Other.Type, Other.FullPath, Other.IncludeName, diff --git a/clang/include/clang/InstallAPI/Visitor.h b/clang/include/clang/InstallAPI/Visitor.h new file mode 100644 index 0000000000000..95d669688e4f9 --- /dev/null +++ b/clang/include/clang/InstallAPI/Visitor.h @@ -0,0 +1,51 @@ +//===- InstallAPI/Visitor.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 +// +//===----------------------------------------------------------------------===// +/// +/// ASTVisitor Interface for InstallAPI frontend operations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INSTALLAPI_VISITOR_H +#define LLVM_CLANG_INSTALLAPI_VISITOR_H + +#include "clang/AST/Mangle.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendActions.h" +#include "llvm/ADT/Twine.h" +#include "llvm/TextAPI/RecordsSlice.h" + +namespace clang { +namespace installapi { + +/// ASTVisitor for collecting declarations that represent global symbols. +class InstallAPIVisitor final : public ASTConsumer, + public RecursiveASTVisitor { +public: + InstallAPIVisitor(ASTContext &ASTCtx, llvm::MachO::RecordsSlice &Slice) + : Slice(Slice), + MC(ItaniumMangleContext::create(ASTCtx, ASTCtx.getDiagnostics())), + Layout(ASTCtx.getTargetInfo().getDataLayoutString()) {} + void HandleTranslationUnit(ASTContext &ASTCtx) override; + + /// Collect global variables. + bool VisitVarDecl(const VarDecl *D); + +private: + std::string getMangledName(const NamedDecl *D) const; + std::string getBackendMangledName(llvm::Twine Name) const; + + llvm::MachO::RecordsSlice &Slice; + std::unique_ptr MC; + StringRef Layout; +}; + +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_VISITOR_H diff --git a/clang/lib/InstallAPI/CMakeLists.txt b/clang/lib/InstallAPI/CMakeLists.txt index fdc4f064f29e9..19fc4c3abde53 100644 --- a/clang/lib/InstallAPI/CMakeLists.txt +++ b/clang/lib/InstallAPI/CMakeLists.txt @@ -1,11 +1,14 @@ set(LLVM_LINK_COMPONENTS Support TextAPI + Core ) add_clang_library(clangInstallAPI FileList.cpp + Frontend.cpp HeaderFile.cpp + Visitor.cpp LINK_LIBS clangAST diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp new file mode 100644 index 0000000000000..9f675ef7d1bd2 --- /dev/null +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -0,0 +1,58 @@ +//===- Frontend.cpp ---------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/InstallAPI/Frontend.h" +#include "clang/AST/Availability.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; +using namespace llvm::MachO; + +namespace clang::installapi { + +static StringRef getFileExtension(clang::Language Lang) { + switch (Lang) { + default: + llvm_unreachable("Unexpected language option."); + case clang::Language::C: + return ".c"; + case clang::Language::CXX: + return ".cpp"; + case clang::Language::ObjC: + return ".m"; + case clang::Language::ObjCXX: + return ".mm"; + } +} + +std::unique_ptr createInputBuffer(const InstallAPIContext &Ctx) { + assert(Ctx.Type != HeaderType::Unknown && + "unexpected access level for parsing"); + SmallString<4096> Contents; + raw_svector_ostream OS(Contents); + for (const HeaderFile &H : Ctx.InputHeaders) { + if (H.getType() != Ctx.Type) + continue; + if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX) + OS << "#include "; + else + OS << "#import "; + if (H.useIncludeName()) + OS << "<" << H.getIncludeName() << ">"; + else + OS << "\"" << H.getPath() << "\""; + } + if (Contents.empty()) + return nullptr; + + return llvm::MemoryBuffer::getMemBufferCopy( + Contents, "installapi-includes" + getFileExtension(Ctx.LangMode)); +} + +} // namespace clang::installapi diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp new file mode 100644 index 0000000000000..9b333a6142ae8 --- /dev/null +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -0,0 +1,94 @@ +//===- Visitor.cpp ---------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/InstallAPI/Visitor.h" +#include "clang/AST/Availability.h" +#include "clang/Basic/Linkage.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" + +using namespace llvm; +using namespace llvm::MachO; + +namespace clang::installapi { + +// Exported NamedDecl needs to have externally visibiliy linkage and +// default visibility from LinkageComputer. +static bool isExported(const NamedDecl *D) { + auto LV = D->getLinkageAndVisibility(); + return isExternallyVisible(LV.getLinkage()) && + (LV.getVisibility() == DefaultVisibility); +} + +static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal) { + SymbolFlags Result = SymbolFlags::None; + if (WeakDef) + Result |= SymbolFlags::WeakDefined; + if (ThreadLocal) + Result |= SymbolFlags::ThreadLocalValue; + + return Result; +} + +void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) { + if (ASTCtx.getDiagnostics().hasErrorOccurred()) + return; + + auto *D = ASTCtx.getTranslationUnitDecl(); + TraverseDecl(D); +} + +std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const { + SmallString<256> Name; + if (MC->shouldMangleDeclName(D)) { + raw_svector_ostream NStream(Name); + MC->mangleName(D, NStream); + } else + Name += D->getNameAsString(); + + return getBackendMangledName(Name); +} + +std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const { + SmallString<256> FinalName; + Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout)); + return std::string(FinalName); +} + +/// Collect all global variables. +bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) { + // Skip function parameters. + if (isa(D)) + return true; + + // Skip variables in records. They are handled seperately for C++. + if (D->getDeclContext()->isRecord()) + return true; + + // Skip anything inside functions or methods. + if (!D->isDefinedOutsideFunctionOrMethod()) + return true; + + // If this is a template but not specialization or instantiation, skip. + if (D->getASTContext().getTemplateOrSpecializationInfo(D) && + D->getTemplateSpecializationKind() == TSK_Undeclared) + return true; + + // TODO: Capture SourceLocation & Availability for Decls. + const RecordLinkage Linkage = + isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal; + const bool WeakDef = D->hasAttr(); + const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None; + Slice.addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable, + getFlags(WeakDef, ThreadLocal)); + return true; +} + +} // namespace clang::installapi diff --git a/clang/test/InstallAPI/basic.test b/clang/test/InstallAPI/basic.test index 22b04792ca2c3..5b41ccd517b0a 100644 --- a/clang/test/InstallAPI/basic.test +++ b/clang/test/InstallAPI/basic.test @@ -16,6 +16,11 @@ // CHECK-NOT: warning: //--- basic_inputs.json +{ + "headers": [ + ], + "version": "3" +} //--- expected.tbd { diff --git a/clang/test/InstallAPI/variables.test b/clang/test/InstallAPI/variables.test new file mode 100644 index 0000000000000..6272867911f18 --- /dev/null +++ b/clang/test/InstallAPI/variables.test @@ -0,0 +1,63 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|SRC_DIR|%/t|g" %t/vars_inputs.json.in > %t/vars_inputs.json + +/// Check multiple targets are captured. +// RUN: clang-installapi -target arm64-apple-macos13.1 -target arm64e-apple-macos13.1 \ +// RUN: -fapplication-extension -install_name /usr/lib/vars.dylib \ +// RUN: %t/vars_inputs.json -o %t/vars.tbd 2>&1 | FileCheck %s --allow-empty +// RUN: llvm-readtapi -compare %t/vars.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty + +// CHECK-NOT: error: +// CHECK-NOT: warning: + +//--- vars.h +extern int foo; + +//--- vars_inputs.json.in +{ + "headers": [ { + "path" : "SRC_DIR/vars.h", + "type" : "public" + }], + "version": "3" +} + +//--- expected.tbd +{ + "main_library": { + "compatibility_versions": [ + { + "version": "0" + }], + "current_versions": [ + { + "version": "0" + }], + "install_names": [ + { + "name": "/usr/lib/vars.dylib" + } + ], + "exported_symbols": [ + { + "data": { + "global": [ + "_foo" + ] + } + } + ], + "target_info": [ + { + "min_deployment": "13.1", + "target": "arm64-macos" + }, + { + "min_deployment": "13.1", + "target": "arm64e-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp index fc23ffd7ae6b9..43c9fca0a82ee 100644 --- a/clang/tools/clang-installapi/ClangInstallAPI.cpp +++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp @@ -12,12 +12,14 @@ //===----------------------------------------------------------------------===// #include "Options.h" -#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Frontend/CompilerInstance.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/InstallAPI/Context.h" +#include "clang/InstallAPI/Frontend.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" @@ -27,7 +29,9 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/TargetParser/Host.h" +#include "llvm/TextAPI/RecordVisitor.h" #include "llvm/TextAPI/TextAPIWriter.h" +#include using namespace clang; using namespace clang::installapi; @@ -35,6 +39,36 @@ using namespace clang::driver::options; using namespace llvm::opt; using namespace llvm::MachO; +static bool runFrontend(StringRef ProgName, bool Verbose, + const InstallAPIContext &Ctx, + llvm::vfs::InMemoryFileSystem *FS, + const ArrayRef InitialArgs) { + + std::unique_ptr ProcessedInput = createInputBuffer(Ctx); + // Skip invoking cc1 when there are no header inputs. + if (!ProcessedInput) + return true; + + if (Verbose) + llvm::errs() << getName(Ctx.Type) << " Headers:\n" + << ProcessedInput->getBuffer() << "\n\n"; + + std::string InputFile = ProcessedInput->getBufferIdentifier().str(); + FS->addFile(InputFile, /*ModTime=*/0, std::move(ProcessedInput)); + // Reconstruct arguments with unique values like target triple or input + // headers. + std::vector Args = {ProgName.data(), "-target", + Ctx.Slice->getTriple().str().c_str()}; + llvm::copy(InitialArgs, std::back_inserter(Args)); + Args.push_back(InputFile); + + // Create & run invocation. + clang::tooling::ToolInvocation Invocation( + std::move(Args), std::make_unique(*Ctx.Slice), Ctx.FM); + + return Invocation.run(); +} + static bool run(ArrayRef Args, const char *ProgName) { // Setup Diagnostics engine. IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); @@ -48,9 +82,15 @@ static bool run(ArrayRef Args, const char *ProgName) { new clang::DiagnosticIDs(), DiagOpts.get(), new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get())); - // Create file manager for all file operations. + // Create file manager for all file operations and holding in-memory generated + // inputs. + llvm::IntrusiveRefCntPtr OverlayFileSystem( + new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); IntrusiveRefCntPtr FM( - new FileManager(clang::FileSystemOptions())); + new FileManager(clang::FileSystemOptions(), OverlayFileSystem)); // Set up driver to parse input arguments. auto DriverArgs = llvm::ArrayRef(Args).slice(1); @@ -71,7 +111,10 @@ static bool run(ArrayRef Args, const char *ProgName) { Options Opts(*Diag, FM.get(), ArgList); if (Diag->hasErrorOccurred()) return EXIT_FAILURE; + InstallAPIContext Ctx = Opts.createContext(); + if (Diag->hasErrorOccurred()) + return EXIT_FAILURE; // Set up compilation. std::unique_ptr CI(new CompilerInstance()); @@ -80,6 +123,21 @@ static bool run(ArrayRef Args, const char *ProgName) { if (!CI->hasDiagnostics()) return EXIT_FAILURE; + // Execute and gather AST results. + llvm::MachO::Records FrontendResults; + for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) { + for (const HeaderType Type : + {HeaderType::Public, HeaderType::Private, HeaderType::Project}) { + Ctx.Slice = std::make_shared(Trip); + Ctx.Type = Type; + if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx, + InMemoryFileSystem.get(), Opts.getClangFrontendArgs())) + return EXIT_FAILURE; + FrontendResults.emplace_back(std::move(Ctx.Slice)); + } + } + + // After symbols have been collected, prepare to write output. auto Out = CI->createOutputFile(Ctx.OutputLoc, /*Binary=*/false, /*RemoveFileOnSignal=*/false, /*UseTemporary=*/false, @@ -88,7 +146,13 @@ static bool run(ArrayRef Args, const char *ProgName) { return EXIT_FAILURE; // Assign attributes for serialization. - InterfaceFile IF; + auto Symbols = std::make_unique(); + for (const auto &FR : FrontendResults) { + SymbolConverter Converter(Symbols.get(), FR->getTarget()); + FR->visit(Converter); + } + + InterfaceFile IF(std::move(Symbols)); for (const auto &TargetInfo : Opts.DriverOpts.Targets) { IF.addTarget(TargetInfo.first); IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first); diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp index 562a643edfcf4..7d45e999448d9 100644 --- a/clang/tools/clang-installapi/Options.cpp +++ b/clang/tools/clang-installapi/Options.cpp @@ -9,6 +9,7 @@ #include "Options.h" #include "clang/Driver/Driver.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/InstallAPI/FileList.h" #include "llvm/Support/Program.h" #include "llvm/TargetParser/Host.h" @@ -68,6 +69,8 @@ bool Options::processDriverOptions(InputArgList &Args) { } } + DriverOpts.Verbose = Args.hasArgNoClaim(OPT_v); + return true; } @@ -104,10 +107,21 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM, if (!processLinkerOptions(ArgList)) return; + + /// Any remaining arguments should be handled by invoking the clang frontend. + for (const Arg *A : ArgList) { + if (A->isClaimed()) + continue; + FrontendArgs.emplace_back(A->getAsString(ArgList)); + } + FrontendArgs.push_back("-fsyntax-only"); } InstallAPIContext Options::createContext() { InstallAPIContext Ctx; + Ctx.FM = FM; + Ctx.Diags = Diags; + // InstallAPI requires two level namespacing. Ctx.BA.TwoLevelNamespace = true; @@ -116,6 +130,21 @@ InstallAPIContext Options::createContext() { Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe; Ctx.FT = DriverOpts.OutFT; Ctx.OutputLoc = DriverOpts.OutputPath; + + // Process inputs. + for (const std::string &ListPath : DriverOpts.FileLists) { + auto Buffer = FM->getBufferForFile(ListPath); + if (auto Err = Buffer.getError()) { + Diags->Report(diag::err_cannot_open_file) << ListPath; + return Ctx; + } + if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()), + Ctx.InputHeaders)) { + Diags->Report(diag::err_cannot_open_file) << ListPath; + return Ctx; + } + } + return Ctx; } diff --git a/clang/tools/clang-installapi/Options.h b/clang/tools/clang-installapi/Options.h index 4a84166a6c91b..f68addf197288 100644 --- a/clang/tools/clang-installapi/Options.h +++ b/clang/tools/clang-installapi/Options.h @@ -43,6 +43,9 @@ struct DriverOptions { /// \brief File encoding to print. llvm::MachO::FileType OutFT = llvm::MachO::FileType::TBD_V5; + + /// \brief Print verbose output. + bool Verbose = false; }; struct LinkerOptions { @@ -78,9 +81,14 @@ class Options { Options(clang::DiagnosticsEngine &Diag, FileManager *FM, llvm::opt::InputArgList &Args); + /// \brief Get CC1 arguments after extracting out the irrelevant + /// ones. + std::vector &getClangFrontendArgs() { return FrontendArgs; } + private: DiagnosticsEngine *Diags; FileManager *FM; + std::vector FrontendArgs; }; } // namespace installapi