1//===- SSAFLinker.cpp - SSAF Linker ---------------------------------------===//
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 file implements the SSAF entity linker tool. Its default behavior is to
10// link N inputs (TU summaries, static libraries, and multi-arch static
11// libraries) into one LU summary via the EntityLinker framework. It also
12// provides the `static-library` subcommand for bundling TU summaries into a
13// StaticLibrary, and the `multi-arch` subcommand for bundling StaticLibrary
14// and SharedLibrary members (or existing multi-arch bundles) into
15// MultiArchStaticLibrary or MultiArchSharedLibrary.
16//
17//===----------------------------------------------------------------------===//
18
19#include "LinkCLI.h"
20#include "MultiArchCreateCLI.h"
21#include "StaticLibraryCreateCLI.h"
22
23#include "clang/ScalableStaticAnalysis/SSAFForceLinker.h" // IWYU pragma: keep
24#include "clang/ScalableStaticAnalysis/Tool/Utils.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/InitLLVM.h"
27#include "llvm/Support/Timer.h"
28#include "llvm/Support/raw_ostream.h"
29#include <string>
30
31using namespace llvm;
32using namespace clang::ssaf;
33
34namespace {
35
36//===----------------------------------------------------------------------===//
37// Command-Line Options
38//===----------------------------------------------------------------------===//
39
40cl::OptionCategory SsafLinkerCategory("clang-ssaf-linker options");
41
42// The `static-library` subcommand groups all StaticLibrary operations.
43cl::SubCommand StaticLibraryCmd("static-library",
44 "Operations on StaticLibraries");
45
46// The `multi-arch` subcommand groups all multi-architecture operations.
47cl::SubCommand MultiArchCmd("multi-arch",
48 "Operations on multi-architecture StaticLibrary "
49 "and SharedLibrary artifacts");
50
51// Top-level (default) `link` action positionals.
52cl::list<std::string> InputPaths(cl::Positional, cl::desc("<input files>"),
53 cl::OneOrMore, cl::cat(SsafLinkerCategory));
54
55cl::opt<std::string> OutputPath("o", cl::desc("Output file path"),
56 cl::value_desc("path"), cl::Required,
57 cl::cat(SsafLinkerCategory));
58
59cl::opt<std::string> TargetTriple(
60 "target-triple",
61 cl::desc(
62 "Target triple of the link unit (defaults to the first input's; "
63 "required when the first input is a multi-arch static library with "
64 "several members)"),
65 cl::value_desc("triple"), cl::cat(SsafLinkerCategory));
66
67// --verbose and --time apply to every subcommand.
68cl::opt<bool> Verbose("verbose", cl::desc("Enable verbose output"),
69 cl::init(Val: false), cl::cat(SsafLinkerCategory),
70 cl::sub(cl::SubCommand::getTopLevel()),
71 cl::sub(StaticLibraryCmd), cl::sub(MultiArchCmd));
72
73cl::opt<bool> Time("time", cl::desc("Enable timing"), cl::init(Val: false),
74 cl::cat(SsafLinkerCategory),
75 cl::sub(cl::SubCommand::getTopLevel()),
76 cl::sub(StaticLibraryCmd), cl::sub(MultiArchCmd));
77
78// The `static-library` subcommand's verb positional. Declared BEFORE
79// StaticLibraryInputs so cl-lib binds argv[0] under the subcommand to the
80// verb rather than to the greedy input list.
81cl::opt<std::string> StaticLibraryVerb(cl::Positional, cl::Required,
82 cl::sub(StaticLibraryCmd),
83 cl::desc("<verb>"),
84 cl::cat(SsafLinkerCategory));
85
86// The `static-library` subcommand's action-specific positional input
87// list. Currently consumed by `static-library create`; if future verbs
88// need different input shapes they'll declare their own positionals.
89cl::list<std::string> StaticLibraryInputs(cl::Positional,
90 cl::sub(StaticLibraryCmd),
91 cl::desc("<TU summary files>"),
92 cl::cat(SsafLinkerCategory));
93
94cl::opt<std::string> StaticLibraryOutput("o", cl::Required,
95 cl::sub(StaticLibraryCmd),
96 cl::desc("Output file path"),
97 cl::value_desc("path"),
98 cl::cat(SsafLinkerCategory));
99
100cl::opt<std::string> StaticLibraryNamespace(
101 "namespace", cl::sub(StaticLibraryCmd),
102 cl::desc("Namespace name for the StaticLibrary (defaults to output "
103 "file stem)"),
104 cl::value_desc("name"), cl::cat(SsafLinkerCategory));
105
106cl::opt<std::string> StaticLibraryTriple(
107 "target-triple", cl::sub(StaticLibraryCmd),
108 cl::desc("Target triple (defaults to inputs' triple; must match all "
109 "inputs when set)"),
110 cl::value_desc("triple"), cl::cat(SsafLinkerCategory));
111
112// The `multi-arch` subcommand's verb positional. Declared BEFORE
113// MultiArchInputs so cl-lib binds argv[0] under the subcommand to the verb
114// rather than to the greedy input list.
115cl::opt<std::string> MultiArchVerb(cl::Positional, cl::Required,
116 cl::sub(MultiArchCmd), cl::desc("<verb>"),
117 cl::cat(SsafLinkerCategory));
118
119// The `multi-arch` subcommand's action-specific positional input list.
120// Currently consumed by `multi-arch create`.
121cl::list<std::string>
122 MultiArchInputs(cl::Positional, cl::sub(MultiArchCmd),
123 cl::desc("<static-library or shared-library files>"),
124 cl::cat(SsafLinkerCategory));
125
126cl::opt<std::string> MultiArchOutput("o", cl::Required, cl::sub(MultiArchCmd),
127 cl::desc("Output file path"),
128 cl::value_desc("path"),
129 cl::cat(SsafLinkerCategory));
130
131//===----------------------------------------------------------------------===//
132// StaticLibrary Verbs
133//===----------------------------------------------------------------------===//
134
135// Verb strings for the `static-library` subcommand. Kept in sync with
136// UnknownStaticLibraryVerb below.
137constexpr const char *StaticLibraryCreateVerb = "create";
138
139//===----------------------------------------------------------------------===//
140// MultiArch Verbs
141//===----------------------------------------------------------------------===//
142
143// Verb strings for the `multi-arch` subcommand. Kept in sync with
144// UnknownMultiArchVerb below.
145constexpr const char *MultiArchCreateVerb = "create";
146
147//===----------------------------------------------------------------------===//
148// Error Messages
149//===----------------------------------------------------------------------===//
150
151namespace LocalErrorMessages {
152
153constexpr const char *UnknownStaticLibraryVerb =
154 "unknown static-library verb '{0}': expected 'create'";
155
156constexpr const char *UnknownMultiArchVerb =
157 "unknown multi-arch verb '{0}': expected 'create'";
158
159} // namespace LocalErrorMessages
160
161//===----------------------------------------------------------------------===//
162// default (no subcommand) link action
163//===----------------------------------------------------------------------===//
164
165void runLink(llvm::TimerGroup &TG) {
166 LinkCLI LC;
167 LC.run(TG, InputPaths, OutputPath, TargetTriple, Verbose, Time);
168}
169
170//===----------------------------------------------------------------------===//
171// static-library subcommand dispatch
172//===----------------------------------------------------------------------===//
173
174void runStaticLibrary(llvm::TimerGroup &TG) {
175 if (StaticLibraryVerb == StaticLibraryCreateVerb) {
176 StaticLibraryCreateCLI::Config Cfg;
177 Cfg.InputPaths = StaticLibraryInputs;
178 Cfg.OutputPath = StaticLibraryOutput;
179 Cfg.Namespace = StaticLibraryNamespace;
180 Cfg.TargetTriple = StaticLibraryTriple;
181 Cfg.Verbose = Verbose;
182 Cfg.Time = Time;
183
184 StaticLibraryCreateCLI SLC;
185 SLC.run(TG, Cfg);
186 return;
187 }
188 fail(Fmt: LocalErrorMessages::UnknownStaticLibraryVerb,
189 Args&: StaticLibraryVerb.getValue());
190}
191
192//===----------------------------------------------------------------------===//
193// multi-arch subcommand dispatch
194//===----------------------------------------------------------------------===//
195
196void runMultiArch(llvm::TimerGroup &TG) {
197 if (MultiArchVerb == MultiArchCreateVerb) {
198 MultiArchCreateCLI MAC;
199 MAC.run(TG, InputPaths: MultiArchInputs, OutputPath: MultiArchOutput, Verbose, Time);
200 return;
201 }
202 fail(Fmt: LocalErrorMessages::UnknownMultiArchVerb, Args&: MultiArchVerb.getValue());
203}
204
205} // namespace
206
207//===----------------------------------------------------------------------===//
208// Driver
209//===----------------------------------------------------------------------===//
210
211int main(int argc, const char **argv) {
212 llvm::StringRef ToolHeading = "SSAF Linker";
213
214 InitLLVM X(argc, argv);
215 initTool(argc, argv, Version: "0.1", Category&: SsafLinkerCategory, ToolHeading);
216
217 llvm::TimerGroup Timers(getToolName(), ToolHeading);
218
219 if (StaticLibraryCmd) {
220 runStaticLibrary(TG&: Timers);
221 } else if (MultiArchCmd) {
222 runMultiArch(TG&: Timers);
223 } else {
224 // Default (no subcommand): run the linker pipeline.
225 runLink(TG&: Timers);
226 }
227
228 return 0;
229}
230