Linking DLLs on Windows

I’m trying to link SDL2 which on Windows is distributed as a compressed folder with headers and a dll. I’m passing -Xlinker ‘-L Libraries\SDL2-2.28.5\lib\x86’ to swift run but I’m getting an error that says ‘SDL2.lib’: no such file or directory.

I also tried to avoid this and link at runtime but there doesn’t seem to be a way to tell the linker to ignore undefined symbols.

How do I tell swift where to find the .lib properly?

I have this in my Package.swift:

.target(
     // ...
    swiftSettings: [.unsafeFlags(["-Isdl/include"]),
    linkerSettings: [.unsafeFlags(["-Lsdl/lib"])
)

After building, I copy the DLLs to the same directory as my executable.

Did you really have a corresponding LIB file (which is called an import library) along with the DLL? If not, you first need to create it from the DLL with LIB /DEF as described here.

I tried putting it in unsafe linker flags but I'm still getting the error :confused:

It definitely looks like the lib file is there:

You should not pass it as a single flag like this. Break it into two string elements or delete the space inside.

Thanks, I have tried it without the space before but it didn't work. However, I never tried both not having that space and choosing the x64 directory. Not sure why I needed that one since I usually don't use Windows or intel processors so I assumed I would need the x86 folder.

x64 represents for AMD64/x86_64, which is the architecture that the Swift on Windows SDK is built against. As long as you’re not building a x86 variant of Swift SDK yourself, your app can only support x64 targets, and should stick to use x64 versions of libraries.

1 Like

By the way, how can I do this for the standard library? The exe produced is somehow 77kb which is definitely not including the stdlib considering even Zig uses a lot more when statically linking.

-static-stdlib doesn't seem to do anything so I assume I have to download a swift stdlib dll from somewhere and also include it with my program (or copy it from somewhere), since it's not placed in the build folder? Where can I find it?

Dynamically linking the stdlib and the way C interop results in mismatched integer signedness for some types vs how they're imported on unix seems like a performance compromise and lots of pain, I feel like Swift wasn't exactly intended to exist on Windows

Static linking for the standard library is not supported currently on Windows. There are improvements that are required to the compiler to support that and that is not yet complete. Someday that might be possible, but still would be generally not the ideal case (much like how statically linking the standard library is not a supported mode on macOS).

The standard library is installed to %ProgramFiles%\Swift\runtime-development\usr\bin in the current stable releases, and is in %LocalAppData%\Programs\Swift\Runtimes\0.0.0\usr\bin. Additionally, in the current development versions, the runtime is also bundled as a MSM so that you can simply include the MSM into your installer for redistribution with your application.

Could you explain how you see type mismatches as a performance compromise? Also, can you share a concrete example that you are finding to have mismatching signedness? Swift was designed to exist on different platforms which is why those base system ABI requirements are something that become obvious when porting code that is Unix-centric. The language is designed to give you a safer environment and the compiler highlights ways that your assumptions may not hold.

1 Like

Sorry, I was referring to dynamic linking of the stdlib as a performance compromise and sightedness as painful, I assume the type conversions would be optimized away - I definitely didn't express that very clearly.

Of course, here is the signature of a C function with mismatched signedness:

func SDL_CreateWindow(_ title: UnsafePointer<CChar>!, _ x: Int32, _ y: Int32, _ w: Int32, _ h: Int32, _ flags: Uint32) -> OpaquePointer!

the flags are a typedef enum assuming uint32 to be the default, and this seems to be different on windows for whatever reason. This is a problem on unix like systems too, it's just worse here.

In my opinion typealias CInt = Int32 is the problem, because it assumes C numbers are equivalent to Swift types, and this is not true even on macOS.

C libraries are written with the type inconsistency in mind. There is nothing Swift can do because C interoperability is inherently unsafe, wrapping numbers in constructors doesn't do much to fix that.

I don't agree with the dynamic linkage to the standard library as a performance compromise. In fact, it is the exact opposite. If there is more than a single instance of Swift in use, the dynamic linking would be a boon. The pages are can be shared, the library itself may even be mapped and the OS can just re-use the pages. Static linking isn't always a benefit. The dynamic linking can reduce the working set and sometimes even help with load times.

That is the correct, desired behaviour. enums on Windows are signed, not unsigned by default. If you want an unsigned enum, you need to use extensions in the C library. flags should be Int32 on Windows as that is what is expected. It is not "for whatever reason", this is a fundamental difference due to the ABI on Windows. This just makes it explicit. If you are saying that the type is imported with a mismatch rather than the imported signature is different across Windows and Linux, that sounds like a bug.

You are of course welcome to your opinion. My opinion is that this is a pretty reasonable assumption. int is expected to be a signed 32-bit integer on most environments.

As you say, those inconsistencies are library dependent, and there is no generic mapping. To accommodate that, there is the concept of overlay libraries which allow you to make those explicit and handle them as a library specific behaviour.