[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / clang / tools / clang-installapi / Options.cpp
blob3fa79636de5d759af8fa0d43e2a26b7023a26e58
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 //===----------------------------------------------------------------------===//
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"
25 using namespace llvm;
26 using namespace llvm::opt;
27 using namespace llvm::MachO;
29 namespace drv = clang::driver::options;
31 namespace clang {
32 namespace installapi {
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
42 static constexpr const llvm::StringLiteral PrefixTable_init[] =
43 #define PREFIX_UNION(VALUES) VALUES
44 #include "InstallAPIOpts.inc"
45 #undef PREFIX_UNION
47 static constexpr const ArrayRef<StringLiteral>
48 PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
50 /// Create table mapping all options defined in InstallAPIOpts.td.
51 static 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
73 namespace {
75 /// \brief Create OptTable class for parsing actual command line arguments.
76 class DriverOptTable : public opt::PrecomputedOptTable {
77 public:
78 DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
81 } // end anonymous namespace.
83 static llvm::opt::OptTable *createDriverOptTable() {
84 return new DriverOptTable();
87 /// Parse JSON input into argument list.
88 ///
89 /* Expected input format.
90 * { "label" : ["-ClangArg1", "-ClangArg2"] }
92 ///
93 /// Input is interpreted as "-Xlabel ClangArg1 -XLabel ClangArg2".
94 static Expected<llvm::opt::InputArgList>
95 getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
96 std::vector<std::string> &Storage) {
97 using namespace json;
98 Expected<Value> ValOrErr = json::parse(Input);
99 if (!ValOrErr)
100 return ValOrErr.takeError();
102 const Object *Root = ValOrErr->getAsObject();
103 if (!Root)
104 return llvm::opt::InputArgList();
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>(TextAPIErrorCode::InvalidInputFormat);
111 for (auto Arg : *ArgList) {
112 std::optional<StringRef> ArgStr = Arg.getAsString();
113 if (!ArgStr)
114 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
115 Storage.emplace_back(Label);
116 Storage.emplace_back(*ArgStr);
120 std::vector<const char *> CArgs(Storage.size());
121 llvm::for_each(Storage,
122 [&CArgs](StringRef Str) { CArgs.emplace_back(Str.data()); });
124 unsigned MissingArgIndex, MissingArgCount;
125 return Table->ParseArgs(CArgs, MissingArgIndex, MissingArgCount);
128 bool Options::processDriverOptions(InputArgList &Args) {
129 // Handle inputs.
130 for (const StringRef Path : Args.getAllArgValues(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(Path))
134 DriverOpts.InputDirectory = Path.str();
135 else
136 DriverOpts.FileLists.emplace_back(Path.str());
139 // Handle output.
140 SmallString<PATH_MAX> OutputPath;
141 if (auto *Arg = Args.getLastArg(drv::OPT_o)) {
142 OutputPath = Arg->getValue();
143 if (OutputPath != "-")
144 FM->makeAbsolutePath(OutputPath);
145 DriverOpts.OutputPath = std::string(OutputPath);
147 if (DriverOpts.OutputPath.empty()) {
148 Diags->Report(diag::err_no_output_file);
149 return false;
152 // Do basic error checking first for mixing -target and -arch options.
153 auto *ArgArch = Args.getLastArgNoClaim(drv::OPT_arch);
154 auto *ArgTarget = Args.getLastArgNoClaim(drv::OPT_target);
155 auto *ArgTargetVariant =
156 Args.getLastArgNoClaim(drv::OPT_darwin_target_variant);
157 if (ArgArch && (ArgTarget || ArgTargetVariant)) {
158 Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
159 << ArgArch->getAsString(Args)
160 << (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
161 return false;
164 auto *ArgMinTargetOS = Args.getLastArgNoClaim(drv::OPT_mtargetos_EQ);
165 if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
166 Diags->Report(clang::diag::err_drv_cannot_mix_options)
167 << ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
168 return false;
171 // Capture target triples first.
172 if (ArgTarget) {
173 for (const Arg *A : Args.filtered(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(clang::diag::err_drv_unsupported_opt_for_target)
180 << "installapi" << TargetTriple.str();
181 return false;
183 DriverOpts.Targets[TAPITarget] = TargetTriple;
187 // Capture target variants.
188 DriverOpts.Zippered = ArgTargetVariant != nullptr;
189 for (Arg *A : Args.filtered(drv::OPT_darwin_target_variant)) {
190 A->claim();
191 Triple Variant(A->getValue());
192 if (Variant.getVendor() != Triple::Apple) {
193 Diags->Report(diag::err_unsupported_vendor)
194 << Variant.getVendorName() << A->getAsString(Args);
195 return false;
198 switch (Variant.getOS()) {
199 default:
200 Diags->Report(diag::err_unsupported_os)
201 << Variant.getOSName() << A->getAsString(Args);
202 return false;
203 case Triple::MacOSX:
204 case Triple::IOS:
205 break;
208 switch (Variant.getEnvironment()) {
209 default:
210 Diags->Report(diag::err_unsupported_environment)
211 << Variant.getEnvironmentName() << A->getAsString(Args);
212 return false;
213 case Triple::UnknownEnvironment:
214 case Triple::MacABI:
215 break;
218 Target TAPIVariant(Variant);
219 // See if there is a matching --target option for this --target-variant
220 // option.
221 auto It = find_if(DriverOpts.Targets, [&](const auto &T) {
222 return (T.first.Arch == TAPIVariant.Arch) &&
223 (T.first.Platform != PlatformType::PLATFORM_UNKNOWN);
226 if (It == DriverOpts.Targets.end()) {
227 Diags->Report(diag::err_no_matching_target) << Variant.str();
228 return false;
231 DriverOpts.Targets[TAPIVariant] = Variant;
234 DriverOpts.Verbose = Args.hasArgNoClaim(drv::OPT_v);
236 return true;
239 bool 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(OPT_Xarch__)) {
243 if (!processXarchOption(Args, It))
244 return false;
245 continue;
246 } else if (A->getOption().matches(OPT_Xplatform__)) {
247 if (!processXplatformOption(Args, It))
248 return false;
249 continue;
250 } else if (A->getOption().matches(OPT_Xproject)) {
251 if (!processXprojectOption(Args, It))
252 return false;
253 continue;
254 } else if (!A->getOption().matches(OPT_X__))
255 continue;
257 // Handle any user defined labels.
258 const StringRef Label = A->getValue(0);
260 // Ban "public" and "private" labels.
261 if ((Label.lower() == "public") || (Label.lower() == "private")) {
262 Diags->Report(diag::err_invalid_label) << Label;
263 return false;
266 auto NextIt = std::next(It);
267 if (NextIt == End) {
268 Diags->Report(clang::diag::err_drv_missing_argument)
269 << A->getAsString(Args) << 1;
270 return false;
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(clang::diag::err_drv_argument_not_allowed_with)
279 << A->getAsString(Args) << NextA->getAsString(Args);
280 return false;
282 const StringRef ASpelling = NextA->getSpelling();
283 const auto &AValues = NextA->getValues();
284 if (AValues.empty())
285 FEOpts.UniqueArgs[Label].emplace_back(ASpelling.str());
286 else
287 for (const StringRef Val : AValues)
288 FEOpts.UniqueArgs[Label].emplace_back((ASpelling + Val).str());
290 A->claim();
291 NextA->claim();
294 return true;
297 bool Options::processXplatformOption(InputArgList &Args, arg_iterator Curr) {
298 Arg *A = *Curr;
300 PlatformType Platform = getPlatformFromName(A->getValue(0));
301 if (Platform == PLATFORM_UNKNOWN) {
302 Diags->Report(diag::err_unsupported_os)
303 << getPlatformName(Platform) << A->getAsString(Args);
304 return false;
306 auto NextIt = std::next(Curr);
307 if (NextIt == Args.end()) {
308 Diags->Report(diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
309 return false;
312 Arg *NextA = *NextIt;
313 switch ((ID)NextA->getOption().getID()) {
314 case OPT_iframework:
315 FEOpts.SystemFwkPaths.emplace_back(NextA->getValue(), Platform);
316 break;
317 default:
318 Diags->Report(diag::err_drv_invalid_argument_to_option)
319 << A->getAsString(Args) << NextA->getAsString(Args);
320 return false;
323 A->claim();
324 NextA->claim();
326 return true;
329 bool Options::processXprojectOption(InputArgList &Args, arg_iterator Curr) {
330 Arg *A = *Curr;
331 auto NextIt = std::next(Curr);
332 if (NextIt == Args.end()) {
333 Diags->Report(diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
334 return false;
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(diag::err_drv_argument_not_allowed_with)
347 << A->getAsString(Args) << NextA->getAsString(Args);
348 return false;
351 std::string ArgString = NextA->getSpelling().str();
352 for (const StringRef Val : NextA->getValues())
353 ArgString += Val.str();
355 ProjectLevelArgs.push_back(ArgString);
356 A->claim();
357 NextA->claim();
359 return true;
362 bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
363 Arg *CurrArg = *Curr;
364 Architecture Arch = getArchitectureFromName(CurrArg->getValue(0));
365 if (Arch == AK_unknown) {
366 Diags->Report(diag::err_drv_invalid_arch_name)
367 << CurrArg->getAsString(Args);
368 return false;
371 auto NextIt = std::next(Curr);
372 if (NextIt == Args.end()) {
373 Diags->Report(diag::err_drv_missing_argument)
374 << CurrArg->getAsString(Args) << 1;
375 return false;
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(diag::err_drv_invalid_argument_to_option)
390 << NextArg->getAsString(Args) << CurrArg->getAsString(Args);
391 return false;
394 ArgToArchMap[NextArg] = Arch;
395 CurrArg->claim();
397 return true;
400 bool Options::processOptionList(InputArgList &Args,
401 llvm::opt::OptTable *Table) {
402 Arg *A = Args.getLastArg(OPT_option_list);
403 if (!A)
404 return true;
406 const StringRef Path = A->getValue(0);
407 auto InputOrErr = FM->getBufferForFile(Path);
408 if (auto Err = InputOrErr.getError()) {
409 Diags->Report(diag::err_cannot_open_file) << Path << Err.message();
410 return false;
412 // Backing storage referenced for argument processing.
413 std::vector<std::string> Storage;
414 auto ArgsOrErr =
415 getArgListFromJSON((*InputOrErr)->getBuffer(), Table, Storage);
417 if (auto Err = ArgsOrErr.takeError()) {
418 Diags->Report(diag::err_cannot_read_input_list)
419 << "option" << Path << toString(std::move(Err));
420 return false;
422 return processInstallAPIXOptions(*ArgsOrErr);
425 bool Options::processLinkerOptions(InputArgList &Args) {
426 // Handle required arguments.
427 if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
428 LinkerOpts.InstallName = A->getValue();
429 if (LinkerOpts.InstallName.empty()) {
430 Diags->Report(diag::err_no_install_name);
431 return false;
434 // Defaulted or optional arguments.
435 if (auto *Arg = Args.getLastArg(drv::OPT_current__version))
436 LinkerOpts.CurrentVersion.parse64(Arg->getValue());
438 if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
439 LinkerOpts.CompatVersion.parse64(Arg->getValue());
441 if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
442 LinkerOpts.CompatVersion.parse64(Arg->getValue());
444 if (auto *Arg = Args.getLastArg(drv::OPT_umbrella))
445 LinkerOpts.ParentUmbrella = Arg->getValue();
447 LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);
449 for (auto *Arg : Args.filtered(drv::OPT_alias_list)) {
450 LinkerOpts.AliasLists.emplace_back(Arg->getValue());
451 Arg->claim();
454 LinkerOpts.AppExtensionSafe = Args.hasFlag(
455 drv::OPT_fapplication_extension, drv::OPT_fno_application_extension,
456 /*Default=*/LinkerOpts.AppExtensionSafe);
458 if (::getenv("LD_NO_ENCRYPT") != nullptr)
459 LinkerOpts.AppExtensionSafe = true;
461 if (::getenv("LD_APPLICATION_EXTENSION_SAFE") != nullptr)
462 LinkerOpts.AppExtensionSafe = true;
464 // Capture library paths.
465 PathSeq LibraryPaths;
466 for (const Arg *A : Args.filtered(drv::OPT_L)) {
467 LibraryPaths.emplace_back(A->getValue());
468 A->claim();
471 if (!LibraryPaths.empty())
472 LinkerOpts.LibPaths = std::move(LibraryPaths);
474 return true;
477 // NOTE: Do not claim any arguments, as they will be passed along for CC1
478 // invocations.
479 bool Options::processFrontendOptions(InputArgList &Args) {
480 // Capture language mode.
481 if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
482 FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
483 .Case("c", clang::Language::C)
484 .Case("c++", clang::Language::CXX)
485 .Case("objective-c", clang::Language::ObjC)
486 .Case("objective-c++", clang::Language::ObjCXX)
487 .Default(clang::Language::Unknown);
489 if (FEOpts.LangMode == clang::Language::Unknown) {
490 Diags->Report(clang::diag::err_drv_invalid_value)
491 << A->getAsString(Args) << A->getValue();
492 return false;
495 for (auto *A : Args.filtered(drv::OPT_ObjC, drv::OPT_ObjCXX)) {
496 if (A->getOption().matches(drv::OPT_ObjC))
497 FEOpts.LangMode = clang::Language::ObjC;
498 else
499 FEOpts.LangMode = clang::Language::ObjCXX;
502 // Capture Sysroot.
503 if (const Arg *A = Args.getLastArgNoClaim(drv::OPT_isysroot)) {
504 SmallString<PATH_MAX> Path(A->getValue());
505 FM->makeAbsolutePath(Path);
506 if (!FM->getOptionalDirectoryRef(Path)) {
507 Diags->Report(diag::err_missing_sysroot) << Path;
508 return false;
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("SDKROOT")) {
515 if (StringRef(Env) != "/" && llvm::sys::path::is_absolute(Env) &&
516 FM->getOptionalFileRef(Env))
517 FEOpts.ISysroot = Env;
521 // Capture system frameworks for all platforms.
522 for (const Arg *A : Args.filtered(drv::OPT_iframework))
523 FEOpts.SystemFwkPaths.emplace_back(A->getValue(),
524 std::optional<PlatformType>{});
526 // Capture framework paths.
527 PathSeq FrameworkPaths;
528 for (const Arg *A : Args.filtered(drv::OPT_F))
529 FrameworkPaths.emplace_back(A->getValue());
531 if (!FrameworkPaths.empty())
532 FEOpts.FwkPaths = std::move(FrameworkPaths);
534 // Add default framework/library paths.
535 PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
536 PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
537 "/System/Library/Frameworks"};
539 for (const StringRef LibPath : DefaultLibraryPaths) {
540 SmallString<PATH_MAX> Path(FEOpts.ISysroot);
541 sys::path::append(Path, LibPath);
542 LinkerOpts.LibPaths.emplace_back(Path.str());
544 for (const StringRef FwkPath : DefaultFrameworkPaths) {
545 SmallString<PATH_MAX> Path(FEOpts.ISysroot);
546 sys::path::append(Path, FwkPath);
547 FEOpts.SystemFwkPaths.emplace_back(Path.str(),
548 std::optional<PlatformType>{});
551 return true;
554 bool Options::addFilePaths(InputArgList &Args, PathSeq &Headers,
555 OptSpecifier ID) {
556 for (const StringRef Path : Args.getAllArgValues(ID)) {
557 if ((bool)FM->getOptionalDirectoryRef(Path, /*CacheFailure=*/false)) {
558 auto InputHeadersOrErr = enumerateFiles(*FM, Path);
559 if (!InputHeadersOrErr) {
560 Diags->Report(diag::err_cannot_open_file)
561 << Path << toString(InputHeadersOrErr.takeError());
562 return false;
564 // Sort headers to ensure deterministic behavior.
565 sort(*InputHeadersOrErr);
566 for (StringRef H : *InputHeadersOrErr)
567 Headers.emplace_back(std::move(H));
568 } else
569 Headers.emplace_back(Path);
571 return true;
574 std::vector<const char *>
575 Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
576 std::unique_ptr<llvm::opt::OptTable> Table;
577 Table.reset(createDriverOptTable());
579 unsigned MissingArgIndex, MissingArgCount;
580 auto ParsedArgs = Table->ParseArgs(Args.slice(1), MissingArgIndex,
581 MissingArgCount, Visibility());
583 // Capture InstallAPI only driver options.
584 if (!processInstallAPIXOptions(ParsedArgs))
585 return {};
587 if (!processOptionList(ParsedArgs, Table.get()))
588 return {};
590 DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);
592 if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
593 DriverOpts.OutFT = TextAPIWriter::parseFileType(A->getValue());
594 if (DriverOpts.OutFT == FileType::Invalid) {
595 Diags->Report(clang::diag::err_drv_invalid_value)
596 << A->getAsString(ParsedArgs) << A->getValue();
597 return {};
601 if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_mode_EQ)) {
602 DriverOpts.VerifyMode =
603 StringSwitch<VerificationMode>(A->getValue())
604 .Case("ErrorsOnly", VerificationMode::ErrorsOnly)
605 .Case("ErrorsAndWarnings", VerificationMode::ErrorsAndWarnings)
606 .Case("Pedantic", VerificationMode::Pedantic)
607 .Default(VerificationMode::Invalid);
609 if (DriverOpts.VerifyMode == VerificationMode::Invalid) {
610 Diags->Report(clang::diag::err_drv_invalid_value)
611 << A->getAsString(ParsedArgs) << A->getValue();
612 return {};
616 if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_against))
617 DriverOpts.DylibToVerify = A->getValue();
619 if (const Arg *A = ParsedArgs.getLastArg(OPT_dsym))
620 DriverOpts.DSYMPath = A->getValue();
622 DriverOpts.TraceLibraryLocation = ParsedArgs.hasArg(OPT_t);
624 // Linker options not handled by clang driver.
625 LinkerOpts.OSLibNotForSharedCache =
626 ParsedArgs.hasArg(OPT_not_for_dyld_shared_cache);
628 for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
629 LinkerOpts.AllowableClients[A->getValue()] =
630 ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
631 A->claim();
634 for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
635 LinkerOpts.ReexportedLibraries[A->getValue()] =
636 ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
637 A->claim();
640 for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
641 LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
642 ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
643 A->claim();
646 for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
647 LinkerOpts.ReexportedFrameworks[A->getValue()] =
648 ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
649 A->claim();
652 for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
653 LinkerOpts.RPaths[A->getValue()] =
654 ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
655 A->claim();
658 // Handle exclude & extra header directories or files.
659 auto handleAdditionalInputArgs = [&](PathSeq &Headers,
660 clang::installapi::ID OptID) {
661 if (ParsedArgs.hasArgNoClaim(OptID))
662 Headers.clear();
663 return addFilePaths(ParsedArgs, Headers, OptID);
666 if (!handleAdditionalInputArgs(DriverOpts.ExtraPublicHeaders,
667 OPT_extra_public_header))
668 return {};
670 if (!handleAdditionalInputArgs(DriverOpts.ExtraPrivateHeaders,
671 OPT_extra_private_header))
672 return {};
673 if (!handleAdditionalInputArgs(DriverOpts.ExtraProjectHeaders,
674 OPT_extra_project_header))
675 return {};
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 {};
687 // Handle umbrella headers.
688 if (const Arg *A = ParsedArgs.getLastArg(OPT_public_umbrella_header))
689 DriverOpts.PublicUmbrellaHeader = A->getValue();
691 if (const Arg *A = ParsedArgs.getLastArg(OPT_private_umbrella_header))
692 DriverOpts.PrivateUmbrellaHeader = A->getValue();
694 if (const Arg *A = ParsedArgs.getLastArg(OPT_project_umbrella_header))
695 DriverOpts.ProjectUmbrellaHeader = A->getValue();
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(A->getSpelling().data());
705 } else
706 llvm::copy(A->getValues(), std::back_inserter(ClangDriverArgs));
708 return ClangDriverArgs;
711 Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
712 ArrayRef<const char *> Args, const StringRef ProgName)
713 : Diags(&Diag), FM(FM) {
715 // First process InstallAPI specific options.
716 auto DriverArgs = processAndFilterOutInstallAPIOptions(Args);
717 if (Diags->hasErrorOccurred())
718 return;
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(DriverArgs, /*UseDriverMode=*/true, HasError);
729 if (HasError)
730 return;
731 Driver.setCheckInputsExist(false);
733 if (!processDriverOptions(ArgList))
734 return;
736 if (!processLinkerOptions(ArgList))
737 return;
739 if (!processFrontendOptions(ArgList))
740 return;
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(DriverOpts.Targets,
746 [&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);
752 assignDefaultLibAttrs(LinkerOpts.AllowableClients);
753 assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
754 assignDefaultLibAttrs(LinkerOpts.ReexportedLibraries);
755 assignDefaultLibAttrs(LinkerOpts.ReexportedLibraryPaths);
756 assignDefaultLibAttrs(LinkerOpts.RPaths);
758 /// Force cc1 options that should always be on.
759 FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
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(A->getSpelling());
766 llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
770 static Expected<std::unique_ptr<InterfaceFile>>
771 getInterfaceFile(const StringRef Filename) {
772 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
773 MemoryBuffer::getFile(Filename);
774 if (auto Err = BufferOrErr.getError())
775 return errorCodeToError(std::move(Err));
777 auto Buffer = std::move(*BufferOrErr);
778 std::unique_ptr<InterfaceFile> IF;
779 switch (identify_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->getMemBufferRef());
784 break;
785 case file_magic::tapi_file:
786 return TextAPIReader::get(Buffer->getMemBufferRef());
787 default:
788 return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
789 "unsupported library file format");
791 llvm_unreachable("unexpected failure in getInterface");
794 std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
795 LibAttrs Reexports;
796 ReexportedInterfaces ReexportIFs;
797 auto AccumulateReexports = [&](StringRef Path, const ArchitectureSet &Archs) {
798 auto ReexportIFOrErr = getInterfaceFile(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({InstallName, Archs});
805 ReexportIFs.emplace_back(std::move(*Reexport));
806 return true;
809 PlatformSet Platforms;
810 llvm::for_each(DriverOpts.Targets,
811 [&](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(FEOpts.SystemFwkPaths, P);
816 FwkSearchPaths.insert(FwkSearchPaths.end(), PlatformSearchPaths.begin(),
817 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(Name, *FM, FwkSearchPaths, {}, {});
822 if (Path.empty()) {
823 Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
824 return {};
826 if (DriverOpts.TraceLibraryLocation)
827 errs() << Path << "\n";
829 AccumulateReexports(Path, Lib.getValue());
831 FwkSearchPaths.resize(FwkSearchPaths.size() - PlatformSearchPaths.size());
834 for (const StringMapEntry<ArchitectureSet> &Lib :
835 LinkerOpts.ReexportedLibraries) {
836 std::string Name = "lib" + Lib.getKey().str() + ".dylib";
837 std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
838 if (Path.empty()) {
839 Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
840 return {};
842 if (DriverOpts.TraceLibraryLocation)
843 errs() << Path << "\n";
845 AccumulateReexports(Path, Lib.getValue());
848 for (const StringMapEntry<ArchitectureSet> &Lib :
849 LinkerOpts.ReexportedLibraryPaths)
850 AccumulateReexports(Lib.getKey(), Lib.getValue());
852 return {std::move(Reexports), std::move(ReexportIFs)};
855 InstallAPIContext Options::createContext() {
856 InstallAPIContext Ctx;
857 Ctx.FM = FM;
858 Ctx.Diags = Diags;
860 // InstallAPI requires two level namespacing.
861 Ctx.BA.TwoLevelNamespace = true;
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;
873 auto [Reexports, ReexportedIFs] = getReexportedLibraries();
874 if (Diags->hasErrorOccurred())
875 return Ctx;
876 Ctx.Reexports = Reexports;
878 // Collect symbols from alias lists.
879 AliasMap Aliases;
880 for (const StringRef ListPath : LinkerOpts.AliasLists) {
881 auto Buffer = FM->getBufferForFile(ListPath);
882 if (auto Err = Buffer.getError()) {
883 Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
884 return Ctx;
886 Expected<AliasMap> Result = parseAliasList(Buffer.get());
887 if (!Result) {
888 Diags->Report(diag::err_cannot_read_input_list)
889 << "symbol alias" << ListPath << toString(Result.takeError());
890 return Ctx;
892 Aliases.insert(Result.get().begin(), Result.get().end());
895 // Attempt to find umbrella headers by capturing framework name.
896 StringRef FrameworkName;
897 if (!LinkerOpts.IsDylib)
898 FrameworkName =
899 Library::getFrameworkNameFromInstallName(LinkerOpts.InstallName);
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(NormalizedPath);
912 sys::path::remove_dots(NormalizedPath, /*remove_dot_dot=*/true);
913 if (llvm::Error Err = Scanner.scan(NormalizedPath)) {
914 Diags->Report(diag::err_directory_scanning)
915 << DriverOpts.InputDirectory << std::move(Err);
916 return Ctx;
918 std::vector<Library> InputLibraries = Scanner.takeLibraries();
919 if (InputLibraries.size() > 1) {
920 Diags->Report(diag::err_more_than_one_library);
921 return Ctx;
923 llvm::append_range(Ctx.InputHeaders,
924 DirectoryScanner::getHeaders(InputLibraries));
925 llvm::stable_sort(Ctx.InputHeaders);
928 for (const StringRef ListPath : DriverOpts.FileLists) {
929 auto Buffer = FM->getBufferForFile(ListPath);
930 if (auto Err = Buffer.getError()) {
931 Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
932 return Ctx;
934 if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()),
935 Ctx.InputHeaders, FM)) {
936 Diags->Report(diag::err_cannot_read_input_list)
937 << "header file" << ListPath << std::move(Err);
938 return Ctx;
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(Path)) {
946 Diags->Report(diag::err_no_such_header_file) << Path << (unsigned)Type;
947 return false;
949 SmallString<PATH_MAX> FullPath(Path);
950 FM->makeAbsolutePath(FullPath);
952 auto IncludeName = createIncludeHeaderName(FullPath);
953 Ctx.InputHeaders.emplace_back(
954 FullPath, Type, IncludeName.has_value() ? *IncludeName : "");
955 Ctx.InputHeaders.back().setExtra();
957 return true;
960 if (!HandleExtraHeaders(DriverOpts.ExtraPublicHeaders, HeaderType::Public) ||
961 !HandleExtraHeaders(DriverOpts.ExtraPrivateHeaders,
962 HeaderType::Private) ||
963 !HandleExtraHeaders(DriverOpts.ExtraProjectHeaders, HeaderType::Project))
964 return Ctx;
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(Path, Type);
973 if (Glob)
974 ExcludedHeaderGlobs.emplace_back(std::move(Glob.get()));
975 else {
976 consumeError(Glob.takeError());
977 if (auto File = FM->getFileRef(Path))
978 ExcludedHeaderFiles.emplace(*File);
979 else {
980 Diags->Report(diag::err_no_such_header_file)
981 << Path << (unsigned)Type;
982 return false;
986 return true;
989 if (!ParseGlobs(DriverOpts.ExcludePublicHeaders, HeaderType::Public) ||
990 !ParseGlobs(DriverOpts.ExcludePrivateHeaders, HeaderType::Private) ||
991 !ParseGlobs(DriverOpts.ExcludeProjectHeaders, HeaderType::Project))
992 return Ctx;
994 for (HeaderFile &Header : Ctx.InputHeaders) {
995 for (auto &Glob : ExcludedHeaderGlobs)
996 if (Glob->match(Header))
997 Header.setExcluded();
999 if (!ExcludedHeaderFiles.empty()) {
1000 for (HeaderFile &Header : Ctx.InputHeaders) {
1001 auto FileRef = FM->getFileRef(Header.getPath());
1002 if (!FileRef)
1003 continue;
1004 if (ExcludedHeaderFiles.count(*FileRef))
1005 Header.setExcluded();
1008 // Report if glob was ignored.
1009 for (const auto &Glob : ExcludedHeaderGlobs)
1010 if (!Glob->didMatch())
1011 Diags->Report(diag::warn_glob_did_not_match) << Glob->str();
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(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) {
1018 return (H.getType() == Type) && Regex.match(H.getPath());
1021 if (It == Ctx.InputHeaders.end())
1022 return false;
1023 It->setUmbrellaHeader();
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(Ctx.InputHeaders, [](const HeaderFile &H) {
1028 return !H.isUmbrellaHeader();
1030 if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It)
1031 std::swap(*BeginPos, *It);
1032 return true;
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(HeaderPath);
1039 Regex UmbrellaRegex(EscapedString);
1040 if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) {
1041 Diags->Report(diag::err_no_such_umbrella_header_file)
1042 << HeaderPath << (unsigned)Type;
1043 return false;
1045 } else if (!FrameworkName.empty() && (Type != HeaderType::Project)) {
1046 auto UmbrellaName = "/" + Regex::escape(FrameworkName);
1047 if (Type == HeaderType::Public)
1048 UmbrellaName += "\\.h";
1049 else
1050 UmbrellaName += "[_]?Private\\.h";
1051 Regex UmbrellaRegex(UmbrellaName);
1052 MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type);
1054 return true;
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;
1064 // Parse binary dylib and initialize verifier.
1065 if (DriverOpts.DylibToVerify.empty()) {
1066 Ctx.Verifier = std::make_unique<DylibVerifier>();
1067 return Ctx;
1070 auto Buffer = FM->getBufferForFile(DriverOpts.DylibToVerify);
1071 if (auto Err = Buffer.getError()) {
1072 Diags->Report(diag::err_cannot_open_file)
1073 << DriverOpts.DylibToVerify << Err.message();
1074 return Ctx;
1077 DylibReader::ParseOption PO;
1078 PO.Undefineds = false;
1079 Expected<Records> Slices =
1080 DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
1081 if (auto Err = Slices.takeError()) {
1082 Diags->Report(diag::err_cannot_open_file)
1083 << DriverOpts.DylibToVerify << std::move(Err);
1084 return Ctx;
1087 Ctx.Verifier = std::make_unique<DylibVerifier>(
1088 std::move(*Slices), std::move(ReexportedIFs), std::move(Aliases), Diags,
1089 DriverOpts.VerifyMode, DriverOpts.Zippered, DriverOpts.Demangle,
1090 DriverOpts.DSYMPath);
1091 return Ctx;
1094 void 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.
1100 // Add specific to platform arguments.
1101 PathSeq PlatformSearchPaths =
1102 getPathsForPlatform(FEOpts.SystemFwkPaths, mapToPlatformType(Targ));
1103 llvm::for_each(PlatformSearchPaths, [&ArgStrings](const StringRef Path) {
1104 ArgStrings.push_back("-iframework");
1105 ArgStrings.push_back(Path.str());
1108 // Add specific to header type arguments.
1109 if (Type == HeaderType::Project)
1110 for (const StringRef A : ProjectLevelArgs)
1111 ArgStrings.emplace_back(A);
1114 } // namespace installapi
1115 } // namespace clang