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