Swift on windows linking msvc dll errors

Hello
I'm trying to link a dll that was compiled within msvc to get symbols and use in swift
However when I try to compile I get the following error
lld-link: warning: C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\debug\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\debug\swift_tolk.build\swift_tolk.swift.o) [LNK4217]
lld-link: error: undefined symbol: __declspec(dllimport) Tolk_Load

referenced by C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\debug\swift_tolk.build\swift_tolk.swift.o:($s10swift_tolk8lib_loadyyF)

lld-link: error: undefined symbol: __declspec(dllimport) Tolk_Unload

referenced by C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\debug\swift_tolk.build\swift_tolk.swift.o:($s10swift_tolk8lib_loadyyF)

lld-link: error: undefined symbol: __declspec(dllimport) Tolk_Speak

referenced by C:\Users\mohamed\projects\ls.build\x86_64-unknown-windows-msvc\debug\swift_tolk.build\swift_tolk.swift.o:($s10swift_tolk8lib_loadyyFSbSPys6UInt16VGXEfU_)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The code is
import windows

public func lib_load() {
Tolk_Load()
let str = "Hello, World".utf16
var thing: UInt16 = 0
for i in str {
thing += i
}
withUnsafePointer(to: thing) {
Tolk_Speak($0, true)
}
Tolk_Unload()
}
module.modulemap
module windows [system][extern_c] {
umbrella header "Tolk.h"
export *
}
Tolk.h
#ifndef TOLK_H
#define TOLK_H

#ifdef _EXPORTING
#define TOLK_DLL_DECLSPEC __declspec(dllexport)
#else
#define TOLK_DLL_DECLSPEC __declspec(dllimport)
#endif // _EXPORTING
#define TOLK_CALL __cdecl

#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#include <wchar.h>
#endif // __cplusplus

TOLK_DLL_DECLSPEC void TOLK_CALL Tolk_Load();

TOLK_DLL_DECLSPEC void TOLK_CALL Tolk_Unload();

#ifdef __cplusplus
TOLK_DLL_DECLSPEC bool TOLK_CALL Tolk_Speak(const wchar_t *str, bool interrupt = false);
#else
TOLK_DLL_DECLSPEC bool TOLK_CALL Tolk_Speak(const wchar_t *str, bool interrupt);
#endif // __cplusplus

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif // TOLK_H

Package.swift
// 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"], cxxSettings: [.unsafeFlags(["-LTolk.dll"])]),
]
)
And I call this by doing
import tolk_swift
tolk_swift.lib_load()
So, Am I doing something wrong?

It is difficult to follow the contents due to the formatting. Could you please clean that up?

At the very least, you are attempting to link against the wrong thing. You do not link against the library, you are supposed to link against the import library (similar to how on Darwin you use TBDs rather than the dylib).

There is no need to add the library suffix, thus you should not be adding the .dll.

Finally, your flags are incorrect. -L is for library search paths, not for linking. I assume that you do not have a directory named Tolk.dll next to the location that you are building from (as it would be a relative path, and thus would be looked up relative CWD).

Once the display is corrected, it might be easier to identify what is going on.

Oh I see, I thought I could link against a dll to make the compiler know what functions to expect.
Staticly linking is not the thing that I want, Is there a way I can load and call a dll function within swift it self?

Sorry, I had assumed dynamic linking (since you said dll in the topic). Although you can statically link C content on Windows, static linking of Swift content is not currently supported on Windows. Everything I stated applies for dynamic linking.

Oh, I understand it now, My bad, I'm just new to this stuff so did not know.
Ok, I'll now go ahead and try linking the import library and seeing the result.

Ok, I linked the import library and it works, However I'm getting weird warnings when compiling.
[1/2] Compiling swift_tolk swift_tolk.swift
[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_names 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!

The warnings are not at compile time, they are at link time. The reason is that you are using linking a library statically when building the binary. You should mark the library as a dynamic library target. As to the section warnings, that is due to the use of DWARF for debug information.

1 Like

Interesting, The warnings disappear, However, The functions does not work anymore, The functions that are exported from the dll.
Edit: Figured out the problem, Both the dll and the binding had the same names, So... Weird stuff happened.

You should mark the library as a dynamic library target

Would you be able to elaborate on this a bit? I've got a project where I'm producing a dynamic library that ultimately gets consumed by C++ code, but as it's grown the number of LNK4217 errors has ballooned to a point I wanted to address it.

In the Package.swift we have multiple internal targets that all get combined into a single top-level product. I have type: .dynamic specified on the product, but I'm still getting these link warnings for nearly every symbol being used by the top-level target that is defined within a separate target.

Here is a very simple repro case: GitHub - kteynor/SwiftLinkerWarnings: Example to reproduce linker warnings when linking a dynamic library for windows

Ah right, the targets in a single module do not respect that and will statically link without control.

Currently SPM doesn’t model the targets in a way that you can avoid the warnings sadly. This is a SPM limitation and the only workaround that I know currently is to have separate packages for each library and a separate package for the executables as the control is only available on the product level and targets within the package do not respect the products. Another option would be to use a build system with more control, such as CMake.

CC: @abertelrud @tomerd