1//===-- Options.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#include "Options.h"
10#include "clang/Basic/DiagnosticIDs.h"
11#include "clang/Driver/Driver.h"
12#include "clang/InstallAPI/DirectoryScanner.h"
13#include "clang/InstallAPI/FileList.h"
14#include "clang/InstallAPI/HeaderFile.h"
15#include "clang/InstallAPI/InstallAPIDiagnostic.h"
16#include "llvm/BinaryFormat/Magic.h"
17#include "llvm/Support/JSON.h"
18#include "llvm/Support/Program.h"
19#include "llvm/TargetParser/Host.h"
20#include "llvm/TextAPI/DylibReader.h"
21#include "llvm/TextAPI/TextAPIError.h"
22#include "llvm/TextAPI/TextAPIReader.h"
23#include "llvm/TextAPI/TextAPIWriter.h"
24
25using namespace llvm;
26using namespace llvm::opt;
27using namespace llvm::MachO;
28
29namespace drv = clang::driver::options;
30
31namespace clang {
32namespace installapi {
33
34/// Create prefix string literals used in InstallAPIOpts.td.
35#define PREFIX(NAME, VALUE) \
36 static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
37 static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
38 NAME##_init, std::size(NAME##_init) - 1);
39#include "InstallAPIOpts.inc"
40#undef PREFIX
41
42static constexpr const llvm::StringLiteral PrefixTable_init[] =
43#define PREFIX_UNION(VALUES) VALUES
44#include "InstallAPIOpts.inc"
45#undef PREFIX_UNION
46 ;
47static constexpr const ArrayRef<StringLiteral>
48 PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
49
50/// Create table mapping all options defined in InstallAPIOpts.td.
51static constexpr OptTable::Info InfoTable[] = {
52#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
53 VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
54 VALUES) \
55 {PREFIX, \
56 NAME, \
57 HELPTEXT, \
58 HELPTEXTSFORVARIANTS, \
59 METAVAR, \
60 OPT_##ID, \
61 Option::KIND##Class, \
62 PARAM, \
63 FLAGS, \
64 VISIBILITY, \
65 OPT_##GROUP, \
66 OPT_##ALIAS, \
67 ALIASARGS, \
68 VALUES},
69#include "InstallAPIOpts.inc"
70#undef OPTION
71};
72
73namespace {
74
75/// \brief Create OptTable class for parsing actual command line arguments.
76class DriverOptTable : public opt::PrecomputedOptTable {
77public:
78 DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
79};
80
81} // end anonymous namespace.
82
83static llvm::opt::OptTable *createDriverOptTable() {
84 return new DriverOptTable();
85}
86
87/// Parse JSON input into argument list.
88///
89/* Expected input format.
90 * { "label" : ["-ClangArg1", "-ClangArg2"] }
91 */
92///
93/// Input is interpreted as "-Xlabel ClangArg1 -XLabel ClangArg2".
94static Expected<llvm::opt::InputArgList>
95getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
96 std::vector<std::string> &Storage) {
97 using namespace json;
98 Expected<Value> ValOrErr = json::parse(JSON: Input);
99 if (!ValOrErr)
100 return ValOrErr.takeError();
101
102 const Object *Root = ValOrErr->getAsObject();
103 if (!Root)
104 return llvm::opt::InputArgList();
105
106 for (const auto &KV : *Root) {
107 const Array *ArgList = KV.getSecond().getAsArray();
108 std::string Label = "-X" + KV.getFirst().str();
109 if (!ArgList)
110 return make_error<TextAPIError>(Args: TextAPIErrorCode::InvalidInputFormat);
111 for (auto Arg : *ArgList) {
112 std::optional<StringRef> ArgStr = Arg.getAsString();
113 if (!ArgStr)
114 return make_error<TextAPIError>(Args: TextAPIErrorCode::InvalidInputFormat);
115 Storage.emplace_back(args&: Label);
116 Storage.emplace_back(args&: *ArgStr);
117 }
118 }
119
120 std::vector<const char *> CArgs(Storage.size());
121 llvm::for_each(Range&: Storage,
122 F: [&CArgs](StringRef Str) { CArgs.emplace_back(args: Str.data()); });
123
124 unsigned MissingArgIndex, MissingArgCount;
125 return Table->ParseArgs(Args: CArgs, MissingArgIndex, MissingArgCount);
126}
127
128bool Options::processDriverOptions(InputArgList &Args) {
129 // Handle inputs.
130 for (const StringRef Path : Args.getAllArgValues(Id: drv::OPT_INPUT)) {
131 // Assume any input that is not a directory is a filelist.
132 // InstallAPI does not accept multiple directories, so retain the last one.
133 if (FM->getOptionalDirectoryRef(DirName: Path))
134 DriverOpts.InputDirectory = Path.str();
135 else
136 DriverOpts.FileLists.emplace_back(args: Path.str());
137 }
138
139 // Handle output.
140 SmallString<PATH_MAX> OutputPath;
141 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_o)) {
142 OutputPath = Arg->getValue();
143 if (OutputPath != "-")
144 FM->makeAbsolutePath(Path&: OutputPath);
145 DriverOpts.OutputPath = std::string(OutputPath);
146 }
147 if (DriverOpts.OutputPath.empty()) {
148 Diags->Report(DiagID: diag::err_no_output_file);
149 return false;
150 }
151
152 // Do basic error checking first for mixing -target and -arch options.
153 auto *ArgArch = Args.getLastArgNoClaim(Ids: drv::OPT_arch);
154 auto *ArgTarget = Args.getLastArgNoClaim(Ids: drv::OPT_target);
155 auto *ArgTargetVariant =
156 Args.getLastArgNoClaim(Ids: drv::OPT_darwin_target_variant);
157 if (ArgArch && (ArgTarget || ArgTargetVariant)) {
158 Diags->Report(DiagID: clang::diag::err_drv_argument_not_allowed_with)
159 << ArgArch->getAsString(Args)
160 << (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
161 return false;
162 }
163
164 auto *ArgMinTargetOS = Args.getLastArgNoClaim(Ids: drv::OPT_mtargetos_EQ);
165 if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
166 Diags->Report(DiagID: clang::diag::err_drv_cannot_mix_options)
167 << ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
168 return false;
169 }
170
171 // Capture target triples first.
172 if (ArgTarget) {
173 for (const Arg *A : Args.filtered(Ids: drv::OPT_target)) {
174 A->claim();
175 llvm::Triple TargetTriple(A->getValue());
176 Target TAPITarget = Target(TargetTriple);
177 if ((TAPITarget.Arch == AK_unknown) ||
178 (TAPITarget.Platform == PLATFORM_UNKNOWN)) {
179 Diags->Report(DiagID: clang::diag::err_drv_unsupported_opt_for_target)
180 << "installapi" << TargetTriple.str();
181 return false;
182 }
183 DriverOpts.Targets[TAPITarget] = TargetTriple;
184 }
185 }
186
187 // Capture target variants.
188 DriverOpts.Zippered = ArgTargetVariant != nullptr;
189 for (Arg *A : Args.filtered(Ids: drv::OPT_darwin_target_variant)) {
190 A->claim();
191 Triple Variant(A->getValue());
192 if (Variant.getVendor() != Triple::Apple) {
193 Diags->Report(DiagID: diag::err_unsupported_vendor)
194 << Variant.getVendorName() << A->getAsString(Args);
195 return false;
196 }
197
198 switch (Variant.getOS()) {
199 default:
200 Diags->Report(DiagID: diag::err_unsupported_os)
201 << Variant.getOSName() << A->getAsString(Args);
202 return false;
203 case Triple::MacOSX:
204 case Triple::IOS:
205 break;
206 }
207
208 switch (Variant.getEnvironment()) {
209 default:
210 Diags->Report(DiagID: diag::err_unsupported_environment)
211 << Variant.getEnvironmentName() << A->getAsString(Args);
212 return false;
213 case Triple::UnknownEnvironment:
214 case Triple::MacABI:
215 break;
216 }
217
218 Target TAPIVariant(Variant);
219 // See if there is a matching --target option for this --target-variant
220 // option.
221 auto It = find_if(Range&: DriverOpts.Targets, P: [&](const auto &T) {
222 return (T.first.Arch == TAPIVariant.Arch) &&
223 (T.first.Platform != PlatformType::PLATFORM_UNKNOWN);
224 });
225
226 if (It == DriverOpts.Targets.end()) {
227 Diags->Report(DiagID: diag::err_no_matching_target) << Variant.str();
228 return false;
229 }
230
231 DriverOpts.Targets[TAPIVariant] = Variant;
232 }
233
234 DriverOpts.Verbose = Args.hasArgNoClaim(Ids: drv::OPT_v);
235
236 return true;
237}
238
239bool Options::processInstallAPIXOptions(InputArgList &Args) {
240 for (arg_iterator It = Args.begin(), End = Args.end(); It != End; ++It) {
241 Arg *A = *It;
242 if (A->getOption().matches(ID: OPT_Xarch__)) {
243 if (!processXarchOption(Args, Curr: It))
244 return false;
245 continue;
246 } else if (A->getOption().matches(ID: OPT_Xplatform__)) {
247 if (!processXplatformOption(Args, Curr: It))
248 return false;
249 continue;
250 } else if (A->getOption().matches(ID: OPT_Xproject)) {
251 if (!processXprojectOption(Args, Curr: It))
252 return false;
253 continue;
254 } else if (!A->getOption().matches(ID: OPT_X__))
255 continue;
256
257 // Handle any user defined labels.
258 const StringRef Label = A->getValue(N: 0);
259
260 // Ban "public" and "private" labels.
261 if ((Label.lower() == "public") || (Label.lower() == "private")) {
262 Diags->Report(DiagID: diag::err_invalid_label) << Label;
263 return false;
264 }
265
266 auto NextIt = std::next(x: It);
267 if (NextIt == End) {
268 Diags->Report(DiagID: clang::diag::err_drv_missing_argument)
269 << A->getAsString(Args) << 1;
270 return false;
271 }
272 Arg *NextA = *NextIt;
273 switch ((ID)NextA->getOption().getID()) {
274 case OPT_D:
275 case OPT_U:
276 break;
277 default:
278 Diags->Report(DiagID: clang::diag::err_drv_argument_not_allowed_with)
279 << A->getAsString(Args) << NextA->getAsString(Args);
280 return false;
281 }
282 const StringRef ASpelling = NextA->getSpelling();
283 const auto &AValues = NextA->getValues();
284 if (AValues.empty())
285 FEOpts.UniqueArgs[Label].emplace_back(args: ASpelling.str());
286 else
287 for (const StringRef Val : AValues)
288 FEOpts.UniqueArgs[Label].emplace_back(args: (ASpelling + Val).str());
289
290 A->claim();
291 NextA->claim();
292 }
293
294 return true;
295}
296
297bool Options::processXplatformOption(InputArgList &Args, arg_iterator Curr) {
298 Arg *A = *Curr;
299
300 PlatformType Platform = getPlatformFromName(Name: A->getValue(N: 0));
301 if (Platform == PLATFORM_UNKNOWN) {
302 Diags->Report(DiagID: diag::err_unsupported_os)
303 << getPlatformName(Platform) << A->getAsString(Args);
304 return false;
305 }
306 auto NextIt = std::next(x: Curr);
307 if (NextIt == Args.end()) {
308 Diags->Report(DiagID: diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
309 return false;
310 }
311
312 Arg *NextA = *NextIt;
313 switch ((ID)NextA->getOption().getID()) {
314 case OPT_iframework:
315 FEOpts.SystemFwkPaths.emplace_back(args: NextA->getValue(), args&: Platform);
316 break;
317 default:
318 Diags->Report(DiagID: diag::err_drv_invalid_argument_to_option)
319 << A->getAsString(Args) << NextA->getAsString(Args);
320 return false;
321 }
322
323 A->claim();
324 NextA->claim();
325
326 return true;
327}
328
329bool Options::processXprojectOption(InputArgList &Args, arg_iterator Curr) {
330 Arg *A = *Curr;
331 auto NextIt = std::next(x: Curr);
332 if (NextIt == Args.end()) {
333 Diags->Report(DiagID: diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
334 return false;
335 }
336
337 Arg *NextA = *NextIt;
338 switch ((ID)NextA->getOption().getID()) {
339 case OPT_fobjc_arc:
340 case OPT_fmodules:
341 case OPT_fmodules_cache_path:
342 case OPT_include_:
343 case OPT_fvisibility_EQ:
344 break;
345 default:
346 Diags->Report(DiagID: diag::err_drv_argument_not_allowed_with)
347 << A->getAsString(Args) << NextA->getAsString(Args);
348 return false;
349 }
350
351 std::string ArgString = NextA->getSpelling().str();
352 for (const StringRef Val : NextA->getValues())
353 ArgString += Val.str();
354
355 ProjectLevelArgs.push_back(x: ArgString);
356 A->claim();
357 NextA->claim();
358
359 return true;
360}
361
362bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
363 Arg *CurrArg = *Curr;
364 Architecture Arch = getArchitectureFromName(Name: CurrArg->getValue(N: 0));
365 if (Arch == AK_unknown) {
366 Diags->Report(DiagID: diag::err_drv_invalid_arch_name)
367 << CurrArg->getAsString(Args);
368 return false;
369 }
370
371 auto NextIt = std::next(x: Curr);
372 if (NextIt == Args.end()) {
373 Diags->Report(DiagID: diag::err_drv_missing_argument)
374 << CurrArg->getAsString(Args) << 1;
375 return false;
376 }
377
378 // InstallAPI has a limited understanding of supported Xarch options.
379 // Currently this is restricted to linker inputs.
380 const Arg *NextArg = *NextIt;
381 switch (NextArg->getOption().getID()) {
382 case OPT_allowable_client:
383 case OPT_reexport_l:
384 case OPT_reexport_framework:
385 case OPT_reexport_library:
386 case OPT_rpath:
387 break;
388 default:
389 Diags->Report(DiagID: diag::err_drv_invalid_argument_to_option)
390 << NextArg->getAsString(Args) << CurrArg->getAsString(Args);
391 return false;
392 }
393
394 ArgToArchMap[NextArg] = Arch;
395 CurrArg->claim();
396
397 return true;
398}
399
400bool Options::processOptionList(InputArgList &Args,
401 llvm::opt::OptTable *Table) {
402 Arg *A = Args.getLastArg(Ids: OPT_option_list);
403 if (!A)
404 return true;
405
406 const StringRef Path = A->getValue(N: 0);
407 auto InputOrErr = FM->getBufferForFile(Filename: Path);
408 if (auto Err = InputOrErr.getError()) {
409 Diags->Report(DiagID: diag::err_cannot_open_file) << Path << Err.message();
410 return false;
411 }
412 // Backing storage referenced for argument processing.
413 std::vector<std::string> Storage;
414 auto ArgsOrErr =
415 getArgListFromJSON(Input: (*InputOrErr)->getBuffer(), Table, Storage);
416
417 if (auto Err = ArgsOrErr.takeError()) {
418 Diags->Report(DiagID: diag::err_cannot_read_input_list)
419 << "option" << Path << toString(E: std::move(Err));
420 return false;
421 }
422 return processInstallAPIXOptions(Args&: *ArgsOrErr);
423}
424
425bool Options::processLinkerOptions(InputArgList &Args) {
426 // Handle required arguments.
427 if (const Arg *A = Args.getLastArg(Ids: drv::OPT_install__name))
428 LinkerOpts.InstallName = A->getValue();
429 if (LinkerOpts.InstallName.empty()) {
430 Diags->Report(DiagID: diag::err_no_install_name);
431 return false;
432 }
433
434 // Defaulted or optional arguments.
435 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_current__version))
436 LinkerOpts.CurrentVersion.parse64(Str: Arg->getValue());
437
438 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_compatibility__version))
439 LinkerOpts.CompatVersion.parse64(Str: Arg->getValue());
440
441 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_compatibility__version))
442 LinkerOpts.CompatVersion.parse64(Str: Arg->getValue());
443
444 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_umbrella))
445 LinkerOpts.ParentUmbrella = Arg->getValue();
446
447 LinkerOpts.IsDylib = Args.hasArg(Ids: drv::OPT_dynamiclib);
448
449 for (auto *Arg : Args.filtered(Ids: drv::OPT_alias_list)) {
450 LinkerOpts.AliasLists.emplace_back(args: Arg->getValue());
451 Arg->claim();
452 }
453
454 LinkerOpts.AppExtensionSafe = Args.hasFlag(
455 Pos: drv::OPT_fapplication_extension, Neg: drv::OPT_fno_application_extension,
456 /*Default=*/LinkerOpts.AppExtensionSafe);
457
458 if (::getenv(name: "LD_NO_ENCRYPT") != nullptr)
459 LinkerOpts.AppExtensionSafe = true;
460
461 if (::getenv(name: "LD_APPLICATION_EXTENSION_SAFE") != nullptr)
462 LinkerOpts.AppExtensionSafe = true;
463
464 // Capture library paths.
465 PathSeq LibraryPaths;
466 for (const Arg *A : Args.filtered(Ids: drv::OPT_L)) {
467 LibraryPaths.emplace_back(args: A->getValue());
468 A->claim();
469 }
470
471 if (!LibraryPaths.empty())
472 LinkerOpts.LibPaths = std::move(LibraryPaths);
473
474 return true;
475}
476
477// NOTE: Do not claim any arguments, as they will be passed along for CC1
478// invocations.
479bool Options::processFrontendOptions(InputArgList &Args) {
480 // Capture language mode.
481 if (auto *A = Args.getLastArgNoClaim(Ids: drv::OPT_x)) {
482 FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
483 .Case(S: "c", Value: clang::Language::C)
484 .Case(S: "c++", Value: clang::Language::CXX)
485 .Case(S: "objective-c", Value: clang::Language::ObjC)
486 .Case(S: "objective-c++", Value: clang::Language::ObjCXX)
487 .Default(Value: clang::Language::Unknown);
488
489 if (FEOpts.LangMode == clang::Language::Unknown) {
490 Diags->Report(DiagID: clang::diag::err_drv_invalid_value)
491 << A->getAsString(Args) << A->getValue();
492 return false;
493 }
494 }
495 for (auto *A : Args.filtered(Ids: drv::OPT_ObjC, Ids: drv::OPT_ObjCXX)) {
496 if (A->getOption().matches(ID: drv::OPT_ObjC))
497 FEOpts.LangMode = clang::Language::ObjC;
498 else
499 FEOpts.LangMode = clang::Language::ObjCXX;
500 }
501
502 // Capture Sysroot.
503 if (const Arg *A = Args.getLastArgNoClaim(Ids: drv::OPT_isysroot)) {
504 SmallString<PATH_MAX> Path(A->getValue());
505 FM->makeAbsolutePath(Path);
506 if (!FM->getOptionalDirectoryRef(DirName: Path)) {
507 Diags->Report(DiagID: diag::err_missing_sysroot) << Path;
508 return false;
509 }
510 FEOpts.ISysroot = std::string(Path);
511 } else if (FEOpts.ISysroot.empty()) {
512 // Mirror CLANG and obtain the isysroot from the SDKROOT environment
513 // variable, if it wasn't defined by the command line.
514 if (auto *Env = ::getenv(name: "SDKROOT")) {
515 if (StringRef(Env) != "/" && llvm::sys::path::is_absolute(path: Env) &&
516 FM->getOptionalFileRef(Filename: Env))
517 FEOpts.ISysroot = Env;
518 }
519 }
520
521 // Capture system frameworks for all platforms.
522 for (const Arg *A : Args.filtered(Ids: drv::OPT_iframework))
523 FEOpts.SystemFwkPaths.emplace_back(args: A->getValue(),
524 args: std::optional<PlatformType>{});
525
526 // Capture framework paths.
527 PathSeq FrameworkPaths;
528 for (const Arg *A : Args.filtered(Ids: drv::OPT_F))
529 FrameworkPaths.emplace_back(args: A->getValue());
530
531 if (!FrameworkPaths.empty())
532 FEOpts.FwkPaths = std::move(FrameworkPaths);
533
534 // Add default framework/library paths.
535 PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
536 PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
537 "/System/Library/Frameworks"};
538
539 for (const StringRef LibPath : DefaultLibraryPaths) {
540 SmallString<PATH_MAX> Path(FEOpts.ISysroot);
541 sys::path::append(path&: Path, a: LibPath);
542 LinkerOpts.LibPaths.emplace_back(args: Path.str());
543 }
544 for (const StringRef FwkPath : DefaultFrameworkPaths) {
545 SmallString<PATH_MAX> Path(FEOpts.ISysroot);
546 sys::path::append(path&: Path, a: FwkPath);
547 FEOpts.SystemFwkPaths.emplace_back(args: Path.str(),
548 args: std::optional<PlatformType>{});
549 }
550
551 return true;
552}
553
554bool Options::addFilePaths(InputArgList &Args, PathSeq &Headers,
555 OptSpecifier ID) {
556 for (const StringRef Path : Args.getAllArgValues(Id: ID)) {
557 if ((bool)FM->getDirectory(DirName: Path, /*CacheFailure=*/false)) {
558 auto InputHeadersOrErr = enumerateFiles(FM&: *FM, Directory: Path);
559 if (!InputHeadersOrErr) {
560 Diags->Report(DiagID: diag::err_cannot_open_file)
561 << Path << toString(E: InputHeadersOrErr.takeError());
562 return false;
563 }
564 // Sort headers to ensure deterministic behavior.
565 sort(C&: *InputHeadersOrErr);
566 for (StringRef H : *InputHeadersOrErr)
567 Headers.emplace_back(args: std::move(H));
568 } else
569 Headers.emplace_back(args: Path);
570 }
571 return true;
572}
573
574std::vector<const char *>
575Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
576 std::unique_ptr<llvm::opt::OptTable> Table;
577 Table.reset(p: createDriverOptTable());
578
579 unsigned MissingArgIndex, MissingArgCount;
580 auto ParsedArgs = Table->ParseArgs(Args: Args.slice(N: 1), MissingArgIndex,
581 MissingArgCount, FlagsToInclude: Visibility());
582
583 // Capture InstallAPI only driver options.
584 if (!processInstallAPIXOptions(Args&: ParsedArgs))
585 return {};
586
587 if (!processOptionList(Args&: ParsedArgs, Table: Table.get()))
588 return {};
589
590 DriverOpts.Demangle = ParsedArgs.hasArg(Ids: OPT_demangle);
591
592 if (auto *A = ParsedArgs.getLastArg(Ids: OPT_filetype)) {
593 DriverOpts.OutFT = TextAPIWriter::parseFileType(FT: A->getValue());
594 if (DriverOpts.OutFT == FileType::Invalid) {
595 Diags->Report(DiagID: clang::diag::err_drv_invalid_value)
596 << A->getAsString(Args: ParsedArgs) << A->getValue();
597 return {};
598 }
599 }
600
601 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_verify_mode_EQ)) {
602 DriverOpts.VerifyMode =
603 StringSwitch<VerificationMode>(A->getValue())
604 .Case(S: "ErrorsOnly", Value: VerificationMode::ErrorsOnly)
605 .Case(S: "ErrorsAndWarnings", Value: VerificationMode::ErrorsAndWarnings)
606 .Case(S: "Pedantic", Value: VerificationMode::Pedantic)
607 .Default(Value: VerificationMode::Invalid);
608
609 if (DriverOpts.VerifyMode == VerificationMode::Invalid) {
610 Diags->Report(DiagID: clang::diag::err_drv_invalid_value)
611 << A->getAsString(Args: ParsedArgs) << A->getValue();
612 return {};
613 }
614 }
615
616 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_verify_against))
617 DriverOpts.DylibToVerify = A->getValue();
618
619 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_dsym))
620 DriverOpts.DSYMPath = A->getValue();
621
622 DriverOpts.TraceLibraryLocation = ParsedArgs.hasArg(Ids: OPT_t);
623
624 // Linker options not handled by clang driver.
625 LinkerOpts.OSLibNotForSharedCache =
626 ParsedArgs.hasArg(Ids: OPT_not_for_dyld_shared_cache);
627
628 for (const Arg *A : ParsedArgs.filtered(Ids: OPT_allowable_client)) {
629 LinkerOpts.AllowableClients[A->getValue()] =
630 ArgToArchMap.count(Val: A) ? ArgToArchMap[A] : ArchitectureSet();
631 A->claim();
632 }
633
634 for (const Arg *A : ParsedArgs.filtered(Ids: OPT_reexport_l)) {
635 LinkerOpts.ReexportedLibraries[A->getValue()] =
636 ArgToArchMap.count(Val: A) ? ArgToArchMap[A] : ArchitectureSet();
637 A->claim();
638 }
639
640 for (const Arg *A : ParsedArgs.filtered(Ids: OPT_reexport_library)) {
641 LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
642 ArgToArchMap.count(Val: A) ? ArgToArchMap[A] : ArchitectureSet();
643 A->claim();
644 }
645
646 for (const Arg *A : ParsedArgs.filtered(Ids: OPT_reexport_framework)) {
647 LinkerOpts.ReexportedFrameworks[A->getValue()] =
648 ArgToArchMap.count(Val: A) ? ArgToArchMap[A] : ArchitectureSet();
649 A->claim();
650 }
651
652 for (const Arg *A : ParsedArgs.filtered(Ids: OPT_rpath)) {
653 LinkerOpts.RPaths[A->getValue()] =
654 ArgToArchMap.count(Val: A) ? ArgToArchMap[A] : ArchitectureSet();
655 A->claim();
656 }
657
658 // Handle exclude & extra header directories or files.
659 auto handleAdditionalInputArgs = [&](PathSeq &Headers,
660 clang::installapi::ID OptID) {
661 if (ParsedArgs.hasArgNoClaim(Ids: OptID))
662 Headers.clear();
663 return addFilePaths(Args&: ParsedArgs, Headers, ID: OptID);
664 };
665
666 if (!handleAdditionalInputArgs(DriverOpts.ExtraPublicHeaders,
667 OPT_extra_public_header))
668 return {};
669
670 if (!handleAdditionalInputArgs(DriverOpts.ExtraPrivateHeaders,
671 OPT_extra_private_header))
672 return {};
673 if (!handleAdditionalInputArgs(DriverOpts.ExtraProjectHeaders,
674 OPT_extra_project_header))
675 return {};
676
677 if (!handleAdditionalInputArgs(DriverOpts.ExcludePublicHeaders,
678 OPT_exclude_public_header))
679 return {};
680 if (!handleAdditionalInputArgs(DriverOpts.ExcludePrivateHeaders,
681 OPT_exclude_private_header))
682 return {};
683 if (!handleAdditionalInputArgs(DriverOpts.ExcludeProjectHeaders,
684 OPT_exclude_project_header))
685 return {};
686
687 // Handle umbrella headers.
688 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_public_umbrella_header))
689 DriverOpts.PublicUmbrellaHeader = A->getValue();
690
691 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_private_umbrella_header))
692 DriverOpts.PrivateUmbrellaHeader = A->getValue();
693
694 if (const Arg *A = ParsedArgs.getLastArg(Ids: OPT_project_umbrella_header))
695 DriverOpts.ProjectUmbrellaHeader = A->getValue();
696
697 /// Any unclaimed arguments should be forwarded to the clang driver.
698 std::vector<const char *> ClangDriverArgs(ParsedArgs.size());
699 for (const Arg *A : ParsedArgs) {
700 if (A->isClaimed())
701 continue;
702 // Forward along unclaimed but overlapping arguments to the clang driver.
703 if (A->getOption().getID() > (unsigned)OPT_UNKNOWN) {
704 ClangDriverArgs.push_back(x: A->getSpelling().data());
705 } else
706 llvm::copy(Range: A->getValues(), Out: std::back_inserter(x&: ClangDriverArgs));
707 }
708 return ClangDriverArgs;
709}
710
711Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
712 ArrayRef<const char *> Args, const StringRef ProgName)
713 : Diags(&Diag), FM(FM) {
714
715 // First process InstallAPI specific options.
716 auto DriverArgs = processAndFilterOutInstallAPIOptions(Args);
717 if (Diags->hasErrorOccurred())
718 return;
719
720 // Set up driver to parse remaining input arguments.
721 clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
722 *Diags, "clang installapi tool");
723 auto TargetAndMode =
724 clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
725 Driver.setTargetAndMode(TargetAndMode);
726 bool HasError = false;
727 llvm::opt::InputArgList ArgList =
728 Driver.ParseArgStrings(Args: DriverArgs, /*UseDriverMode=*/true, ContainsError&: HasError);
729 if (HasError)
730 return;
731 Driver.setCheckInputsExist(false);
732
733 if (!processDriverOptions(Args&: ArgList))
734 return;
735
736 if (!processLinkerOptions(Args&: ArgList))
737 return;
738
739 if (!processFrontendOptions(Args&: ArgList))
740 return;
741
742 // After all InstallAPI necessary arguments have been collected. Go back and
743 // assign values that were unknown before the clang driver opt table was used.
744 ArchitectureSet AllArchs;
745 llvm::for_each(Range&: DriverOpts.Targets,
746 F: [&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
747 auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
748 for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
749 if (Entry.getValue().empty())
750 Entry.setValue(AllArchs);
751 };
752 assignDefaultLibAttrs(LinkerOpts.AllowableClients);
753 assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
754 assignDefaultLibAttrs(LinkerOpts.ReexportedLibraries);
755 assignDefaultLibAttrs(LinkerOpts.ReexportedLibraryPaths);
756 assignDefaultLibAttrs(LinkerOpts.RPaths);
757
758 /// Force cc1 options that should always be on.
759 FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
760
761 /// Any unclaimed arguments should be handled by invoking the clang frontend.
762 for (const Arg *A : ArgList) {
763 if (A->isClaimed())
764 continue;
765 FrontendArgs.emplace_back(args: A->getSpelling());
766 llvm::copy(Range: A->getValues(), Out: std::back_inserter(x&: FrontendArgs));
767 }
768}
769
770static Expected<std::unique_ptr<InterfaceFile>>
771getInterfaceFile(const StringRef Filename) {
772 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
773 MemoryBuffer::getFile(Filename);
774 if (auto Err = BufferOrErr.getError())
775 return errorCodeToError(EC: std::move(Err));
776
777 auto Buffer = std::move(*BufferOrErr);
778 std::unique_ptr<InterfaceFile> IF;
779 switch (identify_magic(magic: Buffer->getBuffer())) {
780 case file_magic::macho_dynamically_linked_shared_lib:
781 case file_magic::macho_dynamically_linked_shared_lib_stub:
782 case file_magic::macho_universal_binary:
783 return DylibReader::get(Buffer: Buffer->getMemBufferRef());
784 break;
785 case file_magic::tapi_file:
786 return TextAPIReader::get(InputBuffer: Buffer->getMemBufferRef());
787 default:
788 return make_error<TextAPIError>(Args: TextAPIErrorCode::InvalidInputFormat,
789 Args: "unsupported library file format");
790 }
791 llvm_unreachable("unexpected failure in getInterface");
792}
793
794std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
795 LibAttrs Reexports;
796 ReexportedInterfaces ReexportIFs;
797 auto AccumulateReexports = [&](StringRef Path, const ArchitectureSet &Archs) {
798 auto ReexportIFOrErr = getInterfaceFile(Filename: Path);
799 if (!ReexportIFOrErr)
800 return false;
801 std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
802 StringRef InstallName = Reexport->getInstallName();
803 assert(!InstallName.empty() && "Parse error for install name");
804 Reexports.insert(KV: {InstallName, Archs});
805 ReexportIFs.emplace_back(Args: std::move(*Reexport));
806 return true;
807 };
808
809 PlatformSet Platforms;
810 llvm::for_each(Range&: DriverOpts.Targets,
811 F: [&](const auto &T) { Platforms.insert(T.first.Platform); });
812 // Populate search paths by looking at user paths before system ones.
813 PathSeq FwkSearchPaths(FEOpts.FwkPaths.begin(), FEOpts.FwkPaths.end());
814 for (const PlatformType P : Platforms) {
815 PathSeq PlatformSearchPaths = getPathsForPlatform(Paths: FEOpts.SystemFwkPaths, Platform: P);
816 FwkSearchPaths.insert(position: FwkSearchPaths.end(), first: PlatformSearchPaths.begin(),
817 last: PlatformSearchPaths.end());
818 for (const StringMapEntry<ArchitectureSet> &Lib :
819 LinkerOpts.ReexportedFrameworks) {
820 std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
821 std::string Path = findLibrary(InstallName: Name, FM&: *FM, FrameworkSearchPaths: FwkSearchPaths, LibrarySearchPaths: {}, SearchPaths: {});
822 if (Path.empty()) {
823 Diags->Report(DiagID: diag::err_cannot_find_reexport) << false << Lib.getKey();
824 return {};
825 }
826 if (DriverOpts.TraceLibraryLocation)
827 errs() << Path << "\n";
828
829 AccumulateReexports(Path, Lib.getValue());
830 }
831 FwkSearchPaths.resize(new_size: FwkSearchPaths.size() - PlatformSearchPaths.size());
832 }
833
834 for (const StringMapEntry<ArchitectureSet> &Lib :
835 LinkerOpts.ReexportedLibraries) {
836 std::string Name = "lib" + Lib.getKey().str() + ".dylib";
837 std::string Path = findLibrary(InstallName: Name, FM&: *FM, FrameworkSearchPaths: {}, LibrarySearchPaths: LinkerOpts.LibPaths, SearchPaths: {});
838 if (Path.empty()) {
839 Diags->Report(DiagID: diag::err_cannot_find_reexport) << true << Lib.getKey();
840 return {};
841 }
842 if (DriverOpts.TraceLibraryLocation)
843 errs() << Path << "\n";
844
845 AccumulateReexports(Path, Lib.getValue());
846 }
847
848 for (const StringMapEntry<ArchitectureSet> &Lib :
849 LinkerOpts.ReexportedLibraryPaths)
850 AccumulateReexports(Lib.getKey(), Lib.getValue());
851
852 return {std::move(Reexports), std::move(ReexportIFs)};
853}
854
855InstallAPIContext Options::createContext() {
856 InstallAPIContext Ctx;
857 Ctx.FM = FM;
858 Ctx.Diags = Diags;
859
860 // InstallAPI requires two level namespacing.
861 Ctx.BA.TwoLevelNamespace = true;
862
863 Ctx.BA.InstallName = LinkerOpts.InstallName;
864 Ctx.BA.CurrentVersion = LinkerOpts.CurrentVersion;
865 Ctx.BA.CompatVersion = LinkerOpts.CompatVersion;
866 Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe;
867 Ctx.BA.ParentUmbrella = LinkerOpts.ParentUmbrella;
868 Ctx.BA.OSLibNotForSharedCache = LinkerOpts.OSLibNotForSharedCache;
869 Ctx.FT = DriverOpts.OutFT;
870 Ctx.OutputLoc = DriverOpts.OutputPath;
871 Ctx.LangMode = FEOpts.LangMode;
872
873 auto [Reexports, ReexportedIFs] = getReexportedLibraries();
874 if (Diags->hasErrorOccurred())
875 return Ctx;
876 Ctx.Reexports = Reexports;
877
878 // Collect symbols from alias lists.
879 AliasMap Aliases;
880 for (const StringRef ListPath : LinkerOpts.AliasLists) {
881 auto Buffer = FM->getBufferForFile(Filename: ListPath);
882 if (auto Err = Buffer.getError()) {
883 Diags->Report(DiagID: diag::err_cannot_open_file) << ListPath << Err.message();
884 return Ctx;
885 }
886 Expected<AliasMap> Result = parseAliasList(Buffer&: Buffer.get());
887 if (!Result) {
888 Diags->Report(DiagID: diag::err_cannot_read_input_list)
889 << "symbol alias" << ListPath << toString(E: Result.takeError());
890 return Ctx;
891 }
892 Aliases.insert(first: Result.get().begin(), last: Result.get().end());
893 }
894
895 // Attempt to find umbrella headers by capturing framework name.
896 StringRef FrameworkName;
897 if (!LinkerOpts.IsDylib)
898 FrameworkName =
899 Library::getFrameworkNameFromInstallName(InstallName: LinkerOpts.InstallName);
900
901 /// Process inputs headers.
902 // 1. For headers discovered by directory scanning, sort them.
903 // 2. For headers discovered by filelist, respect ordering.
904 // 3. Append extra headers and mark any excluded headers.
905 // 4. Finally, surface up umbrella headers to top of the list.
906 if (!DriverOpts.InputDirectory.empty()) {
907 DirectoryScanner Scanner(*FM, LinkerOpts.IsDylib
908 ? ScanMode::ScanDylibs
909 : ScanMode::ScanFrameworks);
910 SmallString<PATH_MAX> NormalizedPath(DriverOpts.InputDirectory);
911 FM->getVirtualFileSystem().makeAbsolute(Path&: NormalizedPath);
912 sys::path::remove_dots(path&: NormalizedPath, /*remove_dot_dot=*/true);
913 if (llvm::Error Err = Scanner.scan(Directory: NormalizedPath)) {
914 Diags->Report(DiagID: diag::err_directory_scanning)
915 << DriverOpts.InputDirectory << std::move(Err);
916 return Ctx;
917 }
918 std::vector<Library> InputLibraries = Scanner.takeLibraries();
919 if (InputLibraries.size() > 1) {
920 Diags->Report(DiagID: diag::err_more_than_one_library);
921 return Ctx;
922 }
923 llvm::append_range(C&: Ctx.InputHeaders,
924 R: DirectoryScanner::getHeaders(Libraries: InputLibraries));
925 llvm::stable_sort(Range&: Ctx.InputHeaders);
926 }
927
928 for (const StringRef ListPath : DriverOpts.FileLists) {
929 auto Buffer = FM->getBufferForFile(Filename: ListPath);
930 if (auto Err = Buffer.getError()) {
931 Diags->Report(DiagID: diag::err_cannot_open_file) << ListPath << Err.message();
932 return Ctx;
933 }
934 if (auto Err = FileListReader::loadHeaders(InputBuffer: std::move(Buffer.get()),
935 Destination&: Ctx.InputHeaders, FM)) {
936 Diags->Report(DiagID: diag::err_cannot_read_input_list)
937 << "header file" << ListPath << std::move(Err);
938 return Ctx;
939 }
940 }
941 // After initial input has been processed, add any extra headers.
942 auto HandleExtraHeaders = [&](PathSeq &Headers, HeaderType Type) -> bool {
943 assert(Type != HeaderType::Unknown && "Missing header type.");
944 for (const StringRef Path : Headers) {
945 if (!FM->getOptionalFileRef(Filename: Path)) {
946 Diags->Report(DiagID: diag::err_no_such_header_file) << Path << (unsigned)Type;
947 return false;
948 }
949 SmallString<PATH_MAX> FullPath(Path);
950 FM->makeAbsolutePath(Path&: FullPath);
951
952 auto IncludeName = createIncludeHeaderName(FullPath);
953 Ctx.InputHeaders.emplace_back(
954 args&: FullPath, args&: Type, args: IncludeName.has_value() ? *IncludeName : "");
955 Ctx.InputHeaders.back().setExtra();
956 }
957 return true;
958 };
959
960 if (!HandleExtraHeaders(DriverOpts.ExtraPublicHeaders, HeaderType::Public) ||
961 !HandleExtraHeaders(DriverOpts.ExtraPrivateHeaders,
962 HeaderType::Private) ||
963 !HandleExtraHeaders(DriverOpts.ExtraProjectHeaders, HeaderType::Project))
964 return Ctx;
965
966 // After all headers have been added, consider excluded headers.
967 std::vector<std::unique_ptr<HeaderGlob>> ExcludedHeaderGlobs;
968 std::set<FileEntryRef> ExcludedHeaderFiles;
969 auto ParseGlobs = [&](const PathSeq &Paths, HeaderType Type) {
970 assert(Type != HeaderType::Unknown && "Missing header type.");
971 for (const StringRef Path : Paths) {
972 auto Glob = HeaderGlob::create(GlobString: Path, Type);
973 if (Glob)
974 ExcludedHeaderGlobs.emplace_back(args: std::move(Glob.get()));
975 else {
976 consumeError(Err: Glob.takeError());
977 if (auto File = FM->getFileRef(Filename: Path))
978 ExcludedHeaderFiles.emplace(args&: *File);
979 else {
980 Diags->Report(DiagID: diag::err_no_such_header_file)
981 << Path << (unsigned)Type;
982 return false;
983 }
984 }
985 }
986 return true;
987 };
988
989 if (!ParseGlobs(DriverOpts.ExcludePublicHeaders, HeaderType::Public) ||
990 !ParseGlobs(DriverOpts.ExcludePrivateHeaders, HeaderType::Private) ||
991 !ParseGlobs(DriverOpts.ExcludeProjectHeaders, HeaderType::Project))
992 return Ctx;
993
994 for (HeaderFile &Header : Ctx.InputHeaders) {
995 for (auto &Glob : ExcludedHeaderGlobs)
996 if (Glob->match(Header))
997 Header.setExcluded();
998 }
999 if (!ExcludedHeaderFiles.empty()) {
1000 for (HeaderFile &Header : Ctx.InputHeaders) {
1001 auto FileRef = FM->getFileRef(Filename: Header.getPath());
1002 if (!FileRef)
1003 continue;
1004 if (ExcludedHeaderFiles.count(x: *FileRef))
1005 Header.setExcluded();
1006 }
1007 }
1008 // Report if glob was ignored.
1009 for (const auto &Glob : ExcludedHeaderGlobs)
1010 if (!Glob->didMatch())
1011 Diags->Report(DiagID: diag::warn_glob_did_not_match) << Glob->str();
1012
1013 // Mark any explicit or inferred umbrella headers. If one exists, move
1014 // that to the beginning of the input headers.
1015 auto MarkandMoveUmbrellaInHeaders = [&](llvm::Regex &Regex,
1016 HeaderType Type) -> bool {
1017 auto It = find_if(Range&: Ctx.InputHeaders, P: [&Regex, Type](const HeaderFile &H) {
1018 return (H.getType() == Type) && Regex.match(String: H.getPath());
1019 });
1020
1021 if (It == Ctx.InputHeaders.end())
1022 return false;
1023 It->setUmbrellaHeader();
1024
1025 // Because there can be an umbrella header per header type,
1026 // find the first non umbrella header to swap position with.
1027 auto BeginPos = find_if(Range&: Ctx.InputHeaders, P: [](const HeaderFile &H) {
1028 return !H.isUmbrellaHeader();
1029 });
1030 if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It)
1031 std::swap(a&: *BeginPos, b&: *It);
1032 return true;
1033 };
1034
1035 auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool {
1036 assert(Type != HeaderType::Unknown && "Missing header type.");
1037 if (!HeaderPath.empty()) {
1038 auto EscapedString = Regex::escape(String: HeaderPath);
1039 Regex UmbrellaRegex(EscapedString);
1040 if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) {
1041 Diags->Report(DiagID: diag::err_no_such_umbrella_header_file)
1042 << HeaderPath << (unsigned)Type;
1043 return false;
1044 }
1045 } else if (!FrameworkName.empty() && (Type != HeaderType::Project)) {
1046 auto UmbrellaName = "/" + Regex::escape(String: FrameworkName);
1047 if (Type == HeaderType::Public)
1048 UmbrellaName += "\\.h";
1049 else
1050 UmbrellaName += "[_]?Private\\.h";
1051 Regex UmbrellaRegex(UmbrellaName);
1052 MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type);
1053 }
1054 return true;
1055 };
1056 if (!FindUmbrellaHeader(DriverOpts.PublicUmbrellaHeader,
1057 HeaderType::Public) ||
1058 !FindUmbrellaHeader(DriverOpts.PrivateUmbrellaHeader,
1059 HeaderType::Private) ||
1060 !FindUmbrellaHeader(DriverOpts.ProjectUmbrellaHeader,
1061 HeaderType::Project))
1062 return Ctx;
1063
1064 // Parse binary dylib and initialize verifier.
1065 if (DriverOpts.DylibToVerify.empty()) {
1066 Ctx.Verifier = std::make_unique<DylibVerifier>();
1067 return Ctx;
1068 }
1069
1070 auto Buffer = FM->getBufferForFile(Filename: DriverOpts.DylibToVerify);
1071 if (auto Err = Buffer.getError()) {
1072 Diags->Report(DiagID: diag::err_cannot_open_file)
1073 << DriverOpts.DylibToVerify << Err.message();
1074 return Ctx;
1075 }
1076
1077 DylibReader::ParseOption PO;
1078 PO.Undefineds = false;
1079 Expected<Records> Slices =
1080 DylibReader::readFile(Buffer: (*Buffer)->getMemBufferRef(), Opt: PO);
1081 if (auto Err = Slices.takeError()) {
1082 Diags->Report(DiagID: diag::err_cannot_open_file)
1083 << DriverOpts.DylibToVerify << std::move(Err);
1084 return Ctx;
1085 }
1086
1087 Ctx.Verifier = std::make_unique<DylibVerifier>(
1088 args: std::move(*Slices), args: std::move(ReexportedIFs), args: std::move(Aliases), args&: Diags,
1089 args&: DriverOpts.VerifyMode, args&: DriverOpts.Zippered, args&: DriverOpts.Demangle,
1090 args&: DriverOpts.DSYMPath);
1091 return Ctx;
1092}
1093
1094void Options::addConditionalCC1Args(std::vector<std::string> &ArgStrings,
1095 const llvm::Triple &Targ,
1096 const HeaderType Type) {
1097 // Unique to architecture (Xarch) options hold no arguments to pass along for
1098 // frontend.
1099
1100 // Add specific to platform arguments.
1101 PathSeq PlatformSearchPaths =
1102 getPathsForPlatform(Paths: FEOpts.SystemFwkPaths, Platform: mapToPlatformType(Target: Targ));
1103 llvm::for_each(Range&: PlatformSearchPaths, F: [&ArgStrings](const StringRef Path) {
1104 ArgStrings.push_back(x: "-iframework");
1105 ArgStrings.push_back(x: Path.str());
1106 });
1107
1108 // Add specific to header type arguments.
1109 if (Type == HeaderType::Project)
1110 for (const StringRef A : ProjectLevelArgs)
1111 ArgStrings.emplace_back(args: A);
1112}
1113
1114} // namespace installapi
1115} // namespace clang
1116