xref: /llvm-project/clang/tools/clang-installapi/Options.cpp (revision dd647e3e608ed0b2bac7c588d5859b80ef4a5976)
10a518db9SCyndy Ishida //===-- Options.cpp -------------------------------------------------------===//
20a518db9SCyndy Ishida //
30a518db9SCyndy Ishida // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40a518db9SCyndy Ishida // See https://llvm.org/LICENSE.txt for license information.
50a518db9SCyndy Ishida // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60a518db9SCyndy Ishida //
70a518db9SCyndy Ishida //===----------------------------------------------------------------------===//
80a518db9SCyndy Ishida 
90a518db9SCyndy Ishida #include "Options.h"
1027b2d7d4SCyndy Ishida #include "clang/Basic/DiagnosticIDs.h"
110a518db9SCyndy Ishida #include "clang/Driver/Driver.h"
12feed66f3SCyndy Ishida #include "clang/InstallAPI/DirectoryScanner.h"
13c6cbf81cSCyndy Ishida #include "clang/InstallAPI/FileList.h"
14487720fcSCyndy Ishida #include "clang/InstallAPI/HeaderFile.h"
15c51095f5SCyndy Ishida #include "clang/InstallAPI/InstallAPIDiagnostic.h"
1627b2d7d4SCyndy Ishida #include "llvm/BinaryFormat/Magic.h"
17c9dc52d4SCyndy Ishida #include "llvm/Support/JSON.h"
180a518db9SCyndy Ishida #include "llvm/Support/Program.h"
190a518db9SCyndy Ishida #include "llvm/TargetParser/Host.h"
20c51095f5SCyndy Ishida #include "llvm/TextAPI/DylibReader.h"
2127b2d7d4SCyndy Ishida #include "llvm/TextAPI/TextAPIError.h"
2227b2d7d4SCyndy Ishida #include "llvm/TextAPI/TextAPIReader.h"
23c51095f5SCyndy Ishida #include "llvm/TextAPI/TextAPIWriter.h"
240a518db9SCyndy Ishida 
25c51095f5SCyndy Ishida using namespace llvm;
260a518db9SCyndy Ishida using namespace llvm::opt;
270a518db9SCyndy Ishida using namespace llvm::MachO;
280a518db9SCyndy Ishida 
29c51095f5SCyndy Ishida namespace drv = clang::driver::options;
30c51095f5SCyndy Ishida 
310a518db9SCyndy Ishida namespace clang {
320a518db9SCyndy Ishida namespace installapi {
330a518db9SCyndy Ishida 
34*dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE
35c51095f5SCyndy Ishida #include "InstallAPIOpts.inc"
36*dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE
37c51095f5SCyndy Ishida 
38*dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE
39c51095f5SCyndy Ishida #include "InstallAPIOpts.inc"
40*dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE
41*dd647e3eSChandler Carruth 
42*dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_UNION_CODE
43*dd647e3eSChandler Carruth #include "InstallAPIOpts.inc"
44*dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_UNION_CODE
45c51095f5SCyndy Ishida 
46c51095f5SCyndy Ishida /// Create table mapping all options defined in InstallAPIOpts.td.
47c51095f5SCyndy Ishida static constexpr OptTable::Info InfoTable[] = {
48*dd647e3eSChandler Carruth #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
49c51095f5SCyndy Ishida #include "InstallAPIOpts.inc"
50c51095f5SCyndy Ishida #undef OPTION
51c51095f5SCyndy Ishida };
52c51095f5SCyndy Ishida 
53c51095f5SCyndy Ishida namespace {
54c51095f5SCyndy Ishida 
55c51095f5SCyndy Ishida /// \brief Create OptTable class for parsing actual command line arguments.
56c51095f5SCyndy Ishida class DriverOptTable : public opt::PrecomputedOptTable {
57c51095f5SCyndy Ishida public:
58*dd647e3eSChandler Carruth   DriverOptTable()
59*dd647e3eSChandler Carruth       : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
60*dd647e3eSChandler Carruth                             OptionPrefixesUnion) {}
61c51095f5SCyndy Ishida };
62c51095f5SCyndy Ishida 
63c51095f5SCyndy Ishida } // end anonymous namespace.
64c51095f5SCyndy Ishida 
65c51095f5SCyndy Ishida static llvm::opt::OptTable *createDriverOptTable() {
66c51095f5SCyndy Ishida   return new DriverOptTable();
67c51095f5SCyndy Ishida }
68c51095f5SCyndy Ishida 
69c9dc52d4SCyndy Ishida /// Parse JSON input into argument list.
70c9dc52d4SCyndy Ishida ///
71c9dc52d4SCyndy Ishida /* Expected input format.
72c9dc52d4SCyndy Ishida  *  { "label" : ["-ClangArg1", "-ClangArg2"] }
73c9dc52d4SCyndy Ishida  */
74c9dc52d4SCyndy Ishida ///
75c9dc52d4SCyndy Ishida /// Input is interpreted as "-Xlabel ClangArg1 -XLabel ClangArg2".
76c9dc52d4SCyndy Ishida static Expected<llvm::opt::InputArgList>
77c9dc52d4SCyndy Ishida getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
78c9dc52d4SCyndy Ishida                    std::vector<std::string> &Storage) {
79c9dc52d4SCyndy Ishida   using namespace json;
80c9dc52d4SCyndy Ishida   Expected<Value> ValOrErr = json::parse(Input);
81c9dc52d4SCyndy Ishida   if (!ValOrErr)
82c9dc52d4SCyndy Ishida     return ValOrErr.takeError();
83c9dc52d4SCyndy Ishida 
84c9dc52d4SCyndy Ishida   const Object *Root = ValOrErr->getAsObject();
85c9dc52d4SCyndy Ishida   if (!Root)
86c9dc52d4SCyndy Ishida     return llvm::opt::InputArgList();
87c9dc52d4SCyndy Ishida 
88c9dc52d4SCyndy Ishida   for (const auto &KV : *Root) {
89c9dc52d4SCyndy Ishida     const Array *ArgList = KV.getSecond().getAsArray();
90c9dc52d4SCyndy Ishida     std::string Label = "-X" + KV.getFirst().str();
91c9dc52d4SCyndy Ishida     if (!ArgList)
92c9dc52d4SCyndy Ishida       return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
93c9dc52d4SCyndy Ishida     for (auto Arg : *ArgList) {
94c9dc52d4SCyndy Ishida       std::optional<StringRef> ArgStr = Arg.getAsString();
95c9dc52d4SCyndy Ishida       if (!ArgStr)
96c9dc52d4SCyndy Ishida         return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
97c9dc52d4SCyndy Ishida       Storage.emplace_back(Label);
98c9dc52d4SCyndy Ishida       Storage.emplace_back(*ArgStr);
99c9dc52d4SCyndy Ishida     }
100c9dc52d4SCyndy Ishida   }
101c9dc52d4SCyndy Ishida 
102c9dc52d4SCyndy Ishida   std::vector<const char *> CArgs(Storage.size());
103c9dc52d4SCyndy Ishida   llvm::for_each(Storage,
104c9dc52d4SCyndy Ishida                  [&CArgs](StringRef Str) { CArgs.emplace_back(Str.data()); });
105c9dc52d4SCyndy Ishida 
106c9dc52d4SCyndy Ishida   unsigned MissingArgIndex, MissingArgCount;
107c9dc52d4SCyndy Ishida   return Table->ParseArgs(CArgs, MissingArgIndex, MissingArgCount);
108c9dc52d4SCyndy Ishida }
109c9dc52d4SCyndy Ishida 
1100a518db9SCyndy Ishida bool Options::processDriverOptions(InputArgList &Args) {
1110a518db9SCyndy Ishida   // Handle inputs.
112feed66f3SCyndy Ishida   for (const StringRef Path : Args.getAllArgValues(drv::OPT_INPUT)) {
113feed66f3SCyndy Ishida     // Assume any input that is not a directory is a filelist.
114feed66f3SCyndy Ishida     // InstallAPI does not accept multiple directories, so retain the last one.
115feed66f3SCyndy Ishida     if (FM->getOptionalDirectoryRef(Path))
116feed66f3SCyndy Ishida       DriverOpts.InputDirectory = Path.str();
117feed66f3SCyndy Ishida     else
118feed66f3SCyndy Ishida       DriverOpts.FileLists.emplace_back(Path.str());
119feed66f3SCyndy Ishida   }
1200a518db9SCyndy Ishida 
1210a518db9SCyndy Ishida   // Handle output.
1220a518db9SCyndy Ishida   SmallString<PATH_MAX> OutputPath;
123c51095f5SCyndy Ishida   if (auto *Arg = Args.getLastArg(drv::OPT_o)) {
1240a518db9SCyndy Ishida     OutputPath = Arg->getValue();
1250a518db9SCyndy Ishida     if (OutputPath != "-")
1260a518db9SCyndy Ishida       FM->makeAbsolutePath(OutputPath);
1270a518db9SCyndy Ishida     DriverOpts.OutputPath = std::string(OutputPath);
1280a518db9SCyndy Ishida   }
129c51095f5SCyndy Ishida   if (DriverOpts.OutputPath.empty()) {
130c51095f5SCyndy Ishida     Diags->Report(diag::err_no_output_file);
131c51095f5SCyndy Ishida     return false;
132c51095f5SCyndy Ishida   }
1330a518db9SCyndy Ishida 
1340a518db9SCyndy Ishida   // Do basic error checking first for mixing -target and -arch options.
135c51095f5SCyndy Ishida   auto *ArgArch = Args.getLastArgNoClaim(drv::OPT_arch);
136c51095f5SCyndy Ishida   auto *ArgTarget = Args.getLastArgNoClaim(drv::OPT_target);
1370a518db9SCyndy Ishida   auto *ArgTargetVariant =
138c24efffaSCyndy Ishida       Args.getLastArgNoClaim(drv::OPT_darwin_target_variant);
1390a518db9SCyndy Ishida   if (ArgArch && (ArgTarget || ArgTargetVariant)) {
1400a518db9SCyndy Ishida     Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
1410a518db9SCyndy Ishida         << ArgArch->getAsString(Args)
1420a518db9SCyndy Ishida         << (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
1430a518db9SCyndy Ishida     return false;
1440a518db9SCyndy Ishida   }
1450a518db9SCyndy Ishida 
146c51095f5SCyndy Ishida   auto *ArgMinTargetOS = Args.getLastArgNoClaim(drv::OPT_mtargetos_EQ);
1470a518db9SCyndy Ishida   if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
1480a518db9SCyndy Ishida     Diags->Report(clang::diag::err_drv_cannot_mix_options)
1490a518db9SCyndy Ishida         << ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
1500a518db9SCyndy Ishida     return false;
1510a518db9SCyndy Ishida   }
1520a518db9SCyndy Ishida 
1530a518db9SCyndy Ishida   // Capture target triples first.
1540a518db9SCyndy Ishida   if (ArgTarget) {
155c51095f5SCyndy Ishida     for (const Arg *A : Args.filtered(drv::OPT_target)) {
156828bf134SCyndy Ishida       A->claim();
157828bf134SCyndy Ishida       llvm::Triple TargetTriple(A->getValue());
1580a518db9SCyndy Ishida       Target TAPITarget = Target(TargetTriple);
1590a518db9SCyndy Ishida       if ((TAPITarget.Arch == AK_unknown) ||
1600a518db9SCyndy Ishida           (TAPITarget.Platform == PLATFORM_UNKNOWN)) {
1610a518db9SCyndy Ishida         Diags->Report(clang::diag::err_drv_unsupported_opt_for_target)
1620a518db9SCyndy Ishida             << "installapi" << TargetTriple.str();
1630a518db9SCyndy Ishida         return false;
1640a518db9SCyndy Ishida       }
1650a518db9SCyndy Ishida       DriverOpts.Targets[TAPITarget] = TargetTriple;
1660a518db9SCyndy Ishida     }
1670a518db9SCyndy Ishida   }
1680a518db9SCyndy Ishida 
169c24efffaSCyndy Ishida   // Capture target variants.
170c24efffaSCyndy Ishida   DriverOpts.Zippered = ArgTargetVariant != nullptr;
171c24efffaSCyndy Ishida   for (Arg *A : Args.filtered(drv::OPT_darwin_target_variant)) {
172c24efffaSCyndy Ishida     A->claim();
173c24efffaSCyndy Ishida     Triple Variant(A->getValue());
174c24efffaSCyndy Ishida     if (Variant.getVendor() != Triple::Apple) {
175c24efffaSCyndy Ishida       Diags->Report(diag::err_unsupported_vendor)
176c24efffaSCyndy Ishida           << Variant.getVendorName() << A->getAsString(Args);
177c24efffaSCyndy Ishida       return false;
178c24efffaSCyndy Ishida     }
179c24efffaSCyndy Ishida 
180c24efffaSCyndy Ishida     switch (Variant.getOS()) {
181c24efffaSCyndy Ishida     default:
182c24efffaSCyndy Ishida       Diags->Report(diag::err_unsupported_os)
183c24efffaSCyndy Ishida           << Variant.getOSName() << A->getAsString(Args);
184c24efffaSCyndy Ishida       return false;
185c24efffaSCyndy Ishida     case Triple::MacOSX:
186c24efffaSCyndy Ishida     case Triple::IOS:
187c24efffaSCyndy Ishida       break;
188c24efffaSCyndy Ishida     }
189c24efffaSCyndy Ishida 
190c24efffaSCyndy Ishida     switch (Variant.getEnvironment()) {
191c24efffaSCyndy Ishida     default:
192c24efffaSCyndy Ishida       Diags->Report(diag::err_unsupported_environment)
193c24efffaSCyndy Ishida           << Variant.getEnvironmentName() << A->getAsString(Args);
194c24efffaSCyndy Ishida       return false;
195c24efffaSCyndy Ishida     case Triple::UnknownEnvironment:
196c24efffaSCyndy Ishida     case Triple::MacABI:
197c24efffaSCyndy Ishida       break;
198c24efffaSCyndy Ishida     }
199c24efffaSCyndy Ishida 
200c24efffaSCyndy Ishida     Target TAPIVariant(Variant);
201c24efffaSCyndy Ishida     // See if there is a matching --target option for this --target-variant
202c24efffaSCyndy Ishida     // option.
203c24efffaSCyndy Ishida     auto It = find_if(DriverOpts.Targets, [&](const auto &T) {
204c24efffaSCyndy Ishida       return (T.first.Arch == TAPIVariant.Arch) &&
205c24efffaSCyndy Ishida              (T.first.Platform != PlatformType::PLATFORM_UNKNOWN);
206c24efffaSCyndy Ishida     });
207c24efffaSCyndy Ishida 
208c24efffaSCyndy Ishida     if (It == DriverOpts.Targets.end()) {
209c24efffaSCyndy Ishida       Diags->Report(diag::err_no_matching_target) << Variant.str();
210c24efffaSCyndy Ishida       return false;
211c24efffaSCyndy Ishida     }
212c24efffaSCyndy Ishida 
213c24efffaSCyndy Ishida     DriverOpts.Targets[TAPIVariant] = Variant;
214c24efffaSCyndy Ishida   }
215c24efffaSCyndy Ishida 
216c51095f5SCyndy Ishida   DriverOpts.Verbose = Args.hasArgNoClaim(drv::OPT_v);
217c6cbf81cSCyndy Ishida 
2180a518db9SCyndy Ishida   return true;
2190a518db9SCyndy Ishida }
2200a518db9SCyndy Ishida 
22127b2d7d4SCyndy Ishida bool Options::processInstallAPIXOptions(InputArgList &Args) {
22227b2d7d4SCyndy Ishida   for (arg_iterator It = Args.begin(), End = Args.end(); It != End; ++It) {
223062f6fe3SCyndy Ishida     Arg *A = *It;
224062f6fe3SCyndy Ishida     if (A->getOption().matches(OPT_Xarch__)) {
22527b2d7d4SCyndy Ishida       if (!processXarchOption(Args, It))
22627b2d7d4SCyndy Ishida         return false;
227062f6fe3SCyndy Ishida       continue;
228062f6fe3SCyndy Ishida     } else if (A->getOption().matches(OPT_Xplatform__)) {
229062f6fe3SCyndy Ishida       if (!processXplatformOption(Args, It))
230062f6fe3SCyndy Ishida         return false;
231062f6fe3SCyndy Ishida       continue;
232062f6fe3SCyndy Ishida     } else if (A->getOption().matches(OPT_Xproject)) {
233062f6fe3SCyndy Ishida       if (!processXprojectOption(Args, It))
234062f6fe3SCyndy Ishida         return false;
235062f6fe3SCyndy Ishida       continue;
236062f6fe3SCyndy Ishida     } else if (!A->getOption().matches(OPT_X__))
237062f6fe3SCyndy Ishida       continue;
238062f6fe3SCyndy Ishida 
239062f6fe3SCyndy Ishida     // Handle any user defined labels.
240062f6fe3SCyndy Ishida     const StringRef Label = A->getValue(0);
241062f6fe3SCyndy Ishida 
242062f6fe3SCyndy Ishida     // Ban "public" and "private" labels.
243062f6fe3SCyndy Ishida     if ((Label.lower() == "public") || (Label.lower() == "private")) {
244062f6fe3SCyndy Ishida       Diags->Report(diag::err_invalid_label) << Label;
245062f6fe3SCyndy Ishida       return false;
24627b2d7d4SCyndy Ishida     }
247062f6fe3SCyndy Ishida 
248062f6fe3SCyndy Ishida     auto NextIt = std::next(It);
249062f6fe3SCyndy Ishida     if (NextIt == End) {
250062f6fe3SCyndy Ishida       Diags->Report(clang::diag::err_drv_missing_argument)
251062f6fe3SCyndy Ishida           << A->getAsString(Args) << 1;
252062f6fe3SCyndy Ishida       return false;
25327b2d7d4SCyndy Ishida     }
254062f6fe3SCyndy Ishida     Arg *NextA = *NextIt;
255062f6fe3SCyndy Ishida     switch ((ID)NextA->getOption().getID()) {
256062f6fe3SCyndy Ishida     case OPT_D:
257062f6fe3SCyndy Ishida     case OPT_U:
258062f6fe3SCyndy Ishida       break;
259062f6fe3SCyndy Ishida     default:
260062f6fe3SCyndy Ishida       Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
261062f6fe3SCyndy Ishida           << A->getAsString(Args) << NextA->getAsString(Args);
262062f6fe3SCyndy Ishida       return false;
263062f6fe3SCyndy Ishida     }
264062f6fe3SCyndy Ishida     const StringRef ASpelling = NextA->getSpelling();
265062f6fe3SCyndy Ishida     const auto &AValues = NextA->getValues();
266062f6fe3SCyndy Ishida     if (AValues.empty())
267062f6fe3SCyndy Ishida       FEOpts.UniqueArgs[Label].emplace_back(ASpelling.str());
268062f6fe3SCyndy Ishida     else
269062f6fe3SCyndy Ishida       for (const StringRef Val : AValues)
270062f6fe3SCyndy Ishida         FEOpts.UniqueArgs[Label].emplace_back((ASpelling + Val).str());
271062f6fe3SCyndy Ishida 
272062f6fe3SCyndy Ishida     A->claim();
273062f6fe3SCyndy Ishida     NextA->claim();
274062f6fe3SCyndy Ishida   }
275062f6fe3SCyndy Ishida 
276062f6fe3SCyndy Ishida   return true;
277062f6fe3SCyndy Ishida }
278062f6fe3SCyndy Ishida 
279062f6fe3SCyndy Ishida bool Options::processXplatformOption(InputArgList &Args, arg_iterator Curr) {
280062f6fe3SCyndy Ishida   Arg *A = *Curr;
281062f6fe3SCyndy Ishida 
282062f6fe3SCyndy Ishida   PlatformType Platform = getPlatformFromName(A->getValue(0));
283062f6fe3SCyndy Ishida   if (Platform == PLATFORM_UNKNOWN) {
284062f6fe3SCyndy Ishida     Diags->Report(diag::err_unsupported_os)
285062f6fe3SCyndy Ishida         << getPlatformName(Platform) << A->getAsString(Args);
286062f6fe3SCyndy Ishida     return false;
287062f6fe3SCyndy Ishida   }
288062f6fe3SCyndy Ishida   auto NextIt = std::next(Curr);
289062f6fe3SCyndy Ishida   if (NextIt == Args.end()) {
290062f6fe3SCyndy Ishida     Diags->Report(diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
291062f6fe3SCyndy Ishida     return false;
292062f6fe3SCyndy Ishida   }
293062f6fe3SCyndy Ishida 
294062f6fe3SCyndy Ishida   Arg *NextA = *NextIt;
295062f6fe3SCyndy Ishida   switch ((ID)NextA->getOption().getID()) {
296062f6fe3SCyndy Ishida   case OPT_iframework:
297062f6fe3SCyndy Ishida     FEOpts.SystemFwkPaths.emplace_back(NextA->getValue(), Platform);
298062f6fe3SCyndy Ishida     break;
299062f6fe3SCyndy Ishida   default:
300062f6fe3SCyndy Ishida     Diags->Report(diag::err_drv_invalid_argument_to_option)
301062f6fe3SCyndy Ishida         << A->getAsString(Args) << NextA->getAsString(Args);
302062f6fe3SCyndy Ishida     return false;
303062f6fe3SCyndy Ishida   }
304062f6fe3SCyndy Ishida 
305062f6fe3SCyndy Ishida   A->claim();
306062f6fe3SCyndy Ishida   NextA->claim();
307062f6fe3SCyndy Ishida 
308062f6fe3SCyndy Ishida   return true;
309062f6fe3SCyndy Ishida }
310062f6fe3SCyndy Ishida 
311062f6fe3SCyndy Ishida bool Options::processXprojectOption(InputArgList &Args, arg_iterator Curr) {
312062f6fe3SCyndy Ishida   Arg *A = *Curr;
313062f6fe3SCyndy Ishida   auto NextIt = std::next(Curr);
314062f6fe3SCyndy Ishida   if (NextIt == Args.end()) {
315062f6fe3SCyndy Ishida     Diags->Report(diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
316062f6fe3SCyndy Ishida     return false;
317062f6fe3SCyndy Ishida   }
318062f6fe3SCyndy Ishida 
319062f6fe3SCyndy Ishida   Arg *NextA = *NextIt;
320062f6fe3SCyndy Ishida   switch ((ID)NextA->getOption().getID()) {
321062f6fe3SCyndy Ishida   case OPT_fobjc_arc:
322062f6fe3SCyndy Ishida   case OPT_fmodules:
323062f6fe3SCyndy Ishida   case OPT_fmodules_cache_path:
324062f6fe3SCyndy Ishida   case OPT_include_:
325062f6fe3SCyndy Ishida   case OPT_fvisibility_EQ:
326062f6fe3SCyndy Ishida     break;
327062f6fe3SCyndy Ishida   default:
328062f6fe3SCyndy Ishida     Diags->Report(diag::err_drv_argument_not_allowed_with)
329062f6fe3SCyndy Ishida         << A->getAsString(Args) << NextA->getAsString(Args);
330062f6fe3SCyndy Ishida     return false;
331062f6fe3SCyndy Ishida   }
332062f6fe3SCyndy Ishida 
333504cf554SCyndy Ishida   std::string ArgString = NextA->getSpelling().str();
334504cf554SCyndy Ishida   for (const StringRef Val : NextA->getValues())
335504cf554SCyndy Ishida     ArgString += Val.str();
336504cf554SCyndy Ishida 
337504cf554SCyndy Ishida   ProjectLevelArgs.push_back(ArgString);
338062f6fe3SCyndy Ishida   A->claim();
339062f6fe3SCyndy Ishida   NextA->claim();
34027b2d7d4SCyndy Ishida 
34127b2d7d4SCyndy Ishida   return true;
34227b2d7d4SCyndy Ishida }
34327b2d7d4SCyndy Ishida 
34427b2d7d4SCyndy Ishida bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
34527b2d7d4SCyndy Ishida   Arg *CurrArg = *Curr;
34627b2d7d4SCyndy Ishida   Architecture Arch = getArchitectureFromName(CurrArg->getValue(0));
34727b2d7d4SCyndy Ishida   if (Arch == AK_unknown) {
34827b2d7d4SCyndy Ishida     Diags->Report(diag::err_drv_invalid_arch_name)
34927b2d7d4SCyndy Ishida         << CurrArg->getAsString(Args);
35027b2d7d4SCyndy Ishida     return false;
35127b2d7d4SCyndy Ishida   }
35227b2d7d4SCyndy Ishida 
35327b2d7d4SCyndy Ishida   auto NextIt = std::next(Curr);
35427b2d7d4SCyndy Ishida   if (NextIt == Args.end()) {
35527b2d7d4SCyndy Ishida     Diags->Report(diag::err_drv_missing_argument)
35627b2d7d4SCyndy Ishida         << CurrArg->getAsString(Args) << 1;
35727b2d7d4SCyndy Ishida     return false;
35827b2d7d4SCyndy Ishida   }
35927b2d7d4SCyndy Ishida 
36027b2d7d4SCyndy Ishida   // InstallAPI has a limited understanding of supported Xarch options.
36127b2d7d4SCyndy Ishida   // Currently this is restricted to linker inputs.
36227b2d7d4SCyndy Ishida   const Arg *NextArg = *NextIt;
36327b2d7d4SCyndy Ishida   switch (NextArg->getOption().getID()) {
36427b2d7d4SCyndy Ishida   case OPT_allowable_client:
36527b2d7d4SCyndy Ishida   case OPT_reexport_l:
36627b2d7d4SCyndy Ishida   case OPT_reexport_framework:
36727b2d7d4SCyndy Ishida   case OPT_reexport_library:
36827b2d7d4SCyndy Ishida   case OPT_rpath:
36927b2d7d4SCyndy Ishida     break;
37027b2d7d4SCyndy Ishida   default:
37127b2d7d4SCyndy Ishida     Diags->Report(diag::err_drv_invalid_argument_to_option)
37227b2d7d4SCyndy Ishida         << NextArg->getAsString(Args) << CurrArg->getAsString(Args);
37327b2d7d4SCyndy Ishida     return false;
37427b2d7d4SCyndy Ishida   }
37527b2d7d4SCyndy Ishida 
37627b2d7d4SCyndy Ishida   ArgToArchMap[NextArg] = Arch;
37727b2d7d4SCyndy Ishida   CurrArg->claim();
37827b2d7d4SCyndy Ishida 
37927b2d7d4SCyndy Ishida   return true;
38027b2d7d4SCyndy Ishida }
38127b2d7d4SCyndy Ishida 
382c9dc52d4SCyndy Ishida bool Options::processOptionList(InputArgList &Args,
383c9dc52d4SCyndy Ishida                                 llvm::opt::OptTable *Table) {
384c9dc52d4SCyndy Ishida   Arg *A = Args.getLastArg(OPT_option_list);
385c9dc52d4SCyndy Ishida   if (!A)
386c9dc52d4SCyndy Ishida     return true;
387c9dc52d4SCyndy Ishida 
388c9dc52d4SCyndy Ishida   const StringRef Path = A->getValue(0);
389c9dc52d4SCyndy Ishida   auto InputOrErr = FM->getBufferForFile(Path);
390c9dc52d4SCyndy Ishida   if (auto Err = InputOrErr.getError()) {
391c9dc52d4SCyndy Ishida     Diags->Report(diag::err_cannot_open_file) << Path << Err.message();
392c9dc52d4SCyndy Ishida     return false;
393c9dc52d4SCyndy Ishida   }
394c9dc52d4SCyndy Ishida   // Backing storage referenced for argument processing.
395c9dc52d4SCyndy Ishida   std::vector<std::string> Storage;
396c9dc52d4SCyndy Ishida   auto ArgsOrErr =
397c9dc52d4SCyndy Ishida       getArgListFromJSON((*InputOrErr)->getBuffer(), Table, Storage);
398c9dc52d4SCyndy Ishida 
399c9dc52d4SCyndy Ishida   if (auto Err = ArgsOrErr.takeError()) {
400c9dc52d4SCyndy Ishida     Diags->Report(diag::err_cannot_read_input_list)
401c9dc52d4SCyndy Ishida         << "option" << Path << toString(std::move(Err));
402c9dc52d4SCyndy Ishida     return false;
403c9dc52d4SCyndy Ishida   }
404c9dc52d4SCyndy Ishida   return processInstallAPIXOptions(*ArgsOrErr);
405c9dc52d4SCyndy Ishida }
406c9dc52d4SCyndy Ishida 
4070a518db9SCyndy Ishida bool Options::processLinkerOptions(InputArgList &Args) {
408c51095f5SCyndy Ishida   // Handle required arguments.
409c51095f5SCyndy Ishida   if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
4100a518db9SCyndy Ishida     LinkerOpts.InstallName = A->getValue();
411c51095f5SCyndy Ishida   if (LinkerOpts.InstallName.empty()) {
412c51095f5SCyndy Ishida     Diags->Report(diag::err_no_install_name);
413c51095f5SCyndy Ishida     return false;
414c51095f5SCyndy Ishida   }
4150a518db9SCyndy Ishida 
4160a518db9SCyndy Ishida   // Defaulted or optional arguments.
417c51095f5SCyndy Ishida   if (auto *Arg = Args.getLastArg(drv::OPT_current__version))
4180a518db9SCyndy Ishida     LinkerOpts.CurrentVersion.parse64(Arg->getValue());
4190a518db9SCyndy Ishida 
420c51095f5SCyndy Ishida   if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
421b058b7e6SCyndy Ishida     LinkerOpts.CompatVersion.parse64(Arg->getValue());
422b058b7e6SCyndy Ishida 
42327b2d7d4SCyndy Ishida   if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
42427b2d7d4SCyndy Ishida     LinkerOpts.CompatVersion.parse64(Arg->getValue());
42527b2d7d4SCyndy Ishida 
42627b2d7d4SCyndy Ishida   if (auto *Arg = Args.getLastArg(drv::OPT_umbrella))
42727b2d7d4SCyndy Ishida     LinkerOpts.ParentUmbrella = Arg->getValue();
42827b2d7d4SCyndy Ishida 
429c51095f5SCyndy Ishida   LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);
4300a518db9SCyndy Ishida 
4314c18681aSCyndy Ishida   for (auto *Arg : Args.filtered(drv::OPT_alias_list)) {
4324c18681aSCyndy Ishida     LinkerOpts.AliasLists.emplace_back(Arg->getValue());
4334c18681aSCyndy Ishida     Arg->claim();
4344c18681aSCyndy Ishida   }
4354c18681aSCyndy Ishida 
436c51095f5SCyndy Ishida   LinkerOpts.AppExtensionSafe = Args.hasFlag(
437c51095f5SCyndy Ishida       drv::OPT_fapplication_extension, drv::OPT_fno_application_extension,
4380a518db9SCyndy Ishida       /*Default=*/LinkerOpts.AppExtensionSafe);
4390a518db9SCyndy Ishida 
4400a518db9SCyndy Ishida   if (::getenv("LD_NO_ENCRYPT") != nullptr)
4410a518db9SCyndy Ishida     LinkerOpts.AppExtensionSafe = true;
4420a518db9SCyndy Ishida 
4430a518db9SCyndy Ishida   if (::getenv("LD_APPLICATION_EXTENSION_SAFE") != nullptr)
4440a518db9SCyndy Ishida     LinkerOpts.AppExtensionSafe = true;
44527b2d7d4SCyndy Ishida 
44627b2d7d4SCyndy Ishida   // Capture library paths.
44727b2d7d4SCyndy Ishida   PathSeq LibraryPaths;
44827b2d7d4SCyndy Ishida   for (const Arg *A : Args.filtered(drv::OPT_L)) {
44927b2d7d4SCyndy Ishida     LibraryPaths.emplace_back(A->getValue());
45027b2d7d4SCyndy Ishida     A->claim();
45127b2d7d4SCyndy Ishida   }
45227b2d7d4SCyndy Ishida 
45327b2d7d4SCyndy Ishida   if (!LibraryPaths.empty())
45427b2d7d4SCyndy Ishida     LinkerOpts.LibPaths = std::move(LibraryPaths);
45527b2d7d4SCyndy Ishida 
4560a518db9SCyndy Ishida   return true;
4570a518db9SCyndy Ishida }
4580a518db9SCyndy Ishida 
45927b2d7d4SCyndy Ishida // NOTE: Do not claim any arguments, as they will be passed along for CC1
4602c93beccSCyndy Ishida // invocations.
46127b2d7d4SCyndy Ishida bool Options::processFrontendOptions(InputArgList &Args) {
46227b2d7d4SCyndy Ishida   // Capture language mode.
463c51095f5SCyndy Ishida   if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
4642c93beccSCyndy Ishida     FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
4652c93beccSCyndy Ishida                           .Case("c", clang::Language::C)
4662c93beccSCyndy Ishida                           .Case("c++", clang::Language::CXX)
4672c93beccSCyndy Ishida                           .Case("objective-c", clang::Language::ObjC)
4682c93beccSCyndy Ishida                           .Case("objective-c++", clang::Language::ObjCXX)
4692c93beccSCyndy Ishida                           .Default(clang::Language::Unknown);
4702c93beccSCyndy Ishida 
4712c93beccSCyndy Ishida     if (FEOpts.LangMode == clang::Language::Unknown) {
4722c93beccSCyndy Ishida       Diags->Report(clang::diag::err_drv_invalid_value)
4732c93beccSCyndy Ishida           << A->getAsString(Args) << A->getValue();
4742c93beccSCyndy Ishida       return false;
4752c93beccSCyndy Ishida     }
4762c93beccSCyndy Ishida   }
477c51095f5SCyndy Ishida   for (auto *A : Args.filtered(drv::OPT_ObjC, drv::OPT_ObjCXX)) {
478c51095f5SCyndy Ishida     if (A->getOption().matches(drv::OPT_ObjC))
4792c93beccSCyndy Ishida       FEOpts.LangMode = clang::Language::ObjC;
4802c93beccSCyndy Ishida     else
4812c93beccSCyndy Ishida       FEOpts.LangMode = clang::Language::ObjCXX;
4822c93beccSCyndy Ishida   }
4832c93beccSCyndy Ishida 
48427b2d7d4SCyndy Ishida   // Capture Sysroot.
48527b2d7d4SCyndy Ishida   if (const Arg *A = Args.getLastArgNoClaim(drv::OPT_isysroot)) {
48627b2d7d4SCyndy Ishida     SmallString<PATH_MAX> Path(A->getValue());
48727b2d7d4SCyndy Ishida     FM->makeAbsolutePath(Path);
48827b2d7d4SCyndy Ishida     if (!FM->getOptionalDirectoryRef(Path)) {
48927b2d7d4SCyndy Ishida       Diags->Report(diag::err_missing_sysroot) << Path;
49027b2d7d4SCyndy Ishida       return false;
49127b2d7d4SCyndy Ishida     }
49227b2d7d4SCyndy Ishida     FEOpts.ISysroot = std::string(Path);
49327b2d7d4SCyndy Ishida   } else if (FEOpts.ISysroot.empty()) {
49427b2d7d4SCyndy Ishida     // Mirror CLANG and obtain the isysroot from the SDKROOT environment
49527b2d7d4SCyndy Ishida     // variable, if it wasn't defined by the  command line.
49627b2d7d4SCyndy Ishida     if (auto *Env = ::getenv("SDKROOT")) {
49727b2d7d4SCyndy Ishida       if (StringRef(Env) != "/" && llvm::sys::path::is_absolute(Env) &&
49827b2d7d4SCyndy Ishida           FM->getOptionalFileRef(Env))
49927b2d7d4SCyndy Ishida         FEOpts.ISysroot = Env;
50027b2d7d4SCyndy Ishida     }
50127b2d7d4SCyndy Ishida   }
50227b2d7d4SCyndy Ishida 
503062f6fe3SCyndy Ishida   // Capture system frameworks for all platforms.
50427b2d7d4SCyndy Ishida   for (const Arg *A : Args.filtered(drv::OPT_iframework))
505062f6fe3SCyndy Ishida     FEOpts.SystemFwkPaths.emplace_back(A->getValue(),
506062f6fe3SCyndy Ishida                                        std::optional<PlatformType>{});
50727b2d7d4SCyndy Ishida 
50827b2d7d4SCyndy Ishida   // Capture framework paths.
50927b2d7d4SCyndy Ishida   PathSeq FrameworkPaths;
51027b2d7d4SCyndy Ishida   for (const Arg *A : Args.filtered(drv::OPT_F))
51127b2d7d4SCyndy Ishida     FrameworkPaths.emplace_back(A->getValue());
51227b2d7d4SCyndy Ishida 
51327b2d7d4SCyndy Ishida   if (!FrameworkPaths.empty())
51427b2d7d4SCyndy Ishida     FEOpts.FwkPaths = std::move(FrameworkPaths);
51527b2d7d4SCyndy Ishida 
51627b2d7d4SCyndy Ishida   // Add default framework/library paths.
51727b2d7d4SCyndy Ishida   PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
51827b2d7d4SCyndy Ishida   PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
51927b2d7d4SCyndy Ishida                                    "/System/Library/Frameworks"};
52027b2d7d4SCyndy Ishida 
52127b2d7d4SCyndy Ishida   for (const StringRef LibPath : DefaultLibraryPaths) {
52227b2d7d4SCyndy Ishida     SmallString<PATH_MAX> Path(FEOpts.ISysroot);
52327b2d7d4SCyndy Ishida     sys::path::append(Path, LibPath);
52427b2d7d4SCyndy Ishida     LinkerOpts.LibPaths.emplace_back(Path.str());
52527b2d7d4SCyndy Ishida   }
52627b2d7d4SCyndy Ishida   for (const StringRef FwkPath : DefaultFrameworkPaths) {
52727b2d7d4SCyndy Ishida     SmallString<PATH_MAX> Path(FEOpts.ISysroot);
52827b2d7d4SCyndy Ishida     sys::path::append(Path, FwkPath);
529062f6fe3SCyndy Ishida     FEOpts.SystemFwkPaths.emplace_back(Path.str(),
530062f6fe3SCyndy Ishida                                        std::optional<PlatformType>{});
53127b2d7d4SCyndy Ishida   }
53227b2d7d4SCyndy Ishida 
5332c93beccSCyndy Ishida   return true;
5342c93beccSCyndy Ishida }
5352c93beccSCyndy Ishida 
536487720fcSCyndy Ishida bool Options::addFilePaths(InputArgList &Args, PathSeq &Headers,
537487720fcSCyndy Ishida                            OptSpecifier ID) {
538487720fcSCyndy Ishida   for (const StringRef Path : Args.getAllArgValues(ID)) {
539b1aea98cSJan Svoboda     if ((bool)FM->getOptionalDirectoryRef(Path, /*CacheFailure=*/false)) {
540487720fcSCyndy Ishida       auto InputHeadersOrErr = enumerateFiles(*FM, Path);
541487720fcSCyndy Ishida       if (!InputHeadersOrErr) {
542487720fcSCyndy Ishida         Diags->Report(diag::err_cannot_open_file)
543487720fcSCyndy Ishida             << Path << toString(InputHeadersOrErr.takeError());
544487720fcSCyndy Ishida         return false;
545487720fcSCyndy Ishida       }
546487720fcSCyndy Ishida       // Sort headers to ensure deterministic behavior.
547487720fcSCyndy Ishida       sort(*InputHeadersOrErr);
54879dca25fSCyndy Ishida       for (StringRef H : *InputHeadersOrErr)
549487720fcSCyndy Ishida         Headers.emplace_back(std::move(H));
550487720fcSCyndy Ishida     } else
551487720fcSCyndy Ishida       Headers.emplace_back(Path);
552487720fcSCyndy Ishida   }
553487720fcSCyndy Ishida   return true;
554487720fcSCyndy Ishida }
555487720fcSCyndy Ishida 
556c51095f5SCyndy Ishida std::vector<const char *>
557c51095f5SCyndy Ishida Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
558c51095f5SCyndy Ishida   std::unique_ptr<llvm::opt::OptTable> Table;
559c51095f5SCyndy Ishida   Table.reset(createDriverOptTable());
560c51095f5SCyndy Ishida 
561c51095f5SCyndy Ishida   unsigned MissingArgIndex, MissingArgCount;
562c51095f5SCyndy Ishida   auto ParsedArgs = Table->ParseArgs(Args.slice(1), MissingArgIndex,
563c51095f5SCyndy Ishida                                      MissingArgCount, Visibility());
564c51095f5SCyndy Ishida 
565c51095f5SCyndy Ishida   // Capture InstallAPI only driver options.
56627b2d7d4SCyndy Ishida   if (!processInstallAPIXOptions(ParsedArgs))
56727b2d7d4SCyndy Ishida     return {};
56827b2d7d4SCyndy Ishida 
569c9dc52d4SCyndy Ishida   if (!processOptionList(ParsedArgs, Table.get()))
570c9dc52d4SCyndy Ishida     return {};
571c9dc52d4SCyndy Ishida 
572c51095f5SCyndy Ishida   DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);
573c51095f5SCyndy Ishida 
574c51095f5SCyndy Ishida   if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
575c51095f5SCyndy Ishida     DriverOpts.OutFT = TextAPIWriter::parseFileType(A->getValue());
576c51095f5SCyndy Ishida     if (DriverOpts.OutFT == FileType::Invalid) {
577c51095f5SCyndy Ishida       Diags->Report(clang::diag::err_drv_invalid_value)
578c51095f5SCyndy Ishida           << A->getAsString(ParsedArgs) << A->getValue();
579c51095f5SCyndy Ishida       return {};
580c51095f5SCyndy Ishida     }
581c51095f5SCyndy Ishida   }
582c51095f5SCyndy Ishida 
583c51095f5SCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_mode_EQ)) {
584c51095f5SCyndy Ishida     DriverOpts.VerifyMode =
585c51095f5SCyndy Ishida         StringSwitch<VerificationMode>(A->getValue())
586c51095f5SCyndy Ishida             .Case("ErrorsOnly", VerificationMode::ErrorsOnly)
587c51095f5SCyndy Ishida             .Case("ErrorsAndWarnings", VerificationMode::ErrorsAndWarnings)
588c51095f5SCyndy Ishida             .Case("Pedantic", VerificationMode::Pedantic)
589c51095f5SCyndy Ishida             .Default(VerificationMode::Invalid);
590c51095f5SCyndy Ishida 
591c51095f5SCyndy Ishida     if (DriverOpts.VerifyMode == VerificationMode::Invalid) {
592c51095f5SCyndy Ishida       Diags->Report(clang::diag::err_drv_invalid_value)
593c51095f5SCyndy Ishida           << A->getAsString(ParsedArgs) << A->getValue();
594c51095f5SCyndy Ishida       return {};
595c51095f5SCyndy Ishida     }
596c51095f5SCyndy Ishida   }
597c51095f5SCyndy Ishida 
598c51095f5SCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_against))
599c51095f5SCyndy Ishida     DriverOpts.DylibToVerify = A->getValue();
600c51095f5SCyndy Ishida 
601a4de589dSCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_dsym))
602a4de589dSCyndy Ishida     DriverOpts.DSYMPath = A->getValue();
603a4de589dSCyndy Ishida 
60427b2d7d4SCyndy Ishida   DriverOpts.TraceLibraryLocation = ParsedArgs.hasArg(OPT_t);
60527b2d7d4SCyndy Ishida 
60627b2d7d4SCyndy Ishida   // Linker options not handled by clang driver.
60727b2d7d4SCyndy Ishida   LinkerOpts.OSLibNotForSharedCache =
60827b2d7d4SCyndy Ishida       ParsedArgs.hasArg(OPT_not_for_dyld_shared_cache);
60927b2d7d4SCyndy Ishida 
61027b2d7d4SCyndy Ishida   for (const Arg *A : ParsedArgs.filtered(OPT_allowable_client)) {
61127b2d7d4SCyndy Ishida     LinkerOpts.AllowableClients[A->getValue()] =
61227b2d7d4SCyndy Ishida         ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
61327b2d7d4SCyndy Ishida     A->claim();
61427b2d7d4SCyndy Ishida   }
61527b2d7d4SCyndy Ishida 
61627b2d7d4SCyndy Ishida   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_l)) {
61727b2d7d4SCyndy Ishida     LinkerOpts.ReexportedLibraries[A->getValue()] =
61827b2d7d4SCyndy Ishida         ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
61927b2d7d4SCyndy Ishida     A->claim();
62027b2d7d4SCyndy Ishida   }
62127b2d7d4SCyndy Ishida 
62227b2d7d4SCyndy Ishida   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_library)) {
62327b2d7d4SCyndy Ishida     LinkerOpts.ReexportedLibraryPaths[A->getValue()] =
62427b2d7d4SCyndy Ishida         ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
62527b2d7d4SCyndy Ishida     A->claim();
62627b2d7d4SCyndy Ishida   }
62727b2d7d4SCyndy Ishida 
62827b2d7d4SCyndy Ishida   for (const Arg *A : ParsedArgs.filtered(OPT_reexport_framework)) {
62927b2d7d4SCyndy Ishida     LinkerOpts.ReexportedFrameworks[A->getValue()] =
63027b2d7d4SCyndy Ishida         ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
63127b2d7d4SCyndy Ishida     A->claim();
63227b2d7d4SCyndy Ishida   }
63327b2d7d4SCyndy Ishida 
63427b2d7d4SCyndy Ishida   for (const Arg *A : ParsedArgs.filtered(OPT_rpath)) {
63527b2d7d4SCyndy Ishida     LinkerOpts.RPaths[A->getValue()] =
63627b2d7d4SCyndy Ishida         ArgToArchMap.count(A) ? ArgToArchMap[A] : ArchitectureSet();
63727b2d7d4SCyndy Ishida     A->claim();
63827b2d7d4SCyndy Ishida   }
63927b2d7d4SCyndy Ishida 
640487720fcSCyndy Ishida   // Handle exclude & extra header directories or files.
641487720fcSCyndy Ishida   auto handleAdditionalInputArgs = [&](PathSeq &Headers,
642487720fcSCyndy Ishida                                        clang::installapi::ID OptID) {
643487720fcSCyndy Ishida     if (ParsedArgs.hasArgNoClaim(OptID))
644487720fcSCyndy Ishida       Headers.clear();
645487720fcSCyndy Ishida     return addFilePaths(ParsedArgs, Headers, OptID);
646487720fcSCyndy Ishida   };
647487720fcSCyndy Ishida 
648487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExtraPublicHeaders,
649487720fcSCyndy Ishida                                  OPT_extra_public_header))
650487720fcSCyndy Ishida     return {};
651487720fcSCyndy Ishida 
652487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExtraPrivateHeaders,
653487720fcSCyndy Ishida                                  OPT_extra_private_header))
654487720fcSCyndy Ishida     return {};
655487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExtraProjectHeaders,
656487720fcSCyndy Ishida                                  OPT_extra_project_header))
657487720fcSCyndy Ishida     return {};
658487720fcSCyndy Ishida 
659487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExcludePublicHeaders,
660487720fcSCyndy Ishida                                  OPT_exclude_public_header))
661487720fcSCyndy Ishida     return {};
662487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExcludePrivateHeaders,
663487720fcSCyndy Ishida                                  OPT_exclude_private_header))
664487720fcSCyndy Ishida     return {};
665487720fcSCyndy Ishida   if (!handleAdditionalInputArgs(DriverOpts.ExcludeProjectHeaders,
666487720fcSCyndy Ishida                                  OPT_exclude_project_header))
667487720fcSCyndy Ishida     return {};
668487720fcSCyndy Ishida 
6696ad1cf3bSCyndy Ishida   // Handle umbrella headers.
6706ad1cf3bSCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_public_umbrella_header))
6716ad1cf3bSCyndy Ishida     DriverOpts.PublicUmbrellaHeader = A->getValue();
6726ad1cf3bSCyndy Ishida 
6736ad1cf3bSCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_private_umbrella_header))
6746ad1cf3bSCyndy Ishida     DriverOpts.PrivateUmbrellaHeader = A->getValue();
6756ad1cf3bSCyndy Ishida 
6766ad1cf3bSCyndy Ishida   if (const Arg *A = ParsedArgs.getLastArg(OPT_project_umbrella_header))
6776ad1cf3bSCyndy Ishida     DriverOpts.ProjectUmbrellaHeader = A->getValue();
6786ad1cf3bSCyndy Ishida 
679c51095f5SCyndy Ishida   /// Any unclaimed arguments should be forwarded to the clang driver.
680c51095f5SCyndy Ishida   std::vector<const char *> ClangDriverArgs(ParsedArgs.size());
681c51095f5SCyndy Ishida   for (const Arg *A : ParsedArgs) {
682c51095f5SCyndy Ishida     if (A->isClaimed())
683c51095f5SCyndy Ishida       continue;
684062f6fe3SCyndy Ishida     // Forward along unclaimed but overlapping arguments to the clang driver.
685062f6fe3SCyndy Ishida     if (A->getOption().getID() > (unsigned)OPT_UNKNOWN) {
686062f6fe3SCyndy Ishida       ClangDriverArgs.push_back(A->getSpelling().data());
687062f6fe3SCyndy Ishida     } else
688c51095f5SCyndy Ishida       llvm::copy(A->getValues(), std::back_inserter(ClangDriverArgs));
689c51095f5SCyndy Ishida   }
690c51095f5SCyndy Ishida   return ClangDriverArgs;
691c51095f5SCyndy Ishida }
692c51095f5SCyndy Ishida 
6930a518db9SCyndy Ishida Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
694c51095f5SCyndy Ishida                  ArrayRef<const char *> Args, const StringRef ProgName)
6950a518db9SCyndy Ishida     : Diags(&Diag), FM(FM) {
696c51095f5SCyndy Ishida 
697c51095f5SCyndy Ishida   // First process InstallAPI specific options.
698c51095f5SCyndy Ishida   auto DriverArgs = processAndFilterOutInstallAPIOptions(Args);
699c51095f5SCyndy Ishida   if (Diags->hasErrorOccurred())
700c51095f5SCyndy Ishida     return;
701c51095f5SCyndy Ishida 
702c51095f5SCyndy Ishida   // Set up driver to parse remaining input arguments.
703c51095f5SCyndy Ishida   clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
704c51095f5SCyndy Ishida                                *Diags, "clang installapi tool");
705c51095f5SCyndy Ishida   auto TargetAndMode =
706c51095f5SCyndy Ishida       clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
707c51095f5SCyndy Ishida   Driver.setTargetAndMode(TargetAndMode);
708c51095f5SCyndy Ishida   bool HasError = false;
709c51095f5SCyndy Ishida   llvm::opt::InputArgList ArgList =
710c51095f5SCyndy Ishida       Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
711c51095f5SCyndy Ishida   if (HasError)
712c51095f5SCyndy Ishida     return;
713c51095f5SCyndy Ishida   Driver.setCheckInputsExist(false);
714c51095f5SCyndy Ishida 
7150a518db9SCyndy Ishida   if (!processDriverOptions(ArgList))
7160a518db9SCyndy Ishida     return;
7170a518db9SCyndy Ishida 
7180a518db9SCyndy Ishida   if (!processLinkerOptions(ArgList))
7190a518db9SCyndy Ishida     return;
720c6cbf81cSCyndy Ishida 
7212c93beccSCyndy Ishida   if (!processFrontendOptions(ArgList))
7222c93beccSCyndy Ishida     return;
7232c93beccSCyndy Ishida 
72427b2d7d4SCyndy Ishida   // After all InstallAPI necessary arguments have been collected. Go back and
72527b2d7d4SCyndy Ishida   // assign values that were unknown before the clang driver opt table was used.
72627b2d7d4SCyndy Ishida   ArchitectureSet AllArchs;
72727b2d7d4SCyndy Ishida   llvm::for_each(DriverOpts.Targets,
72827b2d7d4SCyndy Ishida                  [&AllArchs](const auto &T) { AllArchs.set(T.first.Arch); });
72927b2d7d4SCyndy Ishida   auto assignDefaultLibAttrs = [&AllArchs](LibAttrs &Attrs) {
73027b2d7d4SCyndy Ishida     for (StringMapEntry<ArchitectureSet> &Entry : Attrs)
73127b2d7d4SCyndy Ishida       if (Entry.getValue().empty())
73227b2d7d4SCyndy Ishida         Entry.setValue(AllArchs);
73327b2d7d4SCyndy Ishida   };
73427b2d7d4SCyndy Ishida   assignDefaultLibAttrs(LinkerOpts.AllowableClients);
73527b2d7d4SCyndy Ishida   assignDefaultLibAttrs(LinkerOpts.ReexportedFrameworks);
73627b2d7d4SCyndy Ishida   assignDefaultLibAttrs(LinkerOpts.ReexportedLibraries);
73727b2d7d4SCyndy Ishida   assignDefaultLibAttrs(LinkerOpts.ReexportedLibraryPaths);
73827b2d7d4SCyndy Ishida   assignDefaultLibAttrs(LinkerOpts.RPaths);
73927b2d7d4SCyndy Ishida 
740936519f2SCyndy Ishida   /// Force cc1 options that should always be on.
741936519f2SCyndy Ishida   FrontendArgs = {"-fsyntax-only", "-Wprivate-extern"};
742936519f2SCyndy Ishida 
7432c93beccSCyndy Ishida   /// Any unclaimed arguments should be handled by invoking the clang frontend.
744c6cbf81cSCyndy Ishida   for (const Arg *A : ArgList) {
745c6cbf81cSCyndy Ishida     if (A->isClaimed())
746c6cbf81cSCyndy Ishida       continue;
74750ae8a2aSCyndy Ishida     FrontendArgs.emplace_back(A->getSpelling());
74850ae8a2aSCyndy Ishida     llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
749c6cbf81cSCyndy Ishida   }
7500a518db9SCyndy Ishida }
7510a518db9SCyndy Ishida 
75227b2d7d4SCyndy Ishida static Expected<std::unique_ptr<InterfaceFile>>
75327b2d7d4SCyndy Ishida getInterfaceFile(const StringRef Filename) {
75427b2d7d4SCyndy Ishida   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
75527b2d7d4SCyndy Ishida       MemoryBuffer::getFile(Filename);
75627b2d7d4SCyndy Ishida   if (auto Err = BufferOrErr.getError())
75727b2d7d4SCyndy Ishida     return errorCodeToError(std::move(Err));
75827b2d7d4SCyndy Ishida 
75927b2d7d4SCyndy Ishida   auto Buffer = std::move(*BufferOrErr);
76027b2d7d4SCyndy Ishida   std::unique_ptr<InterfaceFile> IF;
76127b2d7d4SCyndy Ishida   switch (identify_magic(Buffer->getBuffer())) {
76227b2d7d4SCyndy Ishida   case file_magic::macho_dynamically_linked_shared_lib:
76327b2d7d4SCyndy Ishida   case file_magic::macho_dynamically_linked_shared_lib_stub:
76427b2d7d4SCyndy Ishida   case file_magic::macho_universal_binary:
76527b2d7d4SCyndy Ishida     return DylibReader::get(Buffer->getMemBufferRef());
76627b2d7d4SCyndy Ishida     break;
76727b2d7d4SCyndy Ishida   case file_magic::tapi_file:
76827b2d7d4SCyndy Ishida     return TextAPIReader::get(Buffer->getMemBufferRef());
76927b2d7d4SCyndy Ishida   default:
77027b2d7d4SCyndy Ishida     return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
77127b2d7d4SCyndy Ishida                                     "unsupported library file format");
77227b2d7d4SCyndy Ishida   }
77327b2d7d4SCyndy Ishida   llvm_unreachable("unexpected failure in getInterface");
77427b2d7d4SCyndy Ishida }
77527b2d7d4SCyndy Ishida 
77627b2d7d4SCyndy Ishida std::pair<LibAttrs, ReexportedInterfaces> Options::getReexportedLibraries() {
77727b2d7d4SCyndy Ishida   LibAttrs Reexports;
77827b2d7d4SCyndy Ishida   ReexportedInterfaces ReexportIFs;
77927b2d7d4SCyndy Ishida   auto AccumulateReexports = [&](StringRef Path, const ArchitectureSet &Archs) {
78027b2d7d4SCyndy Ishida     auto ReexportIFOrErr = getInterfaceFile(Path);
78127b2d7d4SCyndy Ishida     if (!ReexportIFOrErr)
78227b2d7d4SCyndy Ishida       return false;
78327b2d7d4SCyndy Ishida     std::unique_ptr<InterfaceFile> Reexport = std::move(*ReexportIFOrErr);
78427b2d7d4SCyndy Ishida     StringRef InstallName = Reexport->getInstallName();
78527b2d7d4SCyndy Ishida     assert(!InstallName.empty() && "Parse error for install name");
78627b2d7d4SCyndy Ishida     Reexports.insert({InstallName, Archs});
78727b2d7d4SCyndy Ishida     ReexportIFs.emplace_back(std::move(*Reexport));
78827b2d7d4SCyndy Ishida     return true;
78927b2d7d4SCyndy Ishida   };
79027b2d7d4SCyndy Ishida 
791062f6fe3SCyndy Ishida   PlatformSet Platforms;
792062f6fe3SCyndy Ishida   llvm::for_each(DriverOpts.Targets,
793062f6fe3SCyndy Ishida                  [&](const auto &T) { Platforms.insert(T.first.Platform); });
79427b2d7d4SCyndy Ishida   // Populate search paths by looking at user paths before system ones.
79527b2d7d4SCyndy Ishida   PathSeq FwkSearchPaths(FEOpts.FwkPaths.begin(), FEOpts.FwkPaths.end());
796062f6fe3SCyndy Ishida   for (const PlatformType P : Platforms) {
797062f6fe3SCyndy Ishida     PathSeq PlatformSearchPaths = getPathsForPlatform(FEOpts.SystemFwkPaths, P);
798062f6fe3SCyndy Ishida     FwkSearchPaths.insert(FwkSearchPaths.end(), PlatformSearchPaths.begin(),
799062f6fe3SCyndy Ishida                           PlatformSearchPaths.end());
800062f6fe3SCyndy Ishida     for (const StringMapEntry<ArchitectureSet> &Lib :
801062f6fe3SCyndy Ishida          LinkerOpts.ReexportedFrameworks) {
802062f6fe3SCyndy Ishida       std::string Name = (Lib.getKey() + ".framework/" + Lib.getKey()).str();
803062f6fe3SCyndy Ishida       std::string Path = findLibrary(Name, *FM, FwkSearchPaths, {}, {});
804062f6fe3SCyndy Ishida       if (Path.empty()) {
805062f6fe3SCyndy Ishida         Diags->Report(diag::err_cannot_find_reexport) << false << Lib.getKey();
806062f6fe3SCyndy Ishida         return {};
807062f6fe3SCyndy Ishida       }
808062f6fe3SCyndy Ishida       if (DriverOpts.TraceLibraryLocation)
809062f6fe3SCyndy Ishida         errs() << Path << "\n";
810062f6fe3SCyndy Ishida 
811062f6fe3SCyndy Ishida       AccumulateReexports(Path, Lib.getValue());
812062f6fe3SCyndy Ishida     }
813062f6fe3SCyndy Ishida     FwkSearchPaths.resize(FwkSearchPaths.size() - PlatformSearchPaths.size());
814062f6fe3SCyndy Ishida   }
81527b2d7d4SCyndy Ishida 
81627b2d7d4SCyndy Ishida   for (const StringMapEntry<ArchitectureSet> &Lib :
81727b2d7d4SCyndy Ishida        LinkerOpts.ReexportedLibraries) {
81827b2d7d4SCyndy Ishida     std::string Name = "lib" + Lib.getKey().str() + ".dylib";
81927b2d7d4SCyndy Ishida     std::string Path = findLibrary(Name, *FM, {}, LinkerOpts.LibPaths, {});
82027b2d7d4SCyndy Ishida     if (Path.empty()) {
82127b2d7d4SCyndy Ishida       Diags->Report(diag::err_cannot_find_reexport) << true << Lib.getKey();
82227b2d7d4SCyndy Ishida       return {};
82327b2d7d4SCyndy Ishida     }
82427b2d7d4SCyndy Ishida     if (DriverOpts.TraceLibraryLocation)
82527b2d7d4SCyndy Ishida       errs() << Path << "\n";
82627b2d7d4SCyndy Ishida 
82727b2d7d4SCyndy Ishida     AccumulateReexports(Path, Lib.getValue());
82827b2d7d4SCyndy Ishida   }
82927b2d7d4SCyndy Ishida 
83027b2d7d4SCyndy Ishida   for (const StringMapEntry<ArchitectureSet> &Lib :
83127b2d7d4SCyndy Ishida        LinkerOpts.ReexportedLibraryPaths)
83227b2d7d4SCyndy Ishida     AccumulateReexports(Lib.getKey(), Lib.getValue());
83327b2d7d4SCyndy Ishida 
83427b2d7d4SCyndy Ishida   return {std::move(Reexports), std::move(ReexportIFs)};
83527b2d7d4SCyndy Ishida }
83627b2d7d4SCyndy Ishida 
8370a518db9SCyndy Ishida InstallAPIContext Options::createContext() {
8380a518db9SCyndy Ishida   InstallAPIContext Ctx;
839c6cbf81cSCyndy Ishida   Ctx.FM = FM;
840c6cbf81cSCyndy Ishida   Ctx.Diags = Diags;
841c6cbf81cSCyndy Ishida 
8420a518db9SCyndy Ishida   // InstallAPI requires two level namespacing.
8430a518db9SCyndy Ishida   Ctx.BA.TwoLevelNamespace = true;
8440a518db9SCyndy Ishida 
8450a518db9SCyndy Ishida   Ctx.BA.InstallName = LinkerOpts.InstallName;
8460a518db9SCyndy Ishida   Ctx.BA.CurrentVersion = LinkerOpts.CurrentVersion;
847b058b7e6SCyndy Ishida   Ctx.BA.CompatVersion = LinkerOpts.CompatVersion;
8480a518db9SCyndy Ishida   Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe;
84927b2d7d4SCyndy Ishida   Ctx.BA.ParentUmbrella = LinkerOpts.ParentUmbrella;
85027b2d7d4SCyndy Ishida   Ctx.BA.OSLibNotForSharedCache = LinkerOpts.OSLibNotForSharedCache;
8510a518db9SCyndy Ishida   Ctx.FT = DriverOpts.OutFT;
8520a518db9SCyndy Ishida   Ctx.OutputLoc = DriverOpts.OutputPath;
8532c93beccSCyndy Ishida   Ctx.LangMode = FEOpts.LangMode;
854c6cbf81cSCyndy Ishida 
85527b2d7d4SCyndy Ishida   auto [Reexports, ReexportedIFs] = getReexportedLibraries();
85627b2d7d4SCyndy Ishida   if (Diags->hasErrorOccurred())
85727b2d7d4SCyndy Ishida     return Ctx;
85827b2d7d4SCyndy Ishida   Ctx.Reexports = Reexports;
85927b2d7d4SCyndy Ishida 
8604c18681aSCyndy Ishida   // Collect symbols from alias lists.
8614c18681aSCyndy Ishida   AliasMap Aliases;
8624c18681aSCyndy Ishida   for (const StringRef ListPath : LinkerOpts.AliasLists) {
8634c18681aSCyndy Ishida     auto Buffer = FM->getBufferForFile(ListPath);
8644c18681aSCyndy Ishida     if (auto Err = Buffer.getError()) {
8654c18681aSCyndy Ishida       Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
8664c18681aSCyndy Ishida       return Ctx;
8674c18681aSCyndy Ishida     }
8684c18681aSCyndy Ishida     Expected<AliasMap> Result = parseAliasList(Buffer.get());
8694c18681aSCyndy Ishida     if (!Result) {
870278774e4SCyndy Ishida       Diags->Report(diag::err_cannot_read_input_list)
871c9dc52d4SCyndy Ishida           << "symbol alias" << ListPath << toString(Result.takeError());
8724c18681aSCyndy Ishida       return Ctx;
8734c18681aSCyndy Ishida     }
8744c18681aSCyndy Ishida     Aliases.insert(Result.get().begin(), Result.get().end());
8754c18681aSCyndy Ishida   }
8764c18681aSCyndy Ishida 
8776ad1cf3bSCyndy Ishida   // Attempt to find umbrella headers by capturing framework name.
8786ad1cf3bSCyndy Ishida   StringRef FrameworkName;
8796ad1cf3bSCyndy Ishida   if (!LinkerOpts.IsDylib)
880feed66f3SCyndy Ishida     FrameworkName =
881feed66f3SCyndy Ishida         Library::getFrameworkNameFromInstallName(LinkerOpts.InstallName);
8826ad1cf3bSCyndy Ishida 
883feed66f3SCyndy Ishida   /// Process inputs headers.
884feed66f3SCyndy Ishida   // 1. For headers discovered by directory scanning, sort them.
885feed66f3SCyndy Ishida   // 2. For headers discovered by filelist, respect ordering.
886feed66f3SCyndy Ishida   // 3. Append extra headers and mark any excluded headers.
887feed66f3SCyndy Ishida   // 4. Finally, surface up umbrella headers to top of the list.
888feed66f3SCyndy Ishida   if (!DriverOpts.InputDirectory.empty()) {
889feed66f3SCyndy Ishida     DirectoryScanner Scanner(*FM, LinkerOpts.IsDylib
890feed66f3SCyndy Ishida                                       ? ScanMode::ScanDylibs
891feed66f3SCyndy Ishida                                       : ScanMode::ScanFrameworks);
892feed66f3SCyndy Ishida     SmallString<PATH_MAX> NormalizedPath(DriverOpts.InputDirectory);
893feed66f3SCyndy Ishida     FM->getVirtualFileSystem().makeAbsolute(NormalizedPath);
894feed66f3SCyndy Ishida     sys::path::remove_dots(NormalizedPath, /*remove_dot_dot=*/true);
895feed66f3SCyndy Ishida     if (llvm::Error Err = Scanner.scan(NormalizedPath)) {
896feed66f3SCyndy Ishida       Diags->Report(diag::err_directory_scanning)
897feed66f3SCyndy Ishida           << DriverOpts.InputDirectory << std::move(Err);
898feed66f3SCyndy Ishida       return Ctx;
899feed66f3SCyndy Ishida     }
900feed66f3SCyndy Ishida     std::vector<Library> InputLibraries = Scanner.takeLibraries();
901feed66f3SCyndy Ishida     if (InputLibraries.size() > 1) {
902feed66f3SCyndy Ishida       Diags->Report(diag::err_more_than_one_library);
903feed66f3SCyndy Ishida       return Ctx;
904feed66f3SCyndy Ishida     }
905feed66f3SCyndy Ishida     llvm::append_range(Ctx.InputHeaders,
906feed66f3SCyndy Ishida                        DirectoryScanner::getHeaders(InputLibraries));
907feed66f3SCyndy Ishida     llvm::stable_sort(Ctx.InputHeaders);
908feed66f3SCyndy Ishida   }
909feed66f3SCyndy Ishida 
91079dca25fSCyndy Ishida   for (const StringRef ListPath : DriverOpts.FileLists) {
911c6cbf81cSCyndy Ishida     auto Buffer = FM->getBufferForFile(ListPath);
912c6cbf81cSCyndy Ishida     if (auto Err = Buffer.getError()) {
913c51095f5SCyndy Ishida       Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
914c6cbf81cSCyndy Ishida       return Ctx;
915c6cbf81cSCyndy Ishida     }
916c6cbf81cSCyndy Ishida     if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()),
917278774e4SCyndy Ishida                                                Ctx.InputHeaders, FM)) {
918278774e4SCyndy Ishida       Diags->Report(diag::err_cannot_read_input_list)
919c9dc52d4SCyndy Ishida           << "header file" << ListPath << std::move(Err);
920c6cbf81cSCyndy Ishida       return Ctx;
921c6cbf81cSCyndy Ishida     }
922c6cbf81cSCyndy Ishida   }
923487720fcSCyndy Ishida   // After initial input has been processed, add any extra headers.
924487720fcSCyndy Ishida   auto HandleExtraHeaders = [&](PathSeq &Headers, HeaderType Type) -> bool {
925487720fcSCyndy Ishida     assert(Type != HeaderType::Unknown && "Missing header type.");
926487720fcSCyndy Ishida     for (const StringRef Path : Headers) {
927487720fcSCyndy Ishida       if (!FM->getOptionalFileRef(Path)) {
9286ad1cf3bSCyndy Ishida         Diags->Report(diag::err_no_such_header_file) << Path << (unsigned)Type;
929487720fcSCyndy Ishida         return false;
930487720fcSCyndy Ishida       }
931487720fcSCyndy Ishida       SmallString<PATH_MAX> FullPath(Path);
932487720fcSCyndy Ishida       FM->makeAbsolutePath(FullPath);
933487720fcSCyndy Ishida 
934487720fcSCyndy Ishida       auto IncludeName = createIncludeHeaderName(FullPath);
935487720fcSCyndy Ishida       Ctx.InputHeaders.emplace_back(
936487720fcSCyndy Ishida           FullPath, Type, IncludeName.has_value() ? *IncludeName : "");
937487720fcSCyndy Ishida       Ctx.InputHeaders.back().setExtra();
938487720fcSCyndy Ishida     }
939487720fcSCyndy Ishida     return true;
940487720fcSCyndy Ishida   };
941487720fcSCyndy Ishida 
942487720fcSCyndy Ishida   if (!HandleExtraHeaders(DriverOpts.ExtraPublicHeaders, HeaderType::Public) ||
943487720fcSCyndy Ishida       !HandleExtraHeaders(DriverOpts.ExtraPrivateHeaders,
944487720fcSCyndy Ishida                           HeaderType::Private) ||
945487720fcSCyndy Ishida       !HandleExtraHeaders(DriverOpts.ExtraProjectHeaders, HeaderType::Project))
946487720fcSCyndy Ishida     return Ctx;
947487720fcSCyndy Ishida 
948487720fcSCyndy Ishida   // After all headers have been added, consider excluded headers.
949487720fcSCyndy Ishida   std::vector<std::unique_ptr<HeaderGlob>> ExcludedHeaderGlobs;
950487720fcSCyndy Ishida   std::set<FileEntryRef> ExcludedHeaderFiles;
951487720fcSCyndy Ishida   auto ParseGlobs = [&](const PathSeq &Paths, HeaderType Type) {
9526ad1cf3bSCyndy Ishida     assert(Type != HeaderType::Unknown && "Missing header type.");
953487720fcSCyndy Ishida     for (const StringRef Path : Paths) {
954487720fcSCyndy Ishida       auto Glob = HeaderGlob::create(Path, Type);
955487720fcSCyndy Ishida       if (Glob)
956487720fcSCyndy Ishida         ExcludedHeaderGlobs.emplace_back(std::move(Glob.get()));
957487720fcSCyndy Ishida       else {
958487720fcSCyndy Ishida         consumeError(Glob.takeError());
959487720fcSCyndy Ishida         if (auto File = FM->getFileRef(Path))
960487720fcSCyndy Ishida           ExcludedHeaderFiles.emplace(*File);
961487720fcSCyndy Ishida         else {
962487720fcSCyndy Ishida           Diags->Report(diag::err_no_such_header_file)
963487720fcSCyndy Ishida               << Path << (unsigned)Type;
964487720fcSCyndy Ishida           return false;
965487720fcSCyndy Ishida         }
966487720fcSCyndy Ishida       }
967487720fcSCyndy Ishida     }
968487720fcSCyndy Ishida     return true;
969487720fcSCyndy Ishida   };
970487720fcSCyndy Ishida 
971487720fcSCyndy Ishida   if (!ParseGlobs(DriverOpts.ExcludePublicHeaders, HeaderType::Public) ||
972487720fcSCyndy Ishida       !ParseGlobs(DriverOpts.ExcludePrivateHeaders, HeaderType::Private) ||
973487720fcSCyndy Ishida       !ParseGlobs(DriverOpts.ExcludeProjectHeaders, HeaderType::Project))
974487720fcSCyndy Ishida     return Ctx;
975487720fcSCyndy Ishida 
976487720fcSCyndy Ishida   for (HeaderFile &Header : Ctx.InputHeaders) {
977487720fcSCyndy Ishida     for (auto &Glob : ExcludedHeaderGlobs)
978487720fcSCyndy Ishida       if (Glob->match(Header))
979487720fcSCyndy Ishida         Header.setExcluded();
980487720fcSCyndy Ishida   }
981487720fcSCyndy Ishida   if (!ExcludedHeaderFiles.empty()) {
982487720fcSCyndy Ishida     for (HeaderFile &Header : Ctx.InputHeaders) {
983487720fcSCyndy Ishida       auto FileRef = FM->getFileRef(Header.getPath());
984487720fcSCyndy Ishida       if (!FileRef)
985487720fcSCyndy Ishida         continue;
986487720fcSCyndy Ishida       if (ExcludedHeaderFiles.count(*FileRef))
987487720fcSCyndy Ishida         Header.setExcluded();
988487720fcSCyndy Ishida     }
989487720fcSCyndy Ishida   }
990487720fcSCyndy Ishida   // Report if glob was ignored.
991487720fcSCyndy Ishida   for (const auto &Glob : ExcludedHeaderGlobs)
992487720fcSCyndy Ishida     if (!Glob->didMatch())
993487720fcSCyndy Ishida       Diags->Report(diag::warn_glob_did_not_match) << Glob->str();
994c6cbf81cSCyndy Ishida 
9956ad1cf3bSCyndy Ishida   // Mark any explicit or inferred umbrella headers. If one exists, move
9966ad1cf3bSCyndy Ishida   // that to the beginning of the input headers.
9976ad1cf3bSCyndy Ishida   auto MarkandMoveUmbrellaInHeaders = [&](llvm::Regex &Regex,
9986ad1cf3bSCyndy Ishida                                           HeaderType Type) -> bool {
9996ad1cf3bSCyndy Ishida     auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) {
10006ad1cf3bSCyndy Ishida       return (H.getType() == Type) && Regex.match(H.getPath());
10016ad1cf3bSCyndy Ishida     });
10026ad1cf3bSCyndy Ishida 
10036ad1cf3bSCyndy Ishida     if (It == Ctx.InputHeaders.end())
10046ad1cf3bSCyndy Ishida       return false;
10056ad1cf3bSCyndy Ishida     It->setUmbrellaHeader();
10066ad1cf3bSCyndy Ishida 
10076ad1cf3bSCyndy Ishida     // Because there can be an umbrella header per header type,
10086ad1cf3bSCyndy Ishida     // find the first non umbrella header to swap position with.
10096ad1cf3bSCyndy Ishida     auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) {
10106ad1cf3bSCyndy Ishida       return !H.isUmbrellaHeader();
10116ad1cf3bSCyndy Ishida     });
10126ad1cf3bSCyndy Ishida     if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It)
10136ad1cf3bSCyndy Ishida       std::swap(*BeginPos, *It);
10146ad1cf3bSCyndy Ishida     return true;
10156ad1cf3bSCyndy Ishida   };
10166ad1cf3bSCyndy Ishida 
10176ad1cf3bSCyndy Ishida   auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool {
10186ad1cf3bSCyndy Ishida     assert(Type != HeaderType::Unknown && "Missing header type.");
10196ad1cf3bSCyndy Ishida     if (!HeaderPath.empty()) {
10206ad1cf3bSCyndy Ishida       auto EscapedString = Regex::escape(HeaderPath);
10216ad1cf3bSCyndy Ishida       Regex UmbrellaRegex(EscapedString);
10226ad1cf3bSCyndy Ishida       if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) {
10236ad1cf3bSCyndy Ishida         Diags->Report(diag::err_no_such_umbrella_header_file)
10246ad1cf3bSCyndy Ishida             << HeaderPath << (unsigned)Type;
10256ad1cf3bSCyndy Ishida         return false;
10266ad1cf3bSCyndy Ishida       }
10276ad1cf3bSCyndy Ishida     } else if (!FrameworkName.empty() && (Type != HeaderType::Project)) {
10286ad1cf3bSCyndy Ishida       auto UmbrellaName = "/" + Regex::escape(FrameworkName);
10296ad1cf3bSCyndy Ishida       if (Type == HeaderType::Public)
10306ad1cf3bSCyndy Ishida         UmbrellaName += "\\.h";
10316ad1cf3bSCyndy Ishida       else
10326ad1cf3bSCyndy Ishida         UmbrellaName += "[_]?Private\\.h";
10336ad1cf3bSCyndy Ishida       Regex UmbrellaRegex(UmbrellaName);
10346ad1cf3bSCyndy Ishida       MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type);
10356ad1cf3bSCyndy Ishida     }
10366ad1cf3bSCyndy Ishida     return true;
10376ad1cf3bSCyndy Ishida   };
10386ad1cf3bSCyndy Ishida   if (!FindUmbrellaHeader(DriverOpts.PublicUmbrellaHeader,
10396ad1cf3bSCyndy Ishida                           HeaderType::Public) ||
10406ad1cf3bSCyndy Ishida       !FindUmbrellaHeader(DriverOpts.PrivateUmbrellaHeader,
10416ad1cf3bSCyndy Ishida                           HeaderType::Private) ||
10426ad1cf3bSCyndy Ishida       !FindUmbrellaHeader(DriverOpts.ProjectUmbrellaHeader,
10436ad1cf3bSCyndy Ishida                           HeaderType::Project))
10446ad1cf3bSCyndy Ishida     return Ctx;
10456ad1cf3bSCyndy Ishida 
1046f2794cceSCyndy Ishida   // Parse binary dylib and initialize verifier.
1047f2794cceSCyndy Ishida   if (DriverOpts.DylibToVerify.empty()) {
1048f2794cceSCyndy Ishida     Ctx.Verifier = std::make_unique<DylibVerifier>();
1049c51095f5SCyndy Ishida     return Ctx;
1050f2794cceSCyndy Ishida   }
1051c51095f5SCyndy Ishida 
1052c51095f5SCyndy Ishida   auto Buffer = FM->getBufferForFile(DriverOpts.DylibToVerify);
1053c51095f5SCyndy Ishida   if (auto Err = Buffer.getError()) {
1054c51095f5SCyndy Ishida     Diags->Report(diag::err_cannot_open_file)
1055c51095f5SCyndy Ishida         << DriverOpts.DylibToVerify << Err.message();
1056c51095f5SCyndy Ishida     return Ctx;
1057c51095f5SCyndy Ishida   }
1058c51095f5SCyndy Ishida 
1059c51095f5SCyndy Ishida   DylibReader::ParseOption PO;
1060c51095f5SCyndy Ishida   PO.Undefineds = false;
1061c51095f5SCyndy Ishida   Expected<Records> Slices =
1062c51095f5SCyndy Ishida       DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
1063c51095f5SCyndy Ishida   if (auto Err = Slices.takeError()) {
106427b2d7d4SCyndy Ishida     Diags->Report(diag::err_cannot_open_file)
106527b2d7d4SCyndy Ishida         << DriverOpts.DylibToVerify << std::move(Err);
1066c51095f5SCyndy Ishida     return Ctx;
1067c51095f5SCyndy Ishida   }
1068c51095f5SCyndy Ishida 
1069f2794cceSCyndy Ishida   Ctx.Verifier = std::make_unique<DylibVerifier>(
10704c18681aSCyndy Ishida       std::move(*Slices), std::move(ReexportedIFs), std::move(Aliases), Diags,
1071c24efffaSCyndy Ishida       DriverOpts.VerifyMode, DriverOpts.Zippered, DriverOpts.Demangle,
1072c24efffaSCyndy Ishida       DriverOpts.DSYMPath);
10730a518db9SCyndy Ishida   return Ctx;
10740a518db9SCyndy Ishida }
10750a518db9SCyndy Ishida 
1076062f6fe3SCyndy Ishida void Options::addConditionalCC1Args(std::vector<std::string> &ArgStrings,
1077062f6fe3SCyndy Ishida                                     const llvm::Triple &Targ,
1078062f6fe3SCyndy Ishida                                     const HeaderType Type) {
1079062f6fe3SCyndy Ishida   // Unique to architecture (Xarch) options hold no arguments to pass along for
1080062f6fe3SCyndy Ishida   // frontend.
1081062f6fe3SCyndy Ishida 
1082062f6fe3SCyndy Ishida   // Add specific to platform arguments.
1083062f6fe3SCyndy Ishida   PathSeq PlatformSearchPaths =
1084062f6fe3SCyndy Ishida       getPathsForPlatform(FEOpts.SystemFwkPaths, mapToPlatformType(Targ));
1085062f6fe3SCyndy Ishida   llvm::for_each(PlatformSearchPaths, [&ArgStrings](const StringRef Path) {
1086062f6fe3SCyndy Ishida     ArgStrings.push_back("-iframework");
1087062f6fe3SCyndy Ishida     ArgStrings.push_back(Path.str());
1088062f6fe3SCyndy Ishida   });
1089062f6fe3SCyndy Ishida 
1090062f6fe3SCyndy Ishida   // Add specific to header type arguments.
1091062f6fe3SCyndy Ishida   if (Type == HeaderType::Project)
1092062f6fe3SCyndy Ishida     for (const StringRef A : ProjectLevelArgs)
1093062f6fe3SCyndy Ishida       ArgStrings.emplace_back(A);
1094062f6fe3SCyndy Ishida }
1095062f6fe3SCyndy Ishida 
10960a518db9SCyndy Ishida } // namespace installapi
10970a518db9SCyndy Ishida } // namespace clang
1098