brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · 8bef969 Raw
219 lines · cpp
1//===-- ClangInstallAPI.cpp ----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This is the entry point to clang-installapi; it is a wrapper10// for functionality in the InstallAPI clang library.11//12//===----------------------------------------------------------------------===//13 14#include "Options.h"15#include "clang/Basic/Diagnostic.h"16#include "clang/Basic/DiagnosticFrontend.h"17#include "clang/Driver/DriverDiagnostic.h"18#include "clang/Driver/Tool.h"19#include "clang/Frontend/TextDiagnosticPrinter.h"20#include "clang/InstallAPI/Frontend.h"21#include "clang/InstallAPI/FrontendRecords.h"22#include "clang/InstallAPI/InstallAPIDiagnostic.h"23#include "clang/InstallAPI/MachO.h"24#include "clang/Tooling/Tooling.h"25#include "llvm/ADT/ArrayRef.h"26#include "llvm/Option/Option.h"27#include "llvm/Support/CommandLine.h"28#include "llvm/Support/LLVMDriver.h"29#include "llvm/Support/ManagedStatic.h"30#include "llvm/Support/PrettyStackTrace.h"31#include "llvm/Support/Process.h"32#include "llvm/Support/Signals.h"33#include "llvm/TargetParser/Host.h"34#include <memory>35 36using namespace clang;37using namespace clang::installapi;38using namespace clang::options;39using namespace llvm::opt;40using namespace llvm::MachO;41 42static bool runFrontend(StringRef ProgName, Twine Label, bool Verbose,43                        InstallAPIContext &Ctx,44                        llvm::vfs::InMemoryFileSystem *FS,45                        const ArrayRef<std::string> InitialArgs) {46 47  std::unique_ptr<llvm::MemoryBuffer> ProcessedInput = createInputBuffer(Ctx);48  // Skip invoking cc1 when there are no header inputs.49  if (!ProcessedInput)50    return true;51 52  if (Verbose)53    llvm::errs() << Label << " Headers:\n"54                 << ProcessedInput->getBuffer() << "\n\n";55 56  std::string InputFile = ProcessedInput->getBufferIdentifier().str();57  FS->addFile(InputFile, /*ModTime=*/0, std::move(ProcessedInput));58  // Reconstruct arguments with unique values like target triple or input59  // headers.60  std::vector<std::string> Args = {ProgName.data(), "-target",61                                   Ctx.Slice->getTriple().str().c_str()};62  llvm::append_range(Args, InitialArgs);63  Args.push_back(InputFile);64 65  // Create & run invocation.66  clang::tooling::ToolInvocation Invocation(67      std::move(Args), std::make_unique<InstallAPIAction>(Ctx), Ctx.FM);68  return Invocation.run();69}70 71static bool run(ArrayRef<const char *> Args, const char *ProgName) {72  // Setup Diagnostics engine.73  DiagnosticOptions DiagOpts;74  const llvm::opt::OptTable &ClangOpts = getDriverOptTable();75  unsigned MissingArgIndex, MissingArgCount;76  llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(77      ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);78  ParseDiagnosticArgs(DiagOpts, ParsedArgs);79 80  auto Diag = llvm::makeIntrusiveRefCnt<clang::DiagnosticsEngine>(81      clang::DiagnosticIDs::create(), DiagOpts,82      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts));83 84  // Create file manager for all file operations and holding in-memory generated85  // inputs.86  auto OverlayFileSystem =87      llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(88          llvm::vfs::getRealFileSystem());89  auto InMemoryFileSystem =90      llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();91  OverlayFileSystem->pushOverlay(InMemoryFileSystem);92  IntrusiveRefCntPtr<clang::FileManager> FM =93      llvm::makeIntrusiveRefCnt<FileManager>(clang::FileSystemOptions(),94                                             OverlayFileSystem);95 96  // Capture all options and diagnose any errors.97  Options Opts(*Diag, FM.get(), Args, ProgName);98  if (Diag->hasErrorOccurred())99    return EXIT_FAILURE;100 101  InstallAPIContext Ctx = Opts.createContext();102  if (Diag->hasErrorOccurred())103    return EXIT_FAILURE;104 105  if (!Opts.DriverOpts.DylibToVerify.empty()) {106    TargetList Targets;107    for (const auto &T : Opts.DriverOpts.Targets)108      Targets.push_back(T.first);109    if (!Ctx.Verifier->verifyBinaryAttrs(Targets, Ctx.BA, Ctx.Reexports,110                                         Opts.LinkerOpts.AllowableClients,111                                         Opts.LinkerOpts.RPaths, Ctx.FT))112      return EXIT_FAILURE;113  };114 115  // Set up compilation.116  std::unique_ptr<CompilerInstance> CI(new CompilerInstance());117  CI->setVirtualFileSystem(FM->getVirtualFileSystemPtr());118  CI->setFileManager(FM);119  CI->createDiagnostics();120  if (!CI->hasDiagnostics())121    return EXIT_FAILURE;122 123  // Execute, verify and gather AST results.124  // An invocation is ran for each unique target triple and for each header125  // access level.126  Records FrontendRecords;127  for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {128    Ctx.Verifier->setTarget(Targ);129    Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);130    for (const HeaderType Type :131         {HeaderType::Public, HeaderType::Private, HeaderType::Project}) {132      std::vector<std::string> ArgStrings = Opts.getClangFrontendArgs();133      Opts.addConditionalCC1Args(ArgStrings, Trip, Type);134      Ctx.Type = Type;135      StringRef HeaderLabel = getName(Ctx.Type);136      if (!runFrontend(ProgName, HeaderLabel, Opts.DriverOpts.Verbose, Ctx,137                       InMemoryFileSystem.get(), ArgStrings))138        return EXIT_FAILURE;139 140      // Run extra passes for unique compiler arguments.141      for (const auto &[Label, ExtraArgs] : Opts.FEOpts.UniqueArgs) {142        std::vector<std::string> FinalArguments = ArgStrings;143        llvm::append_range(FinalArguments, ExtraArgs);144        if (!runFrontend(ProgName, Label + " " + HeaderLabel,145                         Opts.DriverOpts.Verbose, Ctx, InMemoryFileSystem.get(),146                         FinalArguments))147          return EXIT_FAILURE;148      }149    }150    FrontendRecords.emplace_back(std::move(Ctx.Slice));151  }152 153  if (Ctx.Verifier->verifyRemainingSymbols() == DylibVerifier::Result::Invalid)154    return EXIT_FAILURE;155 156  // After symbols have been collected, prepare to write output.157  auto Out = CI->getOrCreateOutputManager().createFile(158      Ctx.OutputLoc, llvm::vfs::OutputConfig()159                         .setTextWithCRLF()160                         .setNoImplyCreateDirectories()161                         .setNoAtomicWrite());162  if (!Out) {163    Diag->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;164    return EXIT_FAILURE;165  }166 167  // Assign attributes for serialization.168  InterfaceFile IF(Ctx.Verifier->takeExports());169  // Assign attributes that are the same per slice first.170  for (const auto &TargetInfo : Opts.DriverOpts.Targets) {171    IF.addTarget(TargetInfo.first);172    IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);173  }174  // Then assign potentially different attributes per slice after.175  auto assignLibAttrs =176      [&IF](177          const auto &Attrs,178          std::function<void(InterfaceFile *, StringRef, const Target &)> Add) {179        for (const auto &[Attr, ArchSet] : Attrs.get())180          for (const auto &T : IF.targets(ArchSet))181            Add(&IF, Attr, T);182      };183 184  assignLibAttrs(Opts.LinkerOpts.AllowableClients,185                 &InterfaceFile::addAllowableClient);186  assignLibAttrs(Opts.LinkerOpts.RPaths, &InterfaceFile::addRPath);187  assignLibAttrs(Ctx.Reexports, &InterfaceFile::addReexportedLibrary);188 189  // Write output file and perform CI cleanup.190  if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {191    Diag->Report(diag::err_cannot_write_file)192        << Ctx.OutputLoc << std::move(Err);193    if (auto Err = Out->discard())194      llvm::consumeError(std::move(Err));195    return EXIT_FAILURE;196  }197  if (auto Err = Out->keep()) {198    Diag->Report(diag::err_cannot_write_file)199        << Ctx.OutputLoc << std::move(Err);200    return EXIT_FAILURE;201  }202  return EXIT_SUCCESS;203}204 205int clang_installapi_main(int argc, char **argv,206                          const llvm::ToolContext &ToolContext) {207  // Standard set up, so program fails gracefully.208  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);209  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);210  llvm::llvm_shutdown_obj Shutdown;211 212  if (llvm::sys::Process::FixupStandardFileDescriptors())213    return EXIT_FAILURE;214 215  const char *ProgName =216      ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;217  return run(llvm::ArrayRef(argv, argc), ProgName);218}219