Can't use dlopen, dlsym, and dlclose

Hello
I'm new to swift, Liking the language so far, But I'm facing a problem, I'm trying to use the dlopen dlsym and dlclose to access a dll on windows, However, It does not work, Here's the code
typealias FuncLibLoad = @convention(c) () -> Void
func lib_load() {
if let handle = dlopen("Tolk.dll", RTLD_NOW) {
if let sym = dlsym(handle, "Tolk_Load") {
let res = unsafeBitCast(sym, to: FuncLibLoad.self)
res()
}
dlclose(handle)
}
}
When I try to compile, I get
[1/1] Compiling swift_tolk swift_tolk.swift
C:\Users\mohamed\projects\ls\swift_tolk\Sources\swift_tolk\swift_tolk.swift:3:21: error: cannot find 'dlopen' in scope
if let handle = dlopen("Tolk.dll", RTLD_NOW) {
^~~~~~
C:\Users\mohamed\projects\ls\swift_tolk\Sources\swift_tolk\swift_tolk.swift:3:40: error: cannot find 'RTLD_NOW' in scope
if let handle = dlopen("Tolk.dll", RTLD_NOW) {
^~~~~~~~
C:\Users\mohamed\projects\ls\swift_tolk\Sources\swift_tolk\swift_tolk.swift:4:22: error: cannot find 'dlsym' in scope
if let sym = dlsym(handle, "Tolk_Load") {
^~~~~
C:\Users\mohamed\projects\ls\swift_tolk\Sources\swift_tolk\swift_tolk.swift:8:9: error: cannot find 'dlclose' in scope
dlclose(handle)
^~~~~~~

  • OS: windows10
  • swift --version output: compnerd.org Swift version 5.5.1 (swift-5.5.1-RELEASE)
    Target: x86_64-unknown-windows-msvc

dlopen, et al, are not part of the Swift libraries. They are supplied by the underlying operating system. As far as I know, dlopen is not implemented in Windows 10, however, there are other means that gets you where you want to go. You might be able to get to dlopen under Windows 11 with the extended support for Linux, however, I'm not a Windows developer, so you would need someone else to consult with who is more familiar with the Windows architecture

Ah, Interesting, Well while doing some search, The OS function for windows is LoadLibrary, For getting function it's GetProcAddress, And closing is FreeLibrary, However, None of this seems to work, So I wonder if swift names them differently or something else?

Again, as far as I know, those functions reside in Windows system libraries, and when you make call to those functions from Swift, it's using its C-interface machinery to access them. If you are compiling, but, getting link errors, then, the system library you need is not being linked in, even though the reference to those functions are present in whatever Windows headers you are including in your project.

The functions are not part of the Swift language or standard libraries. They are external functions that can be accessed via Swift, C#, C, C++, Fortran, and all the other languages Windows supports.

Ok, Fixed by doing the following steps

  1. Create a systemLibrary module, Should look like this
    Sources/
    Cwindows_bind/
    module.modulemap
    win_bridge.h
    In module.modulemap:
    module windows [extern_c][system] {
    umbrella header "win_bridge.h"
    export *
    }
    win_bridge.h
    #include <windows.h>
    // We're defining this only because for some reason, LoadLibrary doesn't get imported into swift automaticly but GetProcAddress, And FreeLibrary does when using this header, I'm guessing do to macro related stuff.
    extern HINSTANCE load_library(const char *path) {
    return LoadLibrary(path);
    }
  2. Add to Package.swift, Should look something like this
    // swift-tools-version:5.5
    // The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "swift_tolk",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "swift_tolk",
targets: ["swift_tolk"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
.systemLibrary (
name: "Cwindows_bind"),

    .target(
        name: "swift_tolk",
        dependencies: ["Cwindows_bind"]),
]

)
3. Finally, Use in the code, After modification and extra google searching since swift doesn't automaticly convert the String I pass to load_library to const char*, So I needed to find the way to do it, And here:
In Sources/swift_tolk/swift_tolk.swift:
import windows
typealias FuncLibLoad = @convention(c) () -> Void
typealias FuncLibSpeak = @convention(c) (CWideChar, CBool) -> CBool

public func lib_load() {
if let handle = "Tolk.dll".withCString ({ (cstr) -> HINSTANCE? in
load_library(cstr)
}) {
if let sym = GetProcAddress(handle, "Tolk_Load") {
let res = unsafeBitCast(sym, to: FuncLibLoad.self)
res()
}
if let sym = GetProcAddress(handle, "Tolk_Speak") {
let res = unsafeBitCast(sym, to: FuncLibSpeak.self)
res(Unicode.Scalar("Hello, World.")!, true)
}
FreeLibrary(handle)
}
}
This compiles, But throws some LLD warnings I honestly don't understand and the functions doesn't scene to work, Here's the compilation output, And nevermind the warning about unused bool, It's just a test to get if the thing is working
[1/2] Compiling swift_tolk swift_tolk.swift
C:\Users\mohamed\projects\ls\swift_tolk\Sources\swift_tolk\swift_tolk.swift:15:13: warning: result of call to function returning 'CBool' (aka 'Bool') is unused
res(Unicode.Scalar("Hello, World.")!, true)
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[2/3] Compiling ls main.swift
lld-link: warning: C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\release\ls.build\main.swift.o: locally defined symbol imported: $s10swift_tolk8lib_loadyyF (defined in C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\release\swift_tolk.build\swift_tolk.swift.o) [LNK4217]
lld-link: warning: section name .debug_abbrev is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_info is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_line is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_loc is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_names is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_ranges is longer than 8 characters and will use a non-standard string table
lld-link: warning: section name .debug_str is longer than 8 characters and will use a non-standard string table
[3/3] Linking C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\release\ls.exe
[3/3] Build complete!
I guess I'm doing something obviously wrong, But not sure what that is.