[Github] Label lldb-dap PRs (#125139)
[llvm-project.git] / clang / tools / clang-installapi / ClangInstallAPI.cpp
blobce6240b1b56f1ef10d5bbb844b76614480cc64e9
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This is the entry point to clang-installapi; it is a wrapper
10 // for functionality in the InstallAPI clang library.
12 //===----------------------------------------------------------------------===//
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>
36 using namespace clang;
37 using namespace clang::installapi;
38 using namespace clang::driver::options;
39 using namespace llvm::opt;
40 using namespace llvm::MachO;
42 static bool runFrontend(StringRef ProgName, Twine Label, bool Verbose,
43 InstallAPIContext &Ctx,
44 llvm::vfs::InMemoryFileSystem *FS,
45 const ArrayRef<std::string> InitialArgs) {
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;
52 if (Verbose)
53 llvm::errs() << Label << " Headers:\n"
54 << ProcessedInput->getBuffer() << "\n\n";
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 input
59 // headers.
60 std::vector<std::string> Args = {ProgName.data(), "-target",
61 Ctx.Slice->getTriple().str().c_str()};
62 llvm::copy(InitialArgs, std::back_inserter(Args));
63 Args.push_back(InputFile);
65 // Create & run invocation.
66 clang::tooling::ToolInvocation Invocation(
67 std::move(Args), std::make_unique<InstallAPIAction>(Ctx), Ctx.FM);
68 return Invocation.run();
71 static bool run(ArrayRef<const char *> Args, const char *ProgName) {
72 // Setup Diagnostics engine.
73 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
74 const llvm::opt::OptTable &ClangOpts = clang::driver::getDriverOptTable();
75 unsigned MissingArgIndex, MissingArgCount;
76 llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(
77 ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);
78 ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
80 IntrusiveRefCntPtr<DiagnosticsEngine> Diag = new clang::DiagnosticsEngine(
81 new clang::DiagnosticIDs(), DiagOpts.get(),
82 new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
84 // Create file manager for all file operations and holding in-memory generated
85 // inputs.
86 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
87 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
88 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
89 new llvm::vfs::InMemoryFileSystem);
90 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
91 IntrusiveRefCntPtr<clang::FileManager> FM(
92 new FileManager(clang::FileSystemOptions(), OverlayFileSystem));
94 // Capture all options and diagnose any errors.
95 Options Opts(*Diag, FM.get(), Args, ProgName);
96 if (Diag->hasErrorOccurred())
97 return EXIT_FAILURE;
99 InstallAPIContext Ctx = Opts.createContext();
100 if (Diag->hasErrorOccurred())
101 return EXIT_FAILURE;
103 if (!Opts.DriverOpts.DylibToVerify.empty()) {
104 TargetList Targets;
105 llvm::for_each(Opts.DriverOpts.Targets,
106 [&](const auto &T) { Targets.push_back(T.first); });
107 if (!Ctx.Verifier->verifyBinaryAttrs(Targets, Ctx.BA, Ctx.Reexports,
108 Opts.LinkerOpts.AllowableClients,
109 Opts.LinkerOpts.RPaths, Ctx.FT))
110 return EXIT_FAILURE;
113 // Set up compilation.
114 std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
115 CI->setFileManager(FM.get());
116 CI->createDiagnostics(FM->getVirtualFileSystem());
117 if (!CI->hasDiagnostics())
118 return EXIT_FAILURE;
120 // Execute, verify and gather AST results.
121 // An invocation is ran for each unique target triple and for each header
122 // access level.
123 Records FrontendRecords;
124 for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
125 Ctx.Verifier->setTarget(Targ);
126 Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
127 for (const HeaderType Type :
128 {HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
129 std::vector<std::string> ArgStrings = Opts.getClangFrontendArgs();
130 Opts.addConditionalCC1Args(ArgStrings, Trip, Type);
131 Ctx.Type = Type;
132 StringRef HeaderLabel = getName(Ctx.Type);
133 if (!runFrontend(ProgName, HeaderLabel, Opts.DriverOpts.Verbose, Ctx,
134 InMemoryFileSystem.get(), ArgStrings))
135 return EXIT_FAILURE;
137 // Run extra passes for unique compiler arguments.
138 for (const auto &[Label, ExtraArgs] : Opts.FEOpts.UniqueArgs) {
139 std::vector<std::string> FinalArguments = ArgStrings;
140 llvm::append_range(FinalArguments, ExtraArgs);
141 if (!runFrontend(ProgName, Label + " " + HeaderLabel,
142 Opts.DriverOpts.Verbose, Ctx, InMemoryFileSystem.get(),
143 FinalArguments))
144 return EXIT_FAILURE;
147 FrontendRecords.emplace_back(std::move(Ctx.Slice));
150 if (Ctx.Verifier->verifyRemainingSymbols() == DylibVerifier::Result::Invalid)
151 return EXIT_FAILURE;
153 // After symbols have been collected, prepare to write output.
154 auto Out = CI->createOutputFile(Ctx.OutputLoc, /*Binary=*/false,
155 /*RemoveFileOnSignal=*/false,
156 /*UseTemporary=*/false,
157 /*CreateMissingDirectories=*/false);
158 if (!Out)
159 return EXIT_FAILURE;
161 // Assign attributes for serialization.
162 InterfaceFile IF(Ctx.Verifier->takeExports());
163 // Assign attributes that are the same per slice first.
164 for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
165 IF.addTarget(TargetInfo.first);
166 IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
168 // Then assign potentially different attributes per slice after.
169 auto assignLibAttrs =
170 [&IF](
171 const auto &Attrs,
172 std::function<void(InterfaceFile *, StringRef, const Target &)> Add) {
173 for (const auto &Lib : Attrs)
174 for (const auto &T : IF.targets(Lib.getValue()))
175 Add(&IF, Lib.getKey(), T);
178 assignLibAttrs(Opts.LinkerOpts.AllowableClients,
179 &InterfaceFile::addAllowableClient);
180 assignLibAttrs(Opts.LinkerOpts.RPaths, &InterfaceFile::addRPath);
181 assignLibAttrs(Ctx.Reexports, &InterfaceFile::addReexportedLibrary);
183 // Write output file and perform CI cleanup.
184 if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
185 Diag->Report(diag::err_cannot_write_file)
186 << Ctx.OutputLoc << std::move(Err);
187 CI->clearOutputFiles(/*EraseFiles=*/true);
188 return EXIT_FAILURE;
191 CI->clearOutputFiles(/*EraseFiles=*/false);
192 return EXIT_SUCCESS;
195 int clang_installapi_main(int argc, char **argv,
196 const llvm::ToolContext &ToolContext) {
197 // Standard set up, so program fails gracefully.
198 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
199 llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
200 llvm::llvm_shutdown_obj Shutdown;
202 if (llvm::sys::Process::FixupStandardFileDescriptors())
203 return EXIT_FAILURE;
205 const char *ProgName =
206 ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;
207 return run(llvm::ArrayRef(argv, argc), ProgName);