Skip to content

Repair the Windows SwiftPM build #5068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 59 additions & 11 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@ let platformsWithThreads: [Platform] = [
.linux,
.windows,
]
var dispatchIncludeFlags: [CSetting]

var dispatchIncludeFlags: [CSetting] = []
if let environmentPath = Context.environment["DISPATCH_INCLUDE_PATH"] {
dispatchIncludeFlags = [.unsafeFlags([
dispatchIncludeFlags.append(.unsafeFlags([
"-I\(environmentPath)",
"-I\(environmentPath)/Block"
])]
]))
} else {
dispatchIncludeFlags = [
dispatchIncludeFlags.append(
.unsafeFlags([
"-I/usr/lib/swift",
"-I/usr/lib/swift/Block"
], .when(platforms: [.linux, .android]))
]
)
if let sdkRoot = Context.environment["SDKROOT"] {
dispatchIncludeFlags.append(.unsafeFlags([
"-I\(sdkRoot)usr\\include",
Expand All @@ -35,10 +36,55 @@ if let environmentPath = Context.environment["DISPATCH_INCLUDE_PATH"] {
}
}

var libxmlIncludeFlags: [CSetting] = []
if let environmentPath = Context.environment["LIBXML_INCLUDE_PATH"] {
libxmlIncludeFlags = [
.unsafeFlags([
"-I\(environmentPath)"
]),
.define("LIBXML_STATIC")
]
}

var curlIncludeFlags: [CSetting] = []
if let environmentPath = Context.environment["CURL_INCLUDE_PATH"] {
curlIncludeFlags = [
.unsafeFlags([
"-I\(environmentPath)"
]),
.define("CURL_STATICLIB")
]
}

var curlLinkFlags: [LinkerSetting] = [
.linkedLibrary("libcurl.lib", .when(platforms: [.windows])),
.linkedLibrary("zlibstatic.lib", .when(platforms: [.windows]))
]
if let environmentPath = Context.environment["CURL_LIBRARY_PATH"] {
curlLinkFlags.append(.unsafeFlags([
"-L\(environmentPath)"
]))
}
if let environmentPath = Context.environment["ZLIB_LIBRARY_PATH"] {
curlLinkFlags.append(.unsafeFlags([
"-L\(environmentPath)"
]))
}

var libxmlLinkFlags: [LinkerSetting] = [
.linkedLibrary("libxml2s.lib", .when(platforms: [.windows]))
]
if let environmentPath = Context.environment["LIBXML2_LIBRARY_PATH"] {
libxmlLinkFlags.append(.unsafeFlags([
"-L\(environmentPath)"
]))
}

let coreFoundationBuildSettings: [CSetting] = [
.headerSearchPath("internalInclude"),
.define("DEBUG", .when(configuration: .debug)),
.define("CF_BUILDING_CF"),
.define("CF_WINDOWS_EXECUTABLE_INITIALIZER", .when(platforms: [.windows])), // Ensure __CFInitialize is run even when statically linked into an executable
.define("DEPLOYMENT_ENABLE_LIBDISPATCH", .when(platforms: platformsWithThreads)),
.define("DEPLOYMENT_RUNTIME_SWIFT"),
.define("HAVE_STRUCT_TIMESPEC"),
Expand Down Expand Up @@ -216,25 +262,27 @@ let package = Package(
name: "_CFXMLInterface",
dependencies: [
"CoreFoundation",
"Clibxml2",
.target(name: "Clibxml2", condition: .when(platforms: [.linux])),
],
path: "Sources/_CFXMLInterface",
exclude: [
"CMakeLists.txt"
],
cSettings: interfaceBuildSettings
cSettings: interfaceBuildSettings + libxmlIncludeFlags,
linkerSettings: libxmlLinkFlags
),
.target(
name: "_CFURLSessionInterface",
dependencies: [
"CoreFoundation",
"Clibcurl",
.target(name: "Clibcurl", condition: .when(platforms: [.linux])),
],
path: "Sources/_CFURLSessionInterface",
exclude: [
"CMakeLists.txt"
],
cSettings: interfaceBuildSettings
cSettings: interfaceBuildSettings + curlIncludeFlags,
linkerSettings: curlLinkFlags
),
.systemLibrary(
name: "Clibxml2",
Expand Down Expand Up @@ -292,8 +340,8 @@ let package = Package(
"Foundation",
"FoundationXML",
"FoundationNetworking",
.targetItem(name: "XCTest", condition: .when(platforms: [.linux])),
"xdgTestHelper"
"XCTest",
.target(name: "xdgTestHelper", condition: .when(platforms: [.linux]))
],
resources: [
.copy("Foundation/Resources")
Expand Down
10 changes: 10 additions & 0 deletions Sources/CoreFoundation/CFRuntime.c
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,16 @@ static CFBundleRef RegisterCoreFoundationBundle(void) {
#define DLL_THREAD_DETACH 3
#define DLL_PROCESS_DETACH 0

#if CF_WINDOWS_EXECUTABLE_INITIALIZER
static void __CFWindowsExecutableInitializer(void) __attribute__ ((constructor)) __attribute__ ((used));

void __CFWindowsExecutableInitializer(void) {
static CFBundleRef cfBundle = NULL;
__CFInitialize();
cfBundle = RegisterCoreFoundationBundle();
}
#endif

int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
static CFBundleRef cfBundle = NULL;
if (dwReason == DLL_PROCESS_ATTACH) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/_CFURLSessionInterface/CFURLSessionInterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
///
//===----------------------------------------------------------------------===//

#include "CFURLSessionInterface.h"
#include "CFInternal.h"
#include "CFURLSessionInterface.h"
#include "CFString.h"
#include <curl/curl.h>

Expand Down
10 changes: 9 additions & 1 deletion Tests/Foundation/TestBundle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,16 @@ internal func testBundleName() -> String {
return testBundle().infoDictionary!["CFBundleName"] as! String
}

internal func xdgTestHelperURL() -> URL {
internal func xdgTestHelperURL() throws -> URL {
#if os(Windows)
// Adding the xdgTestHelper as a dependency of TestFoundation causes its object files (including the main function) to be linked into the test runner executable as well
// While this works on Linux due to special linker functionality, this doesn't work on Windows and results in a collision between the two main symbols
// SwiftPM also cannot support depending on this executable (to ensure it is built) without also linking its objects into the test runner
// For those reasons, using the xdgTestHelper on Windows is currently unsupported and tests that rely on it must be skipped
throw XCTSkip("xdgTestHelper is not supported during testing on Windows (test executables are not supported by SwiftPM on Windows)")
#else
testBundle().bundleURL.deletingLastPathComponent().appendingPathComponent("xdgTestHelper")
#endif
}


Expand Down
2 changes: 1 addition & 1 deletion Tests/Foundation/TestFileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,7 @@ class TestFileManager : XCTestCase {
environment[entry.key] = entry.value
}

let helper = xdgTestHelperURL()
let helper = try xdgTestHelperURL()
let (stdout, _) = try runTask([ helper.path, "--nspathfor", method, identifier ],
environment: environment)

Expand Down
2 changes: 1 addition & 1 deletion Tests/Foundation/TestHTTPCookieStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class TestHTTPCookieStorage: XCTestCase {

// Test by setting the environmental variable
let task = Process()
task.executableURL = xdgTestHelperURL()
task.executableURL = try xdgTestHelperURL()
task.arguments = ["--xdgcheck"]
var environment = ProcessInfo.processInfo.environment
let testPath = NSHomeDirectory() + "/TestXDG"
Expand Down
Loading