brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · 68d73ea Raw
248 lines · cpp
1//===- Utils.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 utility functions for TextAPI Darwin operations.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/TextAPI/Utils.h"14#include "llvm/ADT/StringExtras.h"15#include "llvm/TextAPI/TextAPIError.h"16 17using namespace llvm;18using namespace llvm::MachO;19 20void llvm::MachO::replace_extension(SmallVectorImpl<char> &Path,21                                    const Twine &Extension) {22  StringRef P(Path.begin(), Path.size());23  auto ParentPath = sys::path::parent_path(P);24  auto Filename = sys::path::filename(P);25 26  if (!ParentPath.ends_with(Filename.str() + ".framework")) {27    sys::path::replace_extension(Path, Extension);28    return;29  }30  // Framework dylibs do not have a file extension, in those cases the new31  // extension is appended. e.g. given Path: "Foo.framework/Foo" and Extension:32  // "tbd", the result is "Foo.framework/Foo.tbd".33  SmallString<8> Storage;34  StringRef Ext = Extension.toStringRef(Storage);35 36  // Append '.' if needed.37  if (!Ext.empty() && Ext[0] != '.')38    Path.push_back('.');39 40  // Append extension.41  Path.append(Ext.begin(), Ext.end());42}43 44std::error_code llvm::MachO::shouldSkipSymLink(const Twine &Path,45                                               bool &Result) {46  Result = false;47  SmallString<PATH_MAX> Storage;48  auto P = Path.toNullTerminatedStringRef(Storage);49  sys::fs::file_status Stat1;50  auto EC = sys::fs::status(P.data(), Stat1);51  if (EC == std::errc::too_many_symbolic_link_levels) {52    Result = true;53    return {};54  }55 56  if (EC)57    return EC;58 59  StringRef Parent = sys::path::parent_path(P);60  while (!Parent.empty()) {61    sys::fs::file_status Stat2;62    if (auto ec = sys::fs::status(Parent, Stat2))63      return ec;64 65    if (sys::fs::equivalent(Stat1, Stat2)) {66      Result = true;67      return {};68    }69 70    Parent = sys::path::parent_path(Parent);71  }72  return {};73}74 75std::error_code76llvm::MachO::make_relative(StringRef From, StringRef To,77                           SmallVectorImpl<char> &RelativePath) {78  SmallString<PATH_MAX> Src = From;79  SmallString<PATH_MAX> Dst = To;80  if (auto EC = sys::fs::make_absolute(Src))81    return EC;82 83  if (auto EC = sys::fs::make_absolute(Dst))84    return EC;85 86  SmallString<PATH_MAX> Result;87  Src = sys::path::parent_path(From);88  auto IT1 = sys::path::begin(Src), IT2 = sys::path::begin(Dst),89       IE1 = sys::path::end(Src), IE2 = sys::path::end(Dst);90  // Ignore the common part.91  for (; IT1 != IE1 && IT2 != IE2; ++IT1, ++IT2) {92    if (*IT1 != *IT2)93      break;94  }95 96  for (; IT1 != IE1; ++IT1)97    sys::path::append(Result, "../");98 99  for (; IT2 != IE2; ++IT2)100    sys::path::append(Result, *IT2);101 102  if (Result.empty())103    Result = ".";104 105  RelativePath.swap(Result);106 107  return {};108}109 110bool llvm::MachO::isPrivateLibrary(StringRef Path, bool IsSymLink) {111  // Remove the iOSSupport and DriverKit prefix to identify public locations.112  Path.consume_front(MACCATALYST_PREFIX_PATH);113  Path.consume_front(DRIVERKIT_PREFIX_PATH);114  // Also /Library/Apple prefix for ROSP.115  Path.consume_front("/Library/Apple");116 117  if (Path.starts_with("/usr/local/lib"))118    return true;119 120  if (Path.starts_with("/System/Library/PrivateFrameworks"))121    return true;122 123  if (Path.starts_with("/System/Library/SubFrameworks"))124    return true;125 126  // Everything in /usr/lib/swift (including sub-directories) are considered127  // public.128  if (Path.consume_front("/usr/lib/swift/"))129    return false;130 131  // Only libraries directly in /usr/lib are public. All other libraries in132  // sub-directories are private.133  if (Path.consume_front("/usr/lib/"))134    return Path.contains('/');135 136  // "/System/Library/Frameworks/" is a public location.137  if (Path.starts_with("/System/Library/Frameworks/")) {138    StringRef Name, Rest;139    std::tie(Name, Rest) =140        Path.drop_front(sizeof("/System/Library/Frameworks")).split('.');141 142    // Allow symlinks to top-level frameworks.143    if (IsSymLink && Rest == "framework")144      return false;145 146    // Only top level framework are public.147    // /System/Library/Frameworks/Foo.framework/Foo ==> true148    // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true149    // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false150    // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar151    // ==> false152    // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo153    // ==> false154    return !(Rest.starts_with("framework/") &&155             (Rest.ends_with(Name) || Rest.ends_with((Name + ".tbd").str()) ||156              (IsSymLink && Rest.ends_with("Current"))));157  }158  return false;159}160 161static StringLiteral RegexMetachars = "()^$|+.[]\\{}";162 163llvm::Expected<Regex> llvm::MachO::createRegexFromGlob(StringRef Glob) {164  SmallString<128> RegexString("^");165  unsigned NumWildcards = 0;166  for (unsigned i = 0; i < Glob.size(); ++i) {167    char C = Glob[i];168    switch (C) {169    case '?':170      RegexString += '.';171      break;172    case '*': {173      const char *PrevChar = i > 0 ? Glob.data() + i - 1 : nullptr;174      NumWildcards = 1;175      ++i;176      while (i < Glob.size() && Glob[i] == '*') {177        ++NumWildcards;178        ++i;179      }180      const char *NextChar = i < Glob.size() ? Glob.data() + i : nullptr;181 182      if ((NumWildcards > 1) && (PrevChar == nullptr || *PrevChar == '/') &&183          (NextChar == nullptr || *NextChar == '/')) {184        RegexString += "(([^/]*(/|$))*)";185      } else186        RegexString += "([^/]*)";187      break;188    }189    default:190      if (RegexMetachars.contains(C))191        RegexString.push_back('\\');192      RegexString.push_back(C);193    }194  }195  RegexString.push_back('$');196  if (NumWildcards == 0)197    return make_error<StringError>("not a glob", inconvertibleErrorCode());198 199  llvm::Regex Rule = Regex(RegexString);200  std::string Error;201  if (!Rule.isValid(Error))202    return make_error<StringError>(Error, inconvertibleErrorCode());203 204  return std::move(Rule);205}206 207Expected<AliasMap>208llvm::MachO::parseAliasList(std::unique_ptr<llvm::MemoryBuffer> &Buffer) {209  SmallVector<StringRef, 16> Lines;210  AliasMap Aliases;211  Buffer->getBuffer().split(Lines, "\n", /*MaxSplit=*/-1,212                            /*KeepEmpty=*/false);213  for (const StringRef Line : Lines) {214    StringRef L = Line.trim();215    if (L.empty())216      continue;217    // Skip comments.218    if (L.starts_with("#"))219      continue;220    StringRef Symbol, Remain, Alias;221    // Base symbol is separated by whitespace.222    std::tie(Symbol, Remain) = getToken(L);223    // The Alias symbol ends before a comment or EOL.224    std::tie(Alias, Remain) = getToken(Remain, "#");225    Alias = Alias.trim();226    if (Alias.empty())227      return make_error<TextAPIError>(228          TextAPIError(TextAPIErrorCode::InvalidInputFormat,229                       ("missing alias for: " + Symbol).str()));230    SimpleSymbol AliasSym = parseSymbol(Alias);231    SimpleSymbol BaseSym = parseSymbol(Symbol);232    Aliases[{AliasSym.Name.str(), AliasSym.Kind}] = {BaseSym.Name.str(),233                                                     BaseSym.Kind};234  }235 236  return Aliases;237}238 239PathSeq llvm::MachO::getPathsForPlatform(const PathToPlatformSeq &Paths,240                                         PlatformType Platform) {241  PathSeq Result;242  for (const auto &[Path, CurrP] : Paths) {243    if (!CurrP.has_value() || CurrP.value() == Platform)244      Result.push_back(Path);245  }246  return Result;247}248