From 950454dc457febba4d021801fd05933b553f2edf Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 19 Jul 2026 21:49:32 +0800 Subject: [PATCH] Restore the CoreFoundation Swift overlay on non-Darwin --- CMakeLists.txt | 5 +++ Package.swift | 12 +++++- Sources/CoreFoundation/CMakeLists.txt | 41 +++++++++++++++++++ Sources/CoreFoundation/CoreFoundation.swift | 29 +++++++++++++ Sources/Foundation/CMakeLists.txt | 5 +++ Tests/CMakeLists.txt | 33 +++++++++++++++ .../CoreFoundation/TestCFObjectHashable.swift | 33 +++++++++++++++ 7 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 Sources/CoreFoundation/CoreFoundation.swift create mode 100644 Tests/CMakeLists.txt create mode 100644 Tests/CoreFoundation/TestCFObjectHashable.swift diff --git a/CMakeLists.txt b/CMakeLists.txt index 504499d340..5af8c66125 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,8 @@ endif() project(Foundation LANGUAGES C Swift) +include(CTest) + option(FOUNDATION_SWIFTPM_DEPS "build Windows SwiftPM dependencies via CMake" NO) if(FOUNDATION_SWIFTPM_DEPS) include(WindowsSwiftPMDependencies) @@ -249,4 +251,7 @@ include(GNUInstallDirs) include(FoundationSwiftSupport) add_subdirectory(Sources) +if(BUILD_TESTING) + add_subdirectory(Tests) +endif() add_subdirectory(cmake/modules) diff --git a/Package.swift b/Package.swift index c0ad41358e..ee6070a189 100644 --- a/Package.swift +++ b/Package.swift @@ -231,7 +231,11 @@ let package = Package( path: "Sources/CoreFoundation", exclude: [ "BlockRuntime", - "CMakeLists.txt" + "CMakeLists.txt", + // SwiftPM does not support mixed C and Swift targets. The + // CoreFoundation Swift overlay is built by CMake as part of + // the toolchain build. + "CoreFoundation.swift" ], cSettings: coreFoundationBuildSettings, linkerSettings: [.linkedLibrary("log", .when(platforms: [.android]))] @@ -339,6 +343,12 @@ let package = Package( "Testing", .target(name: "xdgTestHelper", condition: .when(platforms: [.linux, .android, .windows])) ], + exclude: [ + "CMakeLists.txt", + // The CoreFoundation Swift overlay is built and tested by + // CMake because SwiftPM cannot build mixed C/Swift targets. + "CoreFoundation" + ], resources: [ .copy("Foundation/Resources") ], diff --git a/Sources/CoreFoundation/CMakeLists.txt b/Sources/CoreFoundation/CMakeLists.txt index bb01502580..8aef9dce85 100644 --- a/Sources/CoreFoundation/CMakeLists.txt +++ b/Sources/CoreFoundation/CMakeLists.txt @@ -120,6 +120,32 @@ target_link_libraries(CoreFoundation _FoundationICU dispatch) +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_library(CoreFoundationOverlay OBJECT + CoreFoundation.swift) + # The Clang importer looks specifically for the compiler-known protocol + # CoreFoundation._CFObject. The CMake target may have a distinct name, but + # the emitted Swift module must remain CoreFoundation for imported CF + # reference types to receive their synthesized conformance. + set_target_properties(CoreFoundationOverlay PROPERTIES + Swift_MODULE_NAME CoreFoundation) + target_include_directories(CoreFoundationOverlay INTERFACE + include) + target_compile_options(CoreFoundationOverlay + PRIVATE + "SHELL:$<$:-swift-version 6>" + "SHELL:$<$:-Xfrontend -module-link-name -Xfrontend Foundation>" + "SHELL:$<$:-Xcc -fmodule-map-file=${CMAKE_CURRENT_SOURCE_DIR}/include/module.modulemap>" + INTERFACE + "SHELL:$<$:-Xcc -fmodule-map-file=${CMAKE_CURRENT_SOURCE_DIR}/include/module.modulemap>") + set_property(GLOBAL APPEND PROPERTY Foundation_EXPORTS + CoreFoundationOverlay) + if(NOT BUILD_SHARED_LIBS) + target_compile_options(CoreFoundationOverlay PRIVATE + "SHELL:$<$:-Xfrontend -public-autolink-library -Xfrontend CoreFoundation>") + endif() +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "WASI") # On WASI, we use vendored BlocksRuntime instead of the one from libdispatch add_subdirectory(BlockRuntime) @@ -146,6 +172,21 @@ install(DIRECTORY DESTINATION lib/${swift}/CoreFoundation) +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + install(FILES + $/CoreFoundation.swiftdoc + DESTINATION + lib/${swift}/${SWIFT_SYSTEM_NAME}/CoreFoundation.swiftmodule + RENAME + ${SwiftFoundation_MODULE_TRIPLE}.swiftdoc) + install(FILES + $/CoreFoundation.swiftmodule + DESTINATION + lib/${swift}/${SWIFT_SYSTEM_NAME}/CoreFoundation.swiftmodule + RENAME + ${SwiftFoundation_MODULE_TRIPLE}.swiftmodule) +endif() + if(NOT BUILD_SHARED_LIBS) install(TARGETS CoreFoundation ARCHIVE DESTINATION lib/swift_static/${SWIFT_SYSTEM_NAME} diff --git a/Sources/CoreFoundation/CoreFoundation.swift b/Sources/CoreFoundation/CoreFoundation.swift new file mode 100644 index 0000000000..23669a1a87 --- /dev/null +++ b/Sources/CoreFoundation/CoreFoundation.swift @@ -0,0 +1,29 @@ +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +@_exported import CoreFoundation + +// The Clang importer synthesizes conformance to the compiler-known +// CoreFoundation._CFObject protocol for declarations it recognizes as Core +// Foundation reference types. Both the module and protocol names are required; +// the default witnesses below then satisfy Hashable for those imported types. +public protocol _CFObject: AnyObject, Hashable {} + +extension _CFObject { + public var hashValue: Int { + Int(bitPattern: CFHash(self)) + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(hashValue) + } + + public static func == (lhs: Self, rhs: Self) -> Bool { + CFEqual(lhs, rhs) + } +} diff --git a/Sources/Foundation/CMakeLists.txt b/Sources/Foundation/CMakeLists.txt index c901e5ab24..e9cf145854 100644 --- a/Sources/Foundation/CMakeLists.txt +++ b/Sources/Foundation/CMakeLists.txt @@ -155,6 +155,11 @@ target_link_libraries(Foundation FoundationEssentials FoundationInternationalization) +if(TARGET CoreFoundationOverlay) + target_link_libraries(Foundation PRIVATE + CoreFoundationOverlay) +endif() + if(NOT BUILD_SHARED_LIBS) target_compile_options(Foundation PRIVATE "SHELL:$<$:-Xfrontend -public-autolink-library -Xfrontend CoreFoundation>") diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt new file mode 100644 index 0000000000..f4c51f1328 --- /dev/null +++ b/Tests/CMakeLists.txt @@ -0,0 +1,33 @@ +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2026 Apple Inc. and the Swift project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## See CONTRIBUTORS.md for the list of Swift project authors +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_executable(CoreFoundationHashableTests + CoreFoundation/TestCFObjectHashable.swift) + + target_compile_options(CoreFoundationHashableTests PRIVATE + "SHELL:$<$:-parse-as-library -swift-version 6>" + "SHELL:$<$:-Xcc -fmodule-map-file=${CMAKE_SOURCE_DIR}/Sources/CoreFoundation/include/module.modulemap>") + target_include_directories(CoreFoundationHashableTests PRIVATE + ${CMAKE_SOURCE_DIR}/Sources/CoreFoundation/include) + + target_link_libraries(CoreFoundationHashableTests PRIVATE + Foundation) + + add_test(NAME CoreFoundation.Hashable + COMMAND CoreFoundationHashableTests) + set_property(TEST CoreFoundation.Hashable PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_prepend:$") +endif() diff --git a/Tests/CoreFoundation/TestCFObjectHashable.swift b/Tests/CoreFoundation/TestCFObjectHashable.swift new file mode 100644 index 0000000000..bd02e9bf84 --- /dev/null +++ b/Tests/CoreFoundation/TestCFObjectHashable.swift @@ -0,0 +1,33 @@ +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors + +import CoreFoundation + +private func requireHashable(_: T.Type) {} + +@main +struct TestCFObjectHashable { + static func main() { + requireHashable(CFDictionary.self) + requireHashable(CFMutableDictionary.self) + requireHashable(CFArray.self) + requireHashable(CFMutableArray.self) + requireHashable(CFSet.self) + requireHashable(CFMutableSet.self) + requireHashable(CFString.self) + requireHashable(CFMutableString.self) + requireHashable(CFData.self) + requireHashable(CFMutableData.self) + + let lhs = CFDictionaryCreate(nil, nil, nil, 0, nil, nil)! + let rhs = CFDictionaryCreate(nil, nil, nil, 0, nil, nil)! + + precondition(lhs == rhs) + precondition(Set([lhs, rhs]).count == 1) + } +}