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