//===- ExtendedInterfaceFile.cpp - Extended Interface File ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// Implements the Extended Interface File /// //===----------------------------------------------------------------------===// #include "ExtendedInterfaceFile.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; TAPI_NAMESPACE_INTERNAL_BEGIN static XPIKind convertSymbolKindToXPIKind(SymbolKind kind) { switch (kind) { case SymbolKind::GlobalSymbol: return XPIKind::GlobalSymbol; case SymbolKind::ObjectiveCClass: return XPIKind::ObjectiveCClass; case SymbolKind::ObjectiveCClassEHType: return XPIKind::ObjectiveCClassEHType; case SymbolKind::ObjectiveCInstanceVariable: return XPIKind::ObjectiveCInstanceVariable; } llvm_unreachable("unexpected SymbolKind kind"); } void ExtendedInterfaceFile::addSymbol(XPIKind kind, StringRef name, ArchitectureSet archs, SymbolFlags flags, XPIAccess access) { switch (kind) { default: llvm_unreachable("invalid XPI kind"); case XPIKind::GlobalSymbol: _symbols->addGlobalSymbol(name, archs, flags, access); break; case XPIKind::ObjectiveCClass: _symbols->addObjCClass(name, archs, access); break; case XPIKind::ObjectiveCClassEHType: _symbols->addObjCClassEHType(name, archs, access); break; case XPIKind::ObjectiveCInstanceVariable: _symbols->addObjCInstanceVariable(name, archs, access); break; } } ObjCClass *ExtendedInterfaceFile::addObjCClass(StringRef name, ArchitectureSet archs, XPIAccess access, ObjCClass *superClass) { return _symbols->addObjCClass(name, archs, access, superClass); } ObjCSelector *ExtendedInterfaceFile::addObjCSelector( ObjCContainer *container, StringRef name, ArchitectureSet archs, bool isInstanceMethod, bool isDynamic, XPIAccess access) { return _symbols->addObjCSelector(container, name, archs, isInstanceMethod, isDynamic, access); } ObjCCategory *ExtendedInterfaceFile::addObjCCategory(ObjCClass *baseClass, StringRef name, ArchitectureSet archs, XPIAccess access) { return _symbols->addObjCCategory(baseClass, name, archs, access); } ObjCProtocol *ExtendedInterfaceFile::addObjCProtocol(StringRef name, ArchitectureSet archs, XPIAccess access) { return _symbols->addObjCProtocol(name, archs, access); } void ExtendedInterfaceFile::addUndefinedSymbol(XPIKind kind, StringRef name, ArchitectureSet archs, SymbolFlags flags) { switch (kind) { default: llvm_unreachable("invalid XPI kind"); case XPIKind::GlobalSymbol: _undefineds->addGlobalSymbol(name, archs, flags, XPIAccess::Exported); break; case XPIKind::ObjectiveCClass: _undefineds->addObjCClass(name, archs, XPIAccess::Exported); break; case XPIKind::ObjectiveCClassEHType: _undefineds->addObjCClassEHType(name, archs, XPIAccess::Exported); break; case XPIKind::ObjectiveCInstanceVariable: _undefineds->addObjCInstanceVariable(name, archs, XPIAccess::Exported); break; } } bool ExtendedInterfaceFile::contains(XPIKind kind, StringRef name, XPI const **result) const { if (auto *it = _symbols->findSymbol(kind, name)) { if (result) *result = it; return true; } return false; } Expected> ExtendedInterfaceFile::merge(const ExtendedInterfaceFile *otherInterface, bool allowArchitectureMerges) const { // Verify files can be merged. if (getFileType() != otherInterface->getFileType()) { return make_error("file types do not match", inconvertibleErrorCode()); } if (!allowArchitectureMerges) { if ((getArchitectures() & otherInterface->getArchitectures()) != Architecture::unknown) { return make_error("architectures overlap", inconvertibleErrorCode()); } } if (getPlatform() != otherInterface->getPlatform()) { return make_error("platforms do not match", inconvertibleErrorCode()); } if (getInstallName() != otherInterface->getInstallName()) { return make_error("install names do not match", inconvertibleErrorCode()); } if (getCurrentVersion() != otherInterface->getCurrentVersion()) { return make_error("current versions do not match", inconvertibleErrorCode()); } if (getCompatibilityVersion() != otherInterface->getCompatibilityVersion()) { return make_error("compatibility versions do not match", inconvertibleErrorCode()); } if (getSwiftABIVersion() != otherInterface->getSwiftABIVersion()) { return make_error("swift ABI versions do not match", inconvertibleErrorCode()); } if (isTwoLevelNamespace() != otherInterface->isTwoLevelNamespace()) { return make_error("two level namespace flags do not match", inconvertibleErrorCode()); } if (isApplicationExtensionSafe() != otherInterface->isApplicationExtensionSafe()) { return make_error( "application extension safe flags do not match", inconvertibleErrorCode()); } if (isInstallAPI() != otherInterface->isInstallAPI()) { return make_error("installapi flags do not match", inconvertibleErrorCode()); } if (getObjCConstraint() != otherInterface->getObjCConstraint()) { return make_error("installapi flags do not match", inconvertibleErrorCode()); } if (getParentUmbrella() != otherInterface->getParentUmbrella()) { return make_error("parent umbrellas do not match", inconvertibleErrorCode()); } std::unique_ptr interface(new ExtendedInterfaceFile()); interface->setFileType(getFileType()); interface->setPath(getPath()); interface->setPlatform(getPlatform()); interface->setInstallName(getInstallName()); interface->setCurrentVersion(getCurrentVersion()); interface->setCompatibilityVersion(getCompatibilityVersion()); interface->setSwiftABIVersion(getSwiftABIVersion()); interface->setTwoLevelNamespace(isTwoLevelNamespace()); interface->setApplicationExtensionSafe(isApplicationExtensionSafe()); interface->setInstallAPI(isInstallAPI()); interface->setObjCConstraint(getObjCConstraint()); interface->setParentUmbrella(getParentUmbrella()); interface->setArchitectures(getArchitectures() | otherInterface->getArchitectures()); for (const auto &lib : allowableClients()) interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); for (const auto &lib : otherInterface->allowableClients()) interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); for (const auto &lib : reexportedLibraries()) interface->addReexportedLibrary(lib.getInstallName(), lib.getArchitectures()); for (const auto &lib : otherInterface->reexportedLibraries()) interface->addReexportedLibrary(lib.getInstallName(), lib.getArchitectures()); for (const auto &uuid : uuids()) interface->addUUID(uuid.first, uuid.second); for (const auto &uuid : otherInterface->uuids()) interface->addUUID(uuid.first, uuid.second); for (const auto *symbol : symbols()) interface->addSymbol(symbol->getKind(), symbol->getName(), symbol->getArchitectures(), symbol->getSymbolFlags(), symbol->getAccess()); for (const auto *symbol : otherInterface->symbols()) interface->addSymbol(symbol->getKind(), symbol->getName(), symbol->getArchitectures(), symbol->getSymbolFlags(), symbol->getAccess()); for (const auto *symbol : undefineds()) interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), symbol->getArchitectures(), symbol->getSymbolFlags()); for (const auto *symbol : otherInterface->undefineds()) interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), symbol->getArchitectures(), symbol->getSymbolFlags()); return std::move(interface); } bool ExtendedInterfaceFile::removeSymbol(XPIKind kind, StringRef name) { return _symbols->removeSymbol(kind, name); } bool ExtendedInterfaceFile::removeSymbol(SymbolKind kind, StringRef name) { return removeSymbol(convertSymbolKindToXPIKind(kind), name); } void ExtendedInterfaceFile::printSymbolsForArch(Architecture arch) const { std::vector exports; for (const auto *symbol : this->exports()) { if (!symbol->getArchitectures().has(arch)) continue; switch (symbol->getKind()) { case XPIKind::GlobalSymbol: exports.emplace_back(symbol->getName()); break; case XPIKind::ObjectiveCClass: if (getPlatform() == Platform::macOS && arch == Architecture::i386) { exports.emplace_back(".objc_class_name_" + symbol->getName().str()); } else { exports.emplace_back("_OBJC_CLASS_$_" + symbol->getName().str()); exports.emplace_back("_OBJC_METACLASS_$_" + symbol->getName().str()); } break; case XPIKind::ObjectiveCClassEHType: exports.emplace_back("_OBJC_EHTYPE_$_" + symbol->getName().str()); break; case XPIKind::ObjectiveCInstanceVariable: exports.emplace_back("_OBJC_IVAR_$_" + symbol->getName().str()); break; default: llvm_unreachable("Unexpected symbol kind for exported symbols"); } } sort(exports); for (auto &symbol : exports) outs() << symbol << "\n"; } void ExtendedInterfaceFile::printSymbols(ArchitectureSet archs) const { if (archs.empty()) archs = getArchitectures(); if (getArchitectures().contains(archs)) { bool firstItr = true; for (auto arch : getArchitectures()) { if (!archs.has(arch)) continue; if (firstItr) firstItr = false; else outs() << "\n"; if (archs.count() > 1) outs() << getPath() << " (for architecture " << arch << "):\n"; printSymbolsForArch(arch); } } else { outs() << "file: " << getPath() << " does not contain architecture: " << archs << "\n"; } } TAPI_NAMESPACE_INTERNAL_END