brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.2 KiB · b35f7fd Raw
432 lines · cpp
1//===- InterfaceFile.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// Implements the Interface File.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/TextAPI/InterfaceFile.h"14#include "llvm/TextAPI/RecordsSlice.h"15#include "llvm/TextAPI/TextAPIError.h"16 17using namespace llvm;18using namespace llvm::MachO;19 20void InterfaceFileRef::addTarget(const Target &Target) {21  addEntry(Targets, Target);22}23 24void InterfaceFile::addAllowableClient(StringRef InstallName,25                                       const Target &Target) {26  if (InstallName.empty())27    return;28  auto Client = addEntry(AllowableClients, InstallName);29  Client->addTarget(Target);30}31 32void InterfaceFile::addReexportedLibrary(StringRef InstallName,33                                         const Target &Target) {34  if (InstallName.empty())35    return;36  auto Lib = addEntry(ReexportedLibraries, InstallName);37  Lib->addTarget(Target);38}39 40void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {41  if (Parent.empty())42    return;43  auto Iter = lower_bound(ParentUmbrellas, Target_,44                          [](const std::pair<Target, std::string> &LHS,45                             Target RHS) { return LHS.first < RHS; });46 47  if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {48    Iter->second = std::string(Parent);49    return;50  }51 52  ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));53}54 55void InterfaceFile::addRPath(StringRef RPath, const Target &InputTarget) {56  if (RPath.empty())57    return;58  using RPathEntryT = const std::pair<Target, std::string>;59  RPathEntryT Entry(InputTarget, RPath);60 61  if (is_contained(RPaths, Entry))62    return;63 64  RPaths.emplace_back(Entry);65}66 67void InterfaceFile::addTarget(const Target &Target) {68  addEntry(Targets, Target);69}70 71InterfaceFile::const_filtered_target_range72InterfaceFile::targets(ArchitectureSet Archs) const {73  std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {74    return Archs.has(Target_.Arch);75  };76  return make_filter_range(Targets, fn);77}78 79void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {80  auto Pos = llvm::lower_bound(Documents, Document,81                               [](const std::shared_ptr<InterfaceFile> &LHS,82                                  const std::shared_ptr<InterfaceFile> &RHS) {83                                 return LHS->InstallName < RHS->InstallName;84                               });85  assert((Pos == Documents.end() ||86          (*Pos)->InstallName != Document->InstallName) &&87         "Unexpected duplicate document added");88  Document->Parent = this;89  Documents.insert(Pos, Document);90}91 92void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,93                                  bool Overwrite) {94  auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {95    auto It = lower_bound(96        Documents, Reexport->getInstallName(),97        [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {98          return Lhs->getInstallName() < Rhs;99        });100 101    if (Overwrite && It != Documents.end() &&102        Reexport->getInstallName() == (*It)->getInstallName()) {103      llvm::replace(Documents, *It, std::move(Reexport));104      return;105    }106 107    if ((It != Documents.end()) &&108        !(Reexport->getInstallName() < (*It)->getInstallName()))109      return;110 111    Documents.emplace(It, std::move(Reexport));112  };113  for (auto Doc : Library->documents())114    AddFwk(std::move(Doc));115 116  Library->Documents.clear();117  AddFwk(std::move(Library));118}119 120Expected<std::unique_ptr<InterfaceFile>>121InterfaceFile::merge(const InterfaceFile *O) const {122  // Verify files can be merged.123  if (getInstallName() != O->getInstallName()) {124    return make_error<StringError>("install names do not match",125                                   inconvertibleErrorCode());126  }127 128  if (getCurrentVersion() != O->getCurrentVersion()) {129    return make_error<StringError>("current versions do not match",130                                   inconvertibleErrorCode());131  }132 133  if (getCompatibilityVersion() != O->getCompatibilityVersion()) {134    return make_error<StringError>("compatibility versions do not match",135                                   inconvertibleErrorCode());136  }137 138  if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&139      (getSwiftABIVersion() != O->getSwiftABIVersion())) {140    return make_error<StringError>("swift ABI versions do not match",141                                   inconvertibleErrorCode());142  }143 144  if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {145    return make_error<StringError>("two level namespace flags do not match",146                                   inconvertibleErrorCode());147  }148 149  if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {150    return make_error<StringError>(151        "application extension safe flags do not match",152        inconvertibleErrorCode());153  }154 155  std::unique_ptr<InterfaceFile> IF(new InterfaceFile());156  IF->setFileType(std::max(getFileType(), O->getFileType()));157  IF->setPath(getPath());158  IF->setInstallName(getInstallName());159  IF->setCurrentVersion(getCurrentVersion());160  IF->setCompatibilityVersion(getCompatibilityVersion());161 162  if (getSwiftABIVersion() == 0)163    IF->setSwiftABIVersion(O->getSwiftABIVersion());164  else165    IF->setSwiftABIVersion(getSwiftABIVersion());166 167  IF->setTwoLevelNamespace(isTwoLevelNamespace());168  IF->setApplicationExtensionSafe(isApplicationExtensionSafe());169  IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());170 171  for (const auto &It : umbrellas()) {172    if (!It.second.empty())173      IF->addParentUmbrella(It.first, It.second);174  }175  for (const auto &It : O->umbrellas()) {176    if (!It.second.empty())177      IF->addParentUmbrella(It.first, It.second);178  }179  IF->addTargets(targets());180  IF->addTargets(O->targets());181 182  for (const auto &Lib : allowableClients())183    for (const auto &Target : Lib.targets())184      IF->addAllowableClient(Lib.getInstallName(), Target);185 186  for (const auto &Lib : O->allowableClients())187    for (const auto &Target : Lib.targets())188      IF->addAllowableClient(Lib.getInstallName(), Target);189 190  for (const auto &Lib : reexportedLibraries())191    for (const auto &Target : Lib.targets())192      IF->addReexportedLibrary(Lib.getInstallName(), Target);193 194  for (const auto &Lib : O->reexportedLibraries())195    for (const auto &Target : Lib.targets())196      IF->addReexportedLibrary(Lib.getInstallName(), Target);197 198  for (const auto &[Target, Path] : rpaths())199    IF->addRPath(Path, Target);200  for (const auto &[Target, Path] : O->rpaths())201    IF->addRPath(Path, Target);202 203  for (const auto *Sym : symbols()) {204    IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),205                  Sym->getFlags());206  }207 208  for (const auto *Sym : O->symbols()) {209    IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),210                  Sym->getFlags());211  }212 213  return std::move(IF);214}215 216Expected<std::unique_ptr<InterfaceFile>>217InterfaceFile::remove(Architecture Arch) const {218  if (getArchitectures() == Arch)219    return make_error<StringError>("cannot remove last architecture slice '" +220                                       getArchitectureName(Arch) + "'",221                                   inconvertibleErrorCode());222 223  if (!getArchitectures().has(Arch)) {224    bool Found = false;225    for (auto &Doc : Documents) {226      if (Doc->getArchitectures().has(Arch)) {227        Found = true;228        break;229      }230    }231 232    if (!Found)233      return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);234  }235 236  // FIXME: Figure out how to keep these attributes in sync when new ones are237  // added.238  std::unique_ptr<InterfaceFile> IF(new InterfaceFile());239  IF->setFileType(getFileType());240  IF->setPath(getPath());241  IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));242  IF->setInstallName(getInstallName());243  IF->setCurrentVersion(getCurrentVersion());244  IF->setCompatibilityVersion(getCompatibilityVersion());245  IF->setSwiftABIVersion(getSwiftABIVersion());246  IF->setTwoLevelNamespace(isTwoLevelNamespace());247  IF->setApplicationExtensionSafe(isApplicationExtensionSafe());248  IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());249  for (const auto &It : umbrellas())250    if (It.first.Arch != Arch)251      IF->addParentUmbrella(It.first, It.second);252 253  for (const auto &Lib : allowableClients()) {254    for (const auto &Target : Lib.targets())255      if (Target.Arch != Arch)256        IF->addAllowableClient(Lib.getInstallName(), Target);257  }258 259  for (const auto &Lib : reexportedLibraries()) {260    for (const auto &Target : Lib.targets())261      if (Target.Arch != Arch)262        IF->addReexportedLibrary(Lib.getInstallName(), Target);263  }264 265  for (const auto *Sym : symbols()) {266    auto Archs = Sym->getArchitectures();267    Archs.clear(Arch);268    if (Archs.empty())269      continue;270 271    IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),272                  Sym->getFlags());273  }274 275  for (auto &Doc : Documents) {276    // Skip the inlined document if the to be removed architecture is the277    // only one left.278    if (Doc->getArchitectures() == Arch)279      continue;280 281    // If the document doesn't contain the arch, then no work is to be done282    // and it can be copied over.283    if (!Doc->getArchitectures().has(Arch)) {284      auto NewDoc = Doc;285      IF->addDocument(std::move(NewDoc));286      continue;287    }288 289    auto Result = Doc->remove(Arch);290    if (!Result)291      return Result;292 293    IF->addDocument(std::move(Result.get()));294  }295 296  return std::move(IF);297}298 299Expected<std::unique_ptr<InterfaceFile>>300InterfaceFile::extract(Architecture Arch) const {301  if (!getArchitectures().has(Arch)) {302    return make_error<StringError>("file doesn't have architecture '" +303                                       getArchitectureName(Arch) + "'",304                                   inconvertibleErrorCode());305  }306 307  std::unique_ptr<InterfaceFile> IF(new InterfaceFile());308  IF->setFileType(getFileType());309  IF->setPath(getPath());310  IF->addTargets(targets(Arch));311  IF->setInstallName(getInstallName());312  IF->setCurrentVersion(getCurrentVersion());313  IF->setCompatibilityVersion(getCompatibilityVersion());314  IF->setSwiftABIVersion(getSwiftABIVersion());315  IF->setTwoLevelNamespace(isTwoLevelNamespace());316  IF->setApplicationExtensionSafe(isApplicationExtensionSafe());317  IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());318  for (const auto &It : umbrellas())319    if (It.first.Arch == Arch)320      IF->addParentUmbrella(It.first, It.second);321 322  for (const auto &It : rpaths())323    if (It.first.Arch == Arch)324      IF->addRPath(It.second, It.first);325 326  for (const auto &Lib : allowableClients())327    for (const auto &Target : Lib.targets())328      if (Target.Arch == Arch)329        IF->addAllowableClient(Lib.getInstallName(), Target);330 331  for (const auto &Lib : reexportedLibraries())332    for (const auto &Target : Lib.targets())333      if (Target.Arch == Arch)334        IF->addReexportedLibrary(Lib.getInstallName(), Target);335 336  for (const auto *Sym : symbols()) {337    if (Sym->hasArchitecture(Arch))338      IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),339                    Sym->getFlags());340  }341 342  for (auto &Doc : Documents) {343    // Skip documents that don't have the requested architecture.344    if (!Doc->getArchitectures().has(Arch))345      continue;346 347    auto Result = Doc->extract(Arch);348    if (!Result)349      return Result;350 351    IF->addDocument(std::move(Result.get()));352  }353 354  return std::move(IF);355}356 357void InterfaceFile::setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA,358                                       const Target &Targ) {359  if (getFileType() != BA.File)360    setFileType(BA.File);361  if (getInstallName().empty())362    setInstallName(BA.InstallName);363  if (BA.AppExtensionSafe && !isApplicationExtensionSafe())364    setApplicationExtensionSafe();365  if (BA.TwoLevelNamespace && !isTwoLevelNamespace())366    setTwoLevelNamespace();367  if (BA.OSLibNotForSharedCache && !isOSLibNotForSharedCache())368    setOSLibNotForSharedCache();369  if (getCurrentVersion().empty())370    setCurrentVersion(BA.CurrentVersion);371  if (getCompatibilityVersion().empty())372    setCompatibilityVersion(BA.CompatVersion);373  if (getSwiftABIVersion() == 0)374    setSwiftABIVersion(BA.SwiftABI);375  if (getPath().empty())376    setPath(BA.Path);377  if (!BA.ParentUmbrella.empty())378    addParentUmbrella(Targ, BA.ParentUmbrella);379  for (const auto &Client : BA.AllowableClients)380    addAllowableClient(Client, Targ);381  for (const auto &Lib : BA.RexportedLibraries)382    addReexportedLibrary(Lib, Targ);383}384 385static bool isYAMLTextStub(const FileType &Kind) {386  return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);387}388 389bool InterfaceFile::operator==(const InterfaceFile &O) const {390  if (Targets != O.Targets)391    return false;392  if (InstallName != O.InstallName)393    return false;394  if ((CurrentVersion != O.CurrentVersion) ||395      (CompatibilityVersion != O.CompatibilityVersion))396    return false;397  if (SwiftABIVersion != O.SwiftABIVersion)398    return false;399  if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)400    return false;401  if (IsAppExtensionSafe != O.IsAppExtensionSafe)402    return false;403  if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)404    return false;405  if (HasSimSupport != O.HasSimSupport)406    return false;407  if (ParentUmbrellas != O.ParentUmbrellas)408    return false;409  if (AllowableClients != O.AllowableClients)410    return false;411  if (ReexportedLibraries != O.ReexportedLibraries)412    return false;413  if (*SymbolsSet != *O.SymbolsSet)414    return false;415  // Don't compare run search paths for older filetypes that cannot express416  // them.417  if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {418    if (RPaths != O.RPaths)419      return false;420    if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))421      return false;422  }423 424  if (!llvm::equal(Documents, O.Documents,425                   [](const std::shared_ptr<InterfaceFile> &LHS,426                      const std::shared_ptr<InterfaceFile> &RHS) {427                     return *LHS == *RHS;428                   }))429    return false;430  return true;431}432