brintos

brintos / llvm-project-archived public Read only

0
0
Text · 37.1 KiB · f484d6f Raw
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