Linker warnings on Windows (locally defined symbol imported)

My project contains a target that links against a C library (SDL). The headers and libs are included locally in my project and I've set up the following flags:

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

With these flags, I can build my project, and, provided that the DLLs are on the path, I can also run it.

However, my build output contains an endless list of warnings such as the following:

lld-link: warning: C:\Users\steve\Developer\swift-sdl.build\x86_64-unknown-windows-msvc\debug\AdvancedText.build\main.swift.o: locally defined symbol imported: $s3SDL14AudioLibrariesVs10SetAlgebraAAMc (defined in C:\Users\steve\Developer\swift-sdl.build\x86_64-unknown-windows-msvc\debug\SDL.build\Audio\AudioLibraries.swift.o) [LNK4217]

lld-link: warning: C:\Users\steve\Developer\swift-sdl.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV7MessageVN (defined in C:\Users\steve\Developer\swift-sdl.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]

Is there something I can or should do to address these?

The issue here is that you are not defining the proper macros for SDL to indicate that the SDL library is built as a DLL. Unfortunately, from a quick glance, this seems like a bug in the SDL library itself. You could workaround it with adding -Xcc -DDECLSPEC=__declspec(dllimport) to unsafeSwiftFlags in Package.swift or just specifying them on the command line.

You definitely should try to get those cleaned up, not only because its hides actual issues, it also causes the linker to do more work, and thus taking longer and more memory to link, and it makes debugging more complicated.

Do you mean the following?

swiftSettings: [
    .unsafeFlags(["-Isdl/include"], .when(platforms: [.windows])),
    .unsafeFlags(["-Xcc", "-DDECLSPEC=__declspec(dllimport)"], .when(platforms: [.windows])),
],

This does remove the linker warnings, however, for some reason I don't understand the additional flag seems to affect the previous -I flag, as I suddenly get errors stating the SDL header files (in sdl/include) cannot be found.

I've also tried adding a .define("DECLSPEC", to: "__declspec(dllimport)") setting to cSettings or cxxSettings, but that has the same result (headers not found anymore).

On the command line, I haven't had any success at all, with the following command:

swift build --build-tests -Xswiftc -I"sdl/include" -Xcc -DDECLSPEC=__declspec(dllimport) -Xlinker -L"sdl/lib"

This builds my project as usual, but the linker warnings are still there.

In PowerShell, this command doesn't work ("The term 'dllimport' is not recognized as a name of a cmdlet, function, script file, or executable program"). I've tried adding more quotes as follows:

swift build --build-tests -Xswiftc -I"sdl/include" -Xcc -D"DECLSPEC=__declspec(dllimport)" -Xlinker -L"sdl/lib"

But the result is the same as in Command Prompt (builds, but with linker warnings).

I would suggest trying something like:

swiftSettings: [
  .unsafeFlags([
    "-I", "sdk/include",
    "-Xcc", "-DDECLSPEC=__declspec(dllimport)",
  ], .when(.platforms: [.windows]),
],

This is expected; using PowerShell is generally a bad idea unless you know what you are doing. PowerShell does not process commands the same way as cmd and you should generally assume that anyone/anything using PowerShell has miscompiled/broken something.

I would recommend building with -v and ensuring that command line invocation is correct.

Could this be unrelated to SDL at all?

I've noticed that the warnings only refer to symbols from my own SDL library (which wraps CSDL) and from the Logging (swift-log) library.

If I declare my library product as explicity dynamic, most of the warnings go away:

products: [
    .library(name: "SwiftSDL", type: .dynamic, targets: ["SDL"])
],

The only warnings that remain now refer to places where I use the Logging framework in my code:

lld-link: warning: C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV5labelACSS_tcfC (defined in C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]
lld-link: warning: C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV8logLevelAC0D0Ovs (defined in C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]
lld-link: warning: C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV5debug_8metadata4file8function4lineyAC7MessageVyXK_SDySSAC13MetadataValueOGSgyXKS2SSutF (defined in C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]
lld-link: warning: C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV7MessageVN (defined in C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]
lld-link: warning: C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\SDL.build\SDL.swift.o: locally defined symbol imported: $s7Logging6LoggerV7MessageVs32ExpressibleByStringInterpolationAAMc (defined in C:\Users\steve\Developer\swift-sdl\.build\x86_64-unknown-windows-msvc\debug\Logging.build\Logging.swift.o) [LNK4217]

Is this because Logger (and previously also my SDL wrapper library) is being statically linked and this is unsupported on Windows? (As described in Enabling Static Linking on Windows)

Yes, that is correct.

1 Like