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