1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if os(Windows)
import CRT
import WinSDK
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Android)
import Android
#endif
public final class DLHandle {
#if os(Windows)
typealias Handle = HMODULE
#else
typealias Handle = UnsafeMutableRawPointer
#endif
var rawValue: Handle? = nil
init(rawValue: Handle) {
self.rawValue = rawValue
}
deinit {
precondition(rawValue == nil, "DLHandle must be closed or explicitly leaked before destroying")
}
public func close() throws {
if let handle = rawValue {
#if os(Windows)
guard FreeLibrary(handle) else {
throw DLError.close("Failed to FreeLibrary: \(GetLastError())")
}
#else
guard dlclose(handle) == 0 else {
throw DLError.close(dlerror() ?? "unknown error")
}
#endif
}
rawValue = nil
}
public func leak() {
rawValue = nil
}
}
public struct DLOpenFlags: RawRepresentable, OptionSet, Sendable {
#if !os(Windows)
public static let lazy: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LAZY)
public static let now: DLOpenFlags = DLOpenFlags(rawValue: RTLD_NOW)
public static let local: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LOCAL)
public static let global: DLOpenFlags = DLOpenFlags(rawValue: RTLD_GLOBAL)
// Platform-specific flags.
#if os(macOS)
public static let first: DLOpenFlags = DLOpenFlags(rawValue: RTLD_FIRST)
#else
public static let first: DLOpenFlags = DLOpenFlags(rawValue: 0)
#endif
#endif
public var rawValue: Int32
public init(rawValue: Int32) {
self.rawValue = rawValue
}
}
public enum DLError: Swift.Error {
case `open`(String)
case close(String)
}
public func dlopen(_ path: String?, mode: DLOpenFlags) throws -> DLHandle {
#if os(Windows)
guard let handle = path?.withCString(encodedAs: UTF16.self, LoadLibraryW) else {
throw DLError.open("LoadLibraryW failed: \(GetLastError())")
}
#else
guard let handle = dlopen(path, mode.rawValue) else {
throw DLError.open(dlerror() ?? "unknown error")
}
#endif
return DLHandle(rawValue: handle)
}
public func dlsym<T>(_ handle: DLHandle, symbol: String) -> T? {
#if os(Windows)
guard let ptr = GetProcAddress(handle.rawValue!, symbol) else {
return nil
}
#else
guard let ptr = dlsym(handle.rawValue!, symbol) else {
return nil
}
#endif
return unsafeBitCast(ptr, to: T.self)
}
public func dlclose(_ handle: DLHandle) throws {
try handle.close()
}
#if !os(Windows)
public func dlerror() -> String? {
if let err: UnsafeMutablePointer<Int8> = dlerror() {
return String(cString: err)
}
return nil
}
#endif
|