1//===-- Options.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Options.h"
10#include "clang/Basic/DiagnosticIDs.h"
11#include "clang/Driver/Driver.h"
12#include "clang/InstallAPI/DirectoryScanner.h"
13#include "clang/InstallAPI/FileList.h"
14#include "clang/InstallAPI/HeaderFile.h"
15#include "clang/InstallAPI/InstallAPIDiagnostic.h"
16#include "llvm/BinaryFormat/Magic.h"
17#include "llvm/Support/JSON.h"
18#include "llvm/Support/Program.h"
19#include "llvm/TargetParser/Host.h"
20#include "llvm/TextAPI/DylibReader.h"
21#include "llvm/TextAPI/TextAPIError.h"
22#include "llvm/TextAPI/TextAPIReader.h"
23#include "llvm/TextAPI/TextAPIWriter.h"
24
25using namespace llvm;
26using namespace llvm::opt;
27using namespace llvm::MachO;
28
29namespace drv = clang::driver::options;
30
31namespace clang {
32namespace installapi {
33
34#define OPTTABLE_STR_TABLE_CODE
35#include "InstallAPIOpts.inc"
36#undef OPTTABLE_STR_TABLE_CODE
37
38#define OPTTABLE_PREFIXES_TABLE_CODE
39#include "InstallAPIOpts.inc"
40#undef OPTTABLE_PREFIXES_TABLE_CODE
41
42#define OPTTABLE_PREFIXES_UNION_CODE
43#include "InstallAPIOpts.inc"
44#undef OPTTABLE_PREFIXES_UNION_CODE
45
46/// Create table mapping all options defined in InstallAPIOpts.td.
47static constexpr OptTable::Info InfoTable[] = {
48#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
49#include "InstallAPIOpts.inc"
50#undef OPTION
51};
52
53namespace {
54
55/// \brief Create OptTable class for parsing actual command line arguments.
56class DriverOptTable : public opt::PrecomputedOptTable {
57public:
58 DriverOptTable()
59 : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
60 OptionPrefixesUnion) {}
61};
62
63} // end anonymous namespace.
64
65static llvm::opt::OptTable *createDriverOptTable() {
66 return new DriverOptTable();
67}
68
69/// Parse JSON input into argument list.
70///
71/* Expected input format.
72 * { "label" : ["-ClangArg1", "-ClangArg2"] }
73 */
74///
75/// Input is interpreted as "-Xlabel ClangArg1 -XLabel ClangArg2".
76static Expected<llvm::opt::InputArgList>
77getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
78 std::vector<std::string> &Storage) {
79 using namespace json;
80 Expected<Value> ValOrErr = json::parse(JSON: Input);
81 if (!ValOrErr)
82 return ValOrErr.takeError();
83
84 const Object *Root = ValOrErr->getAsObject();
85 if (!Root)
86 return llvm::opt::InputArgList();
87
88 for (const auto &KV : *Root) {
89 const Array *ArgList = KV.getSecond().getAsArray();
90 std::string Label = "-X" + KV.getFirst().str();
91 if (!ArgList)
92 return make_error<TextAPIError>(Args: TextAPIErrorCode::InvalidInputFormat);
93 for (auto Arg : *ArgList) {
94 std::optional<StringRef> ArgStr = Arg.getAsString();
95 if (!ArgStr)
96 return make_error<TextAPIError>(Args: TextAPIErrorCode::InvalidInputFormat);
97 Storage.emplace_back(args&: Label);
98 Storage.emplace_back(args&: *ArgStr);
99 }
100 }
101
102 std::vector<const char *> CArgs(Storage.size());
103 for (StringRef Str : Storage)
104 CArgs.emplace_back(args: Str.data());
105
106 unsigned MissingArgIndex, MissingArgCount;
107 return Table->ParseArgs(Args: CArgs, MissingArgIndex, MissingArgCount);
108}
109
110bool Options::processDriverOptions(InputArgList &Args) {
111 // Handle inputs.
112 for (const StringRef Path : Args.getAllArgValues(Id: drv::OPT_INPUT)) {
113 // Assume any input that is not a directory is a filelist.
114 // InstallAPI does not accept multiple directories, so retain the last one.
115 if (FM->getOptionalDirectoryRef(DirName: Path))
116 DriverOpts.InputDirectory = Path.str();
117 else
118 DriverOpts.FileLists.emplace_back(args: Path.str());
119 }
120
121 // Handle output.
122 SmallString<PATH_MAX> OutputPath;
123 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_o)) {
124 OutputPath = Arg->getValue();
125 if (OutputPath != "-")
126 FM->makeAbsolutePath(Path&: OutputPath);
127 DriverOpts.OutputPath = std::string(OutputPath);
128 }
129 if (DriverOpts.OutputPath.empty()) {
130 Diags->Report(DiagID: diag::err_no_output_file);
131 return false;
132 }
133
134 // Do basic error checking first for mixing -target and -arch options.
135 auto *ArgArch = Args.getLastArgNoClaim(Ids: drv::OPT_arch);
136 auto *ArgTarget = Args.getLastArgNoClaim(Ids: drv::OPT_target);
137 auto *ArgTargetVariant =
138 Args.getLastArgNoClaim(Ids: drv::OPT_darwin_target_variant);
139 if (ArgArch && (ArgTarget || ArgTargetVariant)) {
140 Diags->Report(DiagID: clang::diag::err_drv_argument_not_allowed_with)
141 << ArgArch->getAsString(Args)
142 << (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
143 return false;
144 }
145
146 auto *ArgMinTargetOS = Args.getLastArgNoClaim(Ids: drv::OPT_mtargetos_EQ);
147 if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
148 Diags->Report(DiagID: clang::diag::err_drv_cannot_mix_options)
149 << ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
150 return false;
151 }
152
153 // Capture target triples first.
154 if (ArgTarget) {
155 for (const Arg *A : Args.filtered(Ids: drv::OPT_target)) {
156 A->claim();
157 llvm::Triple TargetTriple(A->getValue());
158 Target TAPITarget = Target(TargetTriple);
159 if ((TAPITarget.Arch == AK_unknown) ||
160 (TAPITarget.Platform == PLATFORM_UNKNOWN)) {
161 Diags->Report(DiagID: clang::diag::err_drv_unsupported_opt_for_target)
162 << "installapi" << TargetTriple.str();
163 return false;
164 }
165 DriverOpts.Targets[TAPITarget] = TargetTriple;
166 }
167 }
168
169 // Capture target variants.
170 DriverOpts.Zippered = ArgTargetVariant != nullptr;
171 for (Arg *A : Args.filtered(Ids: drv::OPT_darwin_target_variant)) {
172 A->claim();
173 Triple Variant(A->getValue());
174 if (Variant.getVendor() != Triple::Apple) {
175 Diags->Report(DiagID: diag::err_unsupported_vendor)
176 << Variant.getVendorName() << A->getAsString(Args);
177 return false;
178 }
179
180 switch (Variant.getOS()) {
181 default:
182 Diags->Report(DiagID: diag::err_unsupported_os)
183 << Variant.getOSName() << A->getAsString(Args);
184 return false;
185 case Triple::MacOSX:
186 case Triple::IOS:
187 break;
188 }
189
190 switch (Variant.getEnvironment()) {
191 default:
192 Diags->Report(DiagID: diag::err_unsupported_environment)
193 << Variant.getEnvironmentName() << A->getAsString(Args);
194 return false;
195 case Triple::UnknownEnvironment:
196 case Triple::MacABI:
197 break;
198 }
199
200 Target TAPIVariant(Variant);
201 // See if there is a matching --target option for this --target-variant
202 // option.
203 auto It = find_if(Range&: DriverOpts.Targets, P: [&](const auto &T) {
204 return (T.first.Arch == TAPIVariant.Arch) &&
205 (T.first.Platform != PlatformType::PLATFORM_UNKNOWN);
206 });
207
208 if (It == DriverOpts.Targets.end()) {
209 Diags->Report(DiagID: diag::err_no_matching_target) << Variant.str();
210 return false;
211 }
212
213 DriverOpts.Targets[TAPIVariant] = Variant;
214 }
215
216 DriverOpts.Verbose = Args.hasArgNoClaim(Ids: drv::OPT_v);
217
218 return true;
219}
220
221bool Options::processInstallAPIXOptions(InputArgList &Args) {
222 for (arg_iterator It = Args.begin(), End = Args.end(); It != End; ++It) {
223 Arg *A = *It;
224 if (A->getOption().matches(ID: OPT_Xarch__)) {
225 if (!processXarchOption(Args, Curr: It))
226 return false;
227 continue;
228 } else if (A->getOption().matches(ID: OPT_Xplatform__)) {
229 if (!processXplatformOption(Args, Curr: It))
230 return false;
231 continue;
232 } else if (A->getOption().matches(ID: OPT_Xproject)) {
233 if (!processXprojectOption(Args, Curr: It))
234 return false;
235 continue;
236 } else if (!A->getOption().matches(ID: OPT_X__))
237 continue;
238
239 // Handle any user defined labels.
240 const StringRef Label = A->getValue(N: 0);
241
242 // Ban "public" and "private" labels.
243 if ((Label.lower() == "public") || (Label.lower() == "private")) {
244 Diags->Report(DiagID: diag::err_invalid_label) << Label;
245 return false;
246 }
247
248 auto NextIt = std::next(x: It);
249 if (NextIt == End) {
250 Diags->Report(DiagID: clang::diag::err_drv_missing_argument)
251 << A->getAsString(Args) << 1;
252 return false;
253 }
254 Arg *NextA = *NextIt;
255 switch ((ID)NextA->getOption().getID()) {
256 case OPT_D:
257 case OPT_U:
258 break;
259 default:
260 Diags->Report(DiagID: clang::diag::err_drv_argument_not_allowed_with)
261 << A->getAsString(Args) << NextA->getAsString(Args);
262 return false;
263 }
264 const StringRef ASpelling = NextA->getSpelling();
265 const auto &AValues = NextA->getValues();
266 auto &UniqueArgs = FEOpts.UniqueArgs[Label];
267 if (AValues.empty())
268 UniqueArgs.emplace_back(args: ASpelling.str());
269 else
270 for (const StringRef Val : AValues)
271 UniqueArgs.emplace_back(args: (ASpelling + Val).str());
272
273 A->claim();
274 NextA->claim();
275 }
276
277 return true;
278}
279
280bool Options::processXplatformOption(InputArgList &Args, arg_iterator Curr) {
281 Arg *A = *Curr;
282
283 PlatformType Platform = getPlatformFromName(Name: A->getValue(N: 0));
284 if (Platform == PLATFORM_UNKNOWN) {
285 Diags->Report(DiagID: diag::err_unsupported_os)
286 << getPlatformName(Platform) << A->getAsString(Args);
287 return false;
288 }
289 auto NextIt = std::next(x: Curr);
290 if (NextIt == Args.end()) {
291 Diags->Report(DiagID: diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
292 return false;
293 }
294
295 Arg *NextA = *NextIt;
296 switch ((ID)NextA->getOption().getID()) {
297 case OPT_iframework:
298 FEOpts.SystemFwkPaths.emplace_back(args: NextA->getValue(), args&: Platform);
299 break;
300 default:
301 Diags->Report(DiagID: diag::err_drv_invalid_argument_to_option)
302 << A->getAsString(Args) << NextA->getAsString(Args);
303 return false;
304 }
305
306 A->claim();
307 NextA->claim();
308
309 return true;
310}
311
312bool Options::processXprojectOption(InputArgList &Args, arg_iterator Curr) {
313 Arg *A = *Curr;
314 auto NextIt = std::next(x: Curr);
315 if (NextIt == Args.end()) {
316 Diags->Report(DiagID: diag::err_drv_missing_argument) << A->getAsString(Args) << 1;
317 return false;
318 }
319
320 Arg *NextA = *NextIt;
321 switch ((ID)NextA->getOption().getID()) {
322 case OPT_fobjc_arc:
323 case OPT_fmodules:
324 case OPT_fmodules_cache_path:
325 case OPT_include_:
326 case OPT_fvisibility_EQ:
327 break;
328 default:
329 Diags->Report(DiagID: diag::err_drv_argument_not_allowed_with)
330 << A->getAsString(Args) << NextA->getAsString(Args);
331 return false;
332 }
333
334 std::string ArgString = NextA->getSpelling().str();
335 for (const StringRef Val : NextA->getValues())
336 ArgString += Val.str();
337
338 ProjectLevelArgs.push_back(x: ArgString);
339 A->claim();
340 NextA->claim();
341
342 return true;
343}
344
345bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) {
346 Arg *CurrArg = *Curr;
347 Architecture Arch = getArchitectureFromName(Name: CurrArg->getValue(N: 0));
348 if (Arch == AK_unknown) {
349 Diags->Report(DiagID: diag::err_drv_invalid_arch_name)
350 << CurrArg->getAsString(Args);
351 return false;
352 }
353
354 auto NextIt = std::next(x: Curr);
355 if (NextIt == Args.end()) {
356 Diags->Report(DiagID: diag::err_drv_missing_argument)
357 << CurrArg->getAsString(Args) << 1;
358 return false;
359 }
360
361 // InstallAPI has a limited understanding of supported Xarch options.
362 // Currently this is restricted to linker inputs.
363 const Arg *NextArg = *NextIt;
364 switch (NextArg->getOption().getID()) {
365 case OPT_allowable_client:
366 case OPT_reexport_l:
367 case OPT_reexport_framework:
368 case OPT_reexport_library:
369 case OPT_rpath:
370 break;
371 default:
372 Diags->Report(DiagID: diag::err_drv_invalid_argument_to_option)
373 << NextArg->getAsString(Args) << CurrArg->getAsString(Args);
374 return false;
375 }
376
377 ArgToArchMap[NextArg] = Arch;
378 CurrArg->claim();
379
380 return true;
381}
382
383bool Options::processOptionList(InputArgList &Args,
384 llvm::opt::OptTable *Table) {
385 Arg *A = Args.getLastArg(Ids: OPT_option_list);
386 if (!A)
387 return true;
388
389 const StringRef Path = A->getValue(N: 0);
390 auto InputOrErr = FM->getBufferForFile(Filename: Path);
391 if (auto Err = InputOrErr.getError()) {
392 Diags->Report(DiagID: diag::err_cannot_open_file) << Path << Err.message();
393 return false;
394 }
395 // Backing storage referenced for argument processing.
396 std::vector<std::string> Storage;
397 auto ArgsOrErr =
398 getArgListFromJSON(Input: (*InputOrErr)->getBuffer(), Table, Storage);
399
400 if (auto Err = ArgsOrErr.takeError()) {
401 Diags->Report(DiagID: diag::err_cannot_read_input_list)
402 << "option" << Path << toString(E: std::move(Err));
403 return false;
404 }
405 return processInstallAPIXOptions(Args&: *ArgsOrErr);
406}
407
408bool Options::processLinkerOptions(InputArgList &Args) {
409 // Handle required arguments.
410 if (const Arg *A = Args.getLastArg(Ids: drv::OPT_install__name))
411 LinkerOpts.InstallName = A->getValue();
412 if (LinkerOpts.InstallName.empty()) {
413 Diags->Report(DiagID: diag::err_no_install_name);
414 return false;
415 }
416
417 // Defaulted or optional arguments.
418 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_current__version))
419 LinkerOpts.CurrentVersion.parse64(Str: Arg->getValue());
420
421 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_compatibility__version))
422 LinkerOpts.CompatVersion.parse64(Str: Arg->getValue());
423
424 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_compatibility__version))
425 LinkerOpts.CompatVersion.parse64(Str: Arg->getValue());
426
427 if (auto *Arg = Args.getLastArg(Ids: drv::OPT_umbrella))
428 LinkerOpts.ParentUmbrella = Arg->getValue();
429
430 LinkerOpts.IsDylib = Args.hasArg(Ids: drv::OPT_dynamiclib);
431
432 for (auto *Arg : Args.filtered(Ids: drv::OPT_alias_list)) {
433 LinkerOpts.AliasLists.emplace_back(args: Arg->getValue());
434 Arg->claim();
435 }
436
437 LinkerOpts.AppExtensionSafe = Args.hasFlag(
438 Pos: drv::OPT_fapplication_extension, Neg: drv::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: drv::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: drv::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: drv::OPT_ObjC, Ids: drv::OPT_ObjCXX)) {
479 if (A->getOption().matches(ID: drv::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: drv::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: drv::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: drv::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