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