mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
137 lines
3.6 KiB
Swift
137 lines
3.6 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SwiftExtensions
|
|
|
|
#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
|
|
|
|
package final class DLHandle: Sendable {
|
|
fileprivate struct Handle: @unchecked Sendable {
|
|
#if os(Windows)
|
|
let handle: HMODULE
|
|
#else
|
|
let handle: UnsafeMutableRawPointer
|
|
#endif
|
|
}
|
|
|
|
fileprivate let rawValue: ThreadSafeBox<Handle?>
|
|
|
|
fileprivate init(rawValue: Handle) {
|
|
self.rawValue = .init(initialValue: rawValue)
|
|
}
|
|
|
|
deinit {
|
|
precondition(rawValue.value == nil, "DLHandle must be closed or explicitly leaked before destroying")
|
|
}
|
|
|
|
/// The handle must not be used anymore after calling `close`.
|
|
package func close() throws {
|
|
try rawValue.withLock { rawValue in
|
|
if let handle = rawValue {
|
|
#if os(Windows)
|
|
guard FreeLibrary(handle.handle) else {
|
|
throw DLError.close("Failed to FreeLibrary: \(GetLastError())")
|
|
}
|
|
#else
|
|
guard dlclose(handle.handle) == 0 else {
|
|
throw DLError.close(dlerror() ?? "unknown error")
|
|
}
|
|
#endif
|
|
}
|
|
rawValue = nil
|
|
}
|
|
}
|
|
|
|
/// The handle must not be used anymore after calling `leak`.
|
|
package func leak() {
|
|
rawValue.value = nil
|
|
}
|
|
}
|
|
|
|
package struct DLOpenFlags: RawRepresentable, OptionSet, Sendable {
|
|
|
|
#if !os(Windows)
|
|
package static let lazy: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LAZY)
|
|
package static let now: DLOpenFlags = DLOpenFlags(rawValue: RTLD_NOW)
|
|
package static let local: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LOCAL)
|
|
package static let global: DLOpenFlags = DLOpenFlags(rawValue: RTLD_GLOBAL)
|
|
|
|
// Platform-specific flags.
|
|
#if os(macOS)
|
|
package static let first: DLOpenFlags = DLOpenFlags(rawValue: RTLD_FIRST)
|
|
#else
|
|
package static let first: DLOpenFlags = DLOpenFlags(rawValue: 0)
|
|
#endif
|
|
#endif
|
|
|
|
package var rawValue: Int32
|
|
|
|
package init(rawValue: Int32) {
|
|
self.rawValue = rawValue
|
|
}
|
|
}
|
|
|
|
package enum DLError: Swift.Error {
|
|
case `open`(String)
|
|
case close(String)
|
|
}
|
|
|
|
package 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: DLHandle.Handle(handle: handle))
|
|
}
|
|
|
|
package func dlsym<T>(_ handle: DLHandle, symbol: String) -> T? {
|
|
#if os(Windows)
|
|
guard let ptr = GetProcAddress(handle.rawValue.value!.handle, symbol) else {
|
|
return nil
|
|
}
|
|
#else
|
|
guard let ptr = dlsym(handle.rawValue.value!.handle, symbol) else {
|
|
return nil
|
|
}
|
|
#endif
|
|
return unsafeBitCast(ptr, to: T.self)
|
|
}
|
|
|
|
package func dlclose(_ handle: DLHandle) throws {
|
|
try handle.close()
|
|
}
|
|
|
|
#if !os(Windows)
|
|
package func dlerror() -> String? {
|
|
if let err: UnsafeMutablePointer<Int8> = dlerror() {
|
|
return String(cString: err)
|
|
}
|
|
return nil
|
|
}
|
|
#endif
|