From 173612a89a64f364d56dadf6d9cdedcec076ee2d Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 2 Nov 2025 23:48:45 +0800 Subject: [PATCH 1/2] Add EnvManager API --- Package.swift | 151 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 35 deletions(-) diff --git a/Package.swift b/Package.swift index 7c82eb87c..c2359b3fa 100644 --- a/Package.swift +++ b/Package.swift @@ -5,30 +5,111 @@ import CompilerPluginSupport import Foundation import PackageDescription -func envEnable(_ key: String, default defaultValue: Bool = false) -> Bool { - guard let value = Context.environment[key] else { - return defaultValue +// MARK: - Env Manager + +@MainActor +final class EnvManager { + static let shared = EnvManager() + + private var domains: [String] = [] + + func register(domain: String) { + domains.append(domain) + } + + func envEnable(rawKey: String, default defaultValue: Bool, searchInDomain: Bool) -> Bool { + if searchInDomain { + for domain in domains { + let key = "\(domain.uppercased())_\(rawKey)" + guard let (value, result) = _envEnable(key) else { + continue + } + print("[Env] \(key)=\(value) -> \(result)") + return result + } + print("[Env] \(rawKey) not set -> \(defaultValue)(default)") + return defaultValue + } else { + guard let (value, result) = _envEnable(rawKey) else { + print("[Env] \(rawKey) not set -> \(defaultValue)(default)") + return defaultValue + } + print("[Env] \(rawKey)=\(value) -> \(result)") + return result + } + } + + func envValue(rawKey: String, default defaultValue: Int, searchInDomain: Bool) -> Int { + if searchInDomain { + for domain in domains { + let key = "\(domain.uppercased())_\(rawKey)" + guard let (value, result) = _envValue(key) else { + continue + } + print("[Env] \(key)=\(value) -> \(result)") + return result + } + print("[Env] \(rawKey) not set -> \(defaultValue)(default)") + return defaultValue + } else { + guard let (value, result) = _envValue(rawKey) else { + print("[Env] \(rawKey) not set -> \(defaultValue)(default)") + return defaultValue + } + print("[Env] \(rawKey)=\(value) -> \(result)") + return result + } } - if value == "1" { - return true - } else if value == "0" { - return false - } else { - return defaultValue + + private func _envEnable(_ key: String) -> (String, Bool)? { + guard let value = Context.environment[key] else { + return nil + } + let result: Bool + if value == "1" { + result = true + } else if value == "0" { + result = false + } else { + return nil + } + return (value, result) + } + + private func _envValue(_ key: String) -> (String, Int)? { + guard let value = Context.environment[key] else { + return nil + } + let result: Int + guard let result = Int(value) else { + return nil + } + return (value, result) } } +EnvManager.shared.register(domain: "OPENSWIFTUI") + +@MainActor +func envEnable(_ key: String, default defaultValue: Bool = false, searchInDomain: Bool = true) -> Bool { + EnvManager.shared.envEnable(rawKey: key, default: defaultValue, searchInDomain: searchInDomain) +} + +@MainActor +func envValue(_ key: String, default defaultValue: Int, searchInDomain: Bool = true) -> Int { + EnvManager.shared.envValue(rawKey: key, default: defaultValue, searchInDomain: searchInDomain) +} #if os(macOS) // NOTE: #if os(macOS) check is not accurate if we are cross compiling for Linux platform. So we add an env key to specify it. -let buildForDarwinPlatform = envEnable("OPENSWIFTUI_BUILD_FOR_DARWIN_PLATFORM", default: true) +let buildForDarwinPlatform = envEnable("BUILD_FOR_DARWIN_PLATFORM", default: true) #else -let buildForDarwinPlatform = envEnable("OPENSWIFTUI_BUILD_FOR_DARWIN_PLATFORM") +let buildForDarwinPlatform = envEnable("BUILD_FOR_DARWIN_PLATFORM") #endif // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/3061#issuecomment-2118821061 // By-pass https://github.com/swiftlang/swift-package-manager/issues/7580 -let isSPIDocGenerationBuild = envEnable("SPI_GENERATE_DOCS") -let isSPIBuild = envEnable("SPI_BUILD") +let isSPIDocGenerationBuild = envEnable("SPI_GENERATE_DOCS", searchInDomain: false) +let isSPIBuild = envEnable("SPI_BUILD", searchInDomain: false) // MARK: - Env and Config @@ -68,14 +149,14 @@ var sharedSwiftSettings: [SwiftSetting] = [ // MARK: - [env] OPENSWIFTUI_ANY_ATTRIBUTE_FIX // For #39 -let anyAttributeFix = envEnable("OPENSWIFTUI_ANY_ATTRIBUTE_FIX", default: !buildForDarwinPlatform) +let anyAttributeFix = envEnable("ANY_ATTRIBUTE_FIX", default: !buildForDarwinPlatform) if anyAttributeFix { sharedSwiftSettings.append(.define("OPENSWIFTUI_ANY_ATTRIBUTE_FIX")) } // MARK: - [env] OPENSWIFTUI_TARGET_RELEASE -let releaseVersion = Context.environment["OPENSWIFTUI_TARGET_RELEASE"].flatMap { Int($0) } ?? 2024 +let releaseVersion = envValue("TARGET_RELEASE", default: 2024) sharedCSettings.append(.define("OPENSWIFTUI_RELEASE", to: "\(releaseVersion)")) sharedSwiftSettings.append(.define("OPENSWIFTUI_RELEASE_\(releaseVersion)")) if releaseVersion >= 2024 { @@ -86,7 +167,7 @@ if releaseVersion >= 2024 { // MARK: - [env] OPENSWIFTUI_DEVELOPMENT -let development = envEnable("OPENSWIFTUI_DEVELOPMENT") +let development = envEnable("DEVELOPMENT") if development { sharedSwiftSettings.append(.define("OPENSWIFTUI_DEVELOPMENT")) @@ -94,7 +175,7 @@ if development { // MARK: - [env] OPENSWIFTUI_LINK_COREUI -let linkCoreUI = envEnable("OPENSWIFTUI_LINK_COREUI", default: buildForDarwinPlatform && !isSPIBuild) +let linkCoreUI = envEnable("LINK_COREUI", default: buildForDarwinPlatform && !isSPIBuild) sharedCSettings.append(.define("OPENSWIFTUI_LINK_COREUI", to: linkCoreUI ? "1" : "0")) sharedCxxSettings.append(.define("OPENSWIFTUI_LINK_COREUI", to: linkCoreUI ? "1" : "0")) if linkCoreUI { @@ -103,7 +184,7 @@ if linkCoreUI { // MARK: - [env] OPENSWIFTUI_LINK_BACKLIGHTSERVICES -let linkBacklightServices = envEnable("OPENSWIFTUI_LINK_BACKLIGHTSERVICES", default: buildForDarwinPlatform && !isSPIBuild) +let linkBacklightServices = envEnable("LINK_BACKLIGHTSERVICES", default: buildForDarwinPlatform && !isSPIBuild) sharedCSettings.append( .define( "OPENSWIFTUI_LINK_BACKLIGHTSERVICES", @@ -127,25 +208,25 @@ if linkBacklightServices { ) } -// MARK: - [env] OPENGSWIFTUI_SYMBOL_LOCATOR +// MARK: - [env] OPENSWIFTUI_SYMBOL_LOCATOR -let symbolLocatorCondition = envEnable("OPENGSWIFTUI_SYMBOL_LOCATOR", default: buildForDarwinPlatform) +let symbolLocatorCondition = envEnable("SYMBOL_LOCATOR", default: buildForDarwinPlatform) // MARK: - [env] OPENSWIFTUI_OPENCOMBINE -let openCombineCondition = envEnable("OPENSWIFTUI_OPENCOMBINE", default: !buildForDarwinPlatform) +let openCombineCondition = envEnable("OPENCOMBINE", default: !buildForDarwinPlatform) // MARK: - [env] OPENSWIFTUI_SWIFT_LOG -let swiftLogCondition = envEnable("OPENSWIFTUI_SWIFT_LOG", default: !buildForDarwinPlatform) +let swiftLogCondition = envEnable("SWIFT_LOG", default: !buildForDarwinPlatform) // MARK: - [env] OPENSWIFTUI_SWIFT_CRYPTO -let swiftCryptoCondition = envEnable("OPENSWIFTUI_SWIFT_CRYPTO", default: !buildForDarwinPlatform) +let swiftCryptoCondition = envEnable("SWIFT_CRYPTO", default: !buildForDarwinPlatform) // MARK: - [env] OPENSWIFTUI_RENDER_GTK -let renderGTKCondition = envEnable("OPENSWIFTUI_RENDER_GTK", default: !buildForDarwinPlatform) +let renderGTKCondition = envEnable("RENDER_GTK", default: !buildForDarwinPlatform) let cgtkTarget = Target.systemLibrary( name: "CGTK", @@ -158,7 +239,7 @@ let cgtkTarget = Target.systemLibrary( // MARK: - [env] OPENGSWIFTUI_SWIFTUI_RENDER -let swiftUIRenderCondition = envEnable("OPENSWIFTUI_SWIFTUI_RENDER", default: buildForDarwinPlatform) +let swiftUIRenderCondition = envEnable("SWIFTUI_RENDER", default: buildForDarwinPlatform) if swiftUIRenderCondition { sharedCSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER")) sharedCxxSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER")) @@ -169,14 +250,14 @@ if swiftUIRenderCondition { // This should be disabled for UI test target due to link issue of Testing. // Only enable for non-UI test targets. -let linkTesting = envEnable("OPENSWIFTUI_LINK_TESTING") +let linkTesting = envEnable("LINK_TESTING") if linkTesting { sharedSwiftSettings.append(.define("OPENSWIFTUI_LINK_TESTING")) } // MARK: - [env] OPENSWIFTUI_WERROR -let warningsAsErrorsCondition = envEnable("OPENSWIFTUI_WERROR", default: isXcodeEnv && development) +let warningsAsErrorsCondition = envEnable("WERROR", default: isXcodeEnv && development) if warningsAsErrorsCondition { // Hold off the werror feature as we can't avoid the concurrency warning. // Since there is no such group for diagnostic we want to ignore, we enable werror for all known groups instead. @@ -199,7 +280,7 @@ if warningsAsErrorsCondition { // MARK: - [env] OPENSWIFTUI_LIBRARY_EVOLUTION -let libraryEvolutionCondition = envEnable("OPENSWIFTUI_LIBRARY_EVOLUTION", default: buildForDarwinPlatform) +let libraryEvolutionCondition = envEnable("LIBRARY_EVOLUTION", default: buildForDarwinPlatform) if libraryEvolutionCondition && !openCombineCondition && !swiftLogCondition { // NOTE: -enable-library-evolution will cause module verify failure for `swift build`. // Either set OPENSWIFTUI_LIBRARY_EVOLUTION=0 or add `-Xswiftc -no-verify-emitted-module-interface` after `swift build` @@ -208,7 +289,7 @@ if libraryEvolutionCondition && !openCombineCondition && !swiftLogCondition { // MARK: - [env] OPENSWIFTUI_COMPATIBILITY_TEST -let compatibilityTestCondition = envEnable("OPENSWIFTUI_COMPATIBILITY_TEST") +let compatibilityTestCondition = envEnable("COMPATIBILITY_TEST") sharedCSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "1" : "0")) sharedCxxSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "1" : "0")) if !compatibilityTestCondition { @@ -217,13 +298,13 @@ if !compatibilityTestCondition { // MARK: - [env] OPENSWIFTUI_IGNORE_AVAILABILITY -let ignoreAvailability = envEnable("OPENSWIFTUI_IGNORE_AVAILABILITY", default: !isSPIDocGenerationBuild && !compatibilityTestCondition) +let ignoreAvailability = envEnable("IGNORE_AVAILABILITY", default: !isSPIDocGenerationBuild && !compatibilityTestCondition) sharedSwiftSettings.append(contentsOf: [SwiftSetting].availabilityMacroSettings(ignoreAvailability: ignoreAvailability)) // MARK: - [env] OPENSWIFTUI_INTERNAL_XR_SDK // Run @OpenSwiftUIProject/DarwinPrivateFrameworks repo's Scripts/install_internal_sdk.sh XRSimulator to install internal XRSimulator SDK -let internalXRSDK = envEnable("OPENSWIFTUI_INTERNAL_XR_SDK") +let internalXRSDK = envEnable("INTERNAL_XR_SDK") sharedCSettings.append(.define("OPENSWIFTUI_INTERNAL_XR_SDK", to: internalXRSDK ? "1" : "0")) sharedCxxSettings.append(.define("OPENSWIFTUI_INTERNAL_XR_SDK", to: internalXRSDK ? "1" : "0")) if internalXRSDK { @@ -232,7 +313,7 @@ if internalXRSDK { // MARK: - [env] OPENSWIFTUI_ENABLE_PRIVATE_IMPORTS -let enablePrivateImports = envEnable("OPENSWIFTUI_ENABLE_PRIVATE_IMPORTS", default: true) +let enablePrivateImports = envEnable("ENABLE_PRIVATE_IMPORTS", default: true) if enablePrivateImports { sharedSwiftSettings.append(.define("OPENSWIFTUI_ENABLE_PRIVATE_IMPORTS")) sharedSwiftSettings.append(.unsafeFlags(["-Xfrontend", "-enable-private-imports"])) @@ -240,7 +321,7 @@ if enablePrivateImports { // MARK: - [env] OPENSWIFTUI_ENABLE_RUNTIME_CONCURRENCY_CHECK -let enableRuntimeConcurrencyCheck = envEnable("OPENSWIFTUI_ENABLE_RUNTIME_CONCURRENCY_CHECK", default: false) +let enableRuntimeConcurrencyCheck = envEnable("ENABLE_RUNTIME_CONCURRENCY_CHECK", default: false) if enableRuntimeConcurrencyCheck { sharedSwiftSettings.append(.define("OPENSWIFTUI_ENABLE_RUNTIME_CONCURRENCY_CHECK")) } @@ -457,7 +538,7 @@ let openSwiftUISymbolDualTestsTarget = Target.testTarget( ) // Workaround iOS CI build issue (We need to disable this on iOS CI) -let supportMultiProducts: Bool = envEnable("OPENSWIFTUI_SUPPORT_MULTI_PRODUCTS", default: true) +let supportMultiProducts: Bool = envEnable("SUPPORT_MULTI_PRODUCTS", default: true) let libraryType: Product.Library.LibraryType? switch Context.environment["OPENSWIFTUI_LIBRARY_TYPE"] { @@ -591,7 +672,7 @@ extension Target { } } -let useLocalDeps = envEnable("OPENSWIFTUI_USE_LOCAL_DEPS") +let useLocalDeps = envEnable("USE_LOCAL_DEPS") let attributeGraphCondition = envEnable("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH", default: buildForDarwinPlatform && !isSPIBuild) if attributeGraphCondition { From c58837927b74e4e688bd4563710386a0d2cb69b0 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 3 Nov 2025 02:18:52 +0800 Subject: [PATCH 2/2] Refactor EnvManager and reorganize Package.swift layout --- Package.resolved | 8 +- Package.swift | 616 ++++++++++++++++++++++++++--------------------- 2 files changed, 340 insertions(+), 284 deletions(-) diff --git a/Package.resolved b/Package.resolved index b1bbb869b..c2b699d7c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "2c64b45620932621276e50344e6c5fe6c9d3f5504944717f976fdeef05f66bc5", + "originHash" : "5e56f5e0102d16fcc8dac2f347eeb346b445dfb32ffd8468e54aaa3bc8afc236", "pins" : [ { "identity" : "darwinprivateframeworks", @@ -16,7 +16,7 @@ "location" : "https://github.com/OpenSwiftUIProject/OpenAttributeGraph", "state" : { "branch" : "main", - "revision" : "6f398f0238e498ce60f98b90e99efdc27b0f0c78" + "revision" : "7c516532e7a11785e383fbee88af834d89cdb981" } }, { @@ -25,7 +25,7 @@ "location" : "https://github.com/OpenSwiftUIProject/OpenCoreGraphics", "state" : { "branch" : "main", - "revision" : "706d964f419ce293fe1c7afa9b784de0d91f7e9a" + "revision" : "cd89c292c4ed4c25d9468a12d9490cc18304ff37" } }, { @@ -43,7 +43,7 @@ "location" : "https://github.com/OpenSwiftUIProject/OpenRenderBox", "state" : { "branch" : "main", - "revision" : "a288f586e9ecac85b259d433a795d4104cb929a5" + "revision" : "1e9139ba6f5521e7fc879e410dfc4a67136fea15" } }, { diff --git a/Package.swift b/Package.swift index c2359b3fa..24e3fc43c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,137 +1,209 @@ // swift-tools-version: 6.1 -// The swift-tools-version declares the minimum version of Swift required to build this package. import CompilerPluginSupport import Foundation import PackageDescription -// MARK: - Env Manager +// MARK: - EnvManager -@MainActor -final class EnvManager { - static let shared = EnvManager() +/* GENERATED BY SPMManifestTool BEGIN */ +/* DO NOT EDIT */ + +public protocol EnvironmentProvider { + func value(forKey key: String) -> String? +} + +import PackageDescription +public struct PackageContextEnvironmentProvider: EnvironmentProvider { + public init() {} + + public func value(forKey key: String) -> String? { + Context.environment[key] + } +} + +public final class EnvManager { + nonisolated(unsafe) public static let shared = EnvManager() private var domains: [String] = [] + private var environmentProvider: EnvironmentProvider + + /// When true, append raw key as fallback when searching in domains + public var includeFallbackToRawKey: Bool = false + + private init() { + self.environmentProvider = PackageContextEnvironmentProvider() + } - func register(domain: String) { + /// Set a custom environment provider (useful for testing) + public func setEnvironmentProvider(_ provider: EnvironmentProvider) { + self.environmentProvider = provider + } + + /// Reset domains and environment provider (useful for testing) + public func reset() { + domains.removeAll() + includeFallbackToRawKey = false + self.environmentProvider = PackageContextEnvironmentProvider() + } + + public func register(domain: String) { + domains.append(domain) + } + + public func withDomain(_ domain: String, perform: () throws -> T) rethrows -> T { domains.append(domain) + defer { domains.removeAll { $0 == domain } } + return try perform() } - func envEnable(rawKey: String, default defaultValue: Bool, searchInDomain: Bool) -> Bool { - if searchInDomain { - for domain in domains { - let key = "\(domain.uppercased())_\(rawKey)" - guard let (value, result) = _envEnable(key) else { - continue - } + private func envValue(rawKey: String, default defaultValue: T?, searchInDomain: Bool, parser: (String) -> T?) -> T? { + func parseEnvValue(_ key: String) -> (String, T)? { + guard let value = environmentProvider.value(forKey: key), + let result = parser(value) else { return nil } + return (value, result) + } + var keys: [String] = searchInDomain ? domains.map { "\($0.uppercased())_\(rawKey)" } : [] + if !searchInDomain || includeFallbackToRawKey { + keys.append(rawKey) + } + for key in keys { + if let (value, result) = parseEnvValue(key) { print("[Env] \(key)=\(value) -> \(result)") return result } - print("[Env] \(rawKey) not set -> \(defaultValue)(default)") - return defaultValue - } else { - guard let (value, result) = _envEnable(rawKey) else { - print("[Env] \(rawKey) not set -> \(defaultValue)(default)") - return defaultValue - } - print("[Env] \(rawKey)=\(value) -> \(result)") - return result } + let primaryKey = keys.first ?? rawKey + if let defaultValue { + print("[Env] \(primaryKey) not set -> \(defaultValue)(default)") + } + return defaultValue } - func envValue(rawKey: String, default defaultValue: Int, searchInDomain: Bool) -> Int { - if searchInDomain { - for domain in domains { - let key = "\(domain.uppercased())_\(rawKey)" - guard let (value, result) = _envValue(key) else { - continue - } - print("[Env] \(key)=\(value) -> \(result)") - return result + public func envBoolValue(rawKey: String, default defaultValue: Bool? = nil, searchInDomain: Bool) -> Bool? { + envValue(rawKey: rawKey, default: defaultValue, searchInDomain: searchInDomain) { value in + switch value { + case "1": true + case "0": false + default: nil } - print("[Env] \(rawKey) not set -> \(defaultValue)(default)") - return defaultValue - } else { - guard let (value, result) = _envValue(rawKey) else { - print("[Env] \(rawKey) not set -> \(defaultValue)(default)") - return defaultValue - } - print("[Env] \(rawKey)=\(value) -> \(result)") - return result } } - private func _envEnable(_ key: String) -> (String, Bool)? { - guard let value = Context.environment[key] else { - return nil - } - let result: Bool - if value == "1" { - result = true - } else if value == "0" { - result = false - } else { - return nil - } - return (value, result) + public func envIntValue(rawKey: String, default defaultValue: Int? = nil, searchInDomain: Bool) -> Int? { + envValue(rawKey: rawKey, default: defaultValue, searchInDomain: searchInDomain) { Int($0) } } - private func _envValue(_ key: String) -> (String, Int)? { - guard let value = Context.environment[key] else { - return nil - } - let result: Int - guard let result = Int(value) else { - return nil - } - return (value, result) + public func envStringValue(rawKey: String, default defaultValue: String? = nil, searchInDomain: Bool) -> String? { + envValue(rawKey: rawKey, default: defaultValue, searchInDomain: searchInDomain) { $0 } } } -EnvManager.shared.register(domain: "OPENSWIFTUI") -@MainActor -func envEnable(_ key: String, default defaultValue: Bool = false, searchInDomain: Bool = true) -> Bool { - EnvManager.shared.envEnable(rawKey: key, default: defaultValue, searchInDomain: searchInDomain) +public func envBoolValue(_ key: String, default defaultValue: Bool = false, searchInDomain: Bool = true) -> Bool { + EnvManager.shared.envBoolValue(rawKey: key, default: defaultValue, searchInDomain: searchInDomain)! } -@MainActor -func envValue(_ key: String, default defaultValue: Int, searchInDomain: Bool = true) -> Int { - EnvManager.shared.envValue(rawKey: key, default: defaultValue, searchInDomain: searchInDomain) +public func envIntValue(_ key: String, default defaultValue: Int = 0, searchInDomain: Bool = true) -> Int { + EnvManager.shared.envIntValue(rawKey: key, default: defaultValue, searchInDomain: searchInDomain)! } +public func envStringValue(_ key: String, default defaultValue: String, searchInDomain: Bool = true) -> String { + EnvManager.shared.envStringValue(rawKey: key, default: defaultValue, searchInDomain: searchInDomain)! +} + +public func envStringValue(_ key: String, searchInDomain: Bool = true) -> String? { + EnvManager.shared.envStringValue(rawKey: key, searchInDomain: searchInDomain) +} + +/* GENERATED BY SPMManifestTool END */ +EnvManager.shared.register(domain: "OpenSwiftUI") + +// MARK: - Env and config + #if os(macOS) // NOTE: #if os(macOS) check is not accurate if we are cross compiling for Linux platform. So we add an env key to specify it. -let buildForDarwinPlatform = envEnable("BUILD_FOR_DARWIN_PLATFORM", default: true) +let buildForDarwinPlatform = envBoolValue("BUILD_FOR_DARWIN_PLATFORM", default: true) #else -let buildForDarwinPlatform = envEnable("BUILD_FOR_DARWIN_PLATFORM") +let buildForDarwinPlatform = envBoolValue("BUILD_FOR_DARWIN_PLATFORM") #endif // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/3061#issuecomment-2118821061 // By-pass https://github.com/swiftlang/swift-package-manager/issues/7580 -let isSPIDocGenerationBuild = envEnable("SPI_GENERATE_DOCS", searchInDomain: false) -let isSPIBuild = envEnable("SPI_BUILD", searchInDomain: false) - -// MARK: - Env and Config - -let isXcodeEnv = Context.environment["__CFBundleIdentifier"] == "com.apple.dt.Xcode" +let isSPIDocGenerationBuild = envBoolValue("SPI_GENERATE_DOCS", searchInDomain: false) +let isSPIBuild = envBoolValue("SPI_BUILD", searchInDomain: false) // Xcode use clang as linker which supports "-iframework" while SwiftPM use swiftc as linker which supports "-Fsystem" let systemFrameworkSearchFlag = isXcodeEnv ? "-iframework" : "-Fsystem" +let isXcodeEnv = envStringValue("__CFBundleIdentifier", searchInDomain: false) == "com.apple.dt.Xcode" +let development = envBoolValue("DEVELOPMENT", default: false) +let warningsAsErrorsCondition = envBoolValue("WERROR", default: isXcodeEnv && development) + +let libSwiftPath = { + // From Swift toolchain being installed or from Swift SDK. + guard let libSwiftPath = envStringValue("LIB_SWIFT_PATH") else { + // Fallback when LIB_SWIFT_PATH is not set + let swiftBinPath = envStringValue("BIN_SWIFT_PATH") ?? envStringValue("_", searchInDomain: false) ?? "/usr/bin/swift" + let swiftBinURL = URL(fileURLWithPath: swiftBinPath) + let SDKPath = swiftBinURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().path + return SDKPath.appending("/usr/lib/swift") + } + return libSwiftPath +}() + +let swiftToolchainPath = envStringValue("SWIFT_TOOLCHAIN_PATH") ?? (development ? "/Volumes/BuildMachine/swift-project" : "") +let swiftToolchainVersion = envStringValue("SWIFT_TOOLCHAIN_VERSION") ?? (development ? "6.0.2" : "") +let swiftToolchainSupported = envBoolValue("SWIFT_TOOLCHAIN_SUPPORTED", default: !swiftToolchainVersion.isEmpty) + +let releaseVersion = envIntValue("TARGET_RELEASE", default: 2024) -let swiftBinPath = Context.environment["_"] ?? "/usr/bin/swift" -let swiftBinURL = URL(fileURLWithPath: swiftBinPath) -let SDKPath = swiftBinURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent().path -let includePath = SDKPath.appending("/usr/lib/swift") +let libraryEvolutionCondition = envBoolValue("LIBRARY_EVOLUTION", default: buildForDarwinPlatform) +let compatibilityTestCondition = envBoolValue("COMPATIBILITY_TEST") + +let useLocalDeps = envBoolValue("USE_LOCAL_DEPS") +let attributeGraphCondition = envBoolValue("ATTRIBUTEGRAPH", default: buildForDarwinPlatform && !isSPIBuild) +let renderBoxCondition = envBoolValue("OPENRENDERBOX_RENDERBOX", default: buildForDarwinPlatform && !isSPIBuild) + +// For #39 +let anyAttributeFix = envBoolValue("ANY_ATTRIBUTE_FIX", default: !buildForDarwinPlatform) + +let linkCoreUI = envBoolValue("LINK_COREUI", default: buildForDarwinPlatform && !isSPIBuild) +let linkBacklightServices = envBoolValue("LINK_BACKLIGHTSERVICES", default: buildForDarwinPlatform && !isSPIBuild) +// This should be disabled for UI test target due to link issue of Testing. +// Only enable for non-UI test targets. +let linkTesting = envBoolValue("LINK_TESTING") + +let symbolLocatorCondition = envBoolValue("SYMBOL_LOCATOR", default: buildForDarwinPlatform) +let openCombineCondition = envBoolValue("OPENCOMBINE", default: !buildForDarwinPlatform) +let swiftLogCondition = envBoolValue("SWIFT_LOG", default: !buildForDarwinPlatform) +let swiftCryptoCondition = envBoolValue("SWIFT_CRYPTO", default: !buildForDarwinPlatform) +let renderGTKCondition = envBoolValue("RENDER_GTK", default: !buildForDarwinPlatform) + +let swiftUIRenderCondition = envBoolValue("SWIFTUI_RENDER", default: buildForDarwinPlatform) + +let ignoreAvailability = envBoolValue("IGNORE_AVAILABILITY", default: !isSPIDocGenerationBuild && !compatibilityTestCondition) + +// Run @OpenSwiftUIProject/DarwinPrivateFrameworks repo's Scripts/install_internal_sdk.sh XRSimulator to install internal XRSimulator SDK +let internalXRSDK = envBoolValue("INTERNAL_XR_SDK") +let enablePrivateImports = envBoolValue("ENABLE_PRIVATE_IMPORTS", default: true) +let enableRuntimeConcurrencyCheck = envBoolValue("ENABLE_RUNTIME_CONCURRENCY_CHECK") + +let bridgeFramework = envStringValue("OPENSWIFTUI_BRIDGE_FRAMEWORK", default: "SwiftUI") + +// Workaround iOS CI build issue (We need to disable this on iOS CI) +let supportMultiProducts: Bool = envBoolValue("SUPPORT_MULTI_PRODUCTS", default: true) + +// MARK: - Shared Settings var sharedCSettings: [CSetting] = [ - .unsafeFlags(["-I", includePath], .when(platforms: .nonDarwinPlatforms)), + .unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)), + .define("NDEBUG", .when(configuration: .release)), .unsafeFlags(["-fmodules"]), .define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)), .define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])), ] var sharedCxxSettings: [CXXSetting] = [ - .unsafeFlags(["-I", includePath], .when(platforms: .nonDarwinPlatforms)), + .unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)), .unsafeFlags(["-fcxx-modules"]), .define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)), .define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])), @@ -141,50 +213,89 @@ var sharedSwiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("BareSlashRegexLiterals"), .enableUpcomingFeature("InternalImportsByDefault"), .enableUpcomingFeature("InferSendableFromCaptures"), + .enableExperimentalFeature("Extern"), // FIXME: -unavailable-decl-optimization=stub is not working somehow (eg. Color.vibrancy). Dig into this later .unsafeFlags(["-unavailable-decl-optimization=stub"]), .swiftLanguageMode(.v5), -] -// MARK: - [env] OPENSWIFTUI_ANY_ATTRIBUTE_FIX + .define("OPENSWIFTUI_RELEASE_\(releaseVersion)"), +] -// For #39 -let anyAttributeFix = envEnable("ANY_ATTRIBUTE_FIX", default: !buildForDarwinPlatform) -if anyAttributeFix { - sharedSwiftSettings.append(.define("OPENSWIFTUI_ANY_ATTRIBUTE_FIX")) +// Modified from: https://github.com/swiftlang/swift/blob/main/SwiftCompilerSources/Package.swift +// +// Create a couple of symlinks to an existing Ninja build: +// +// ```shell +// cd $OPENSWIFTUI_SWIFT_TOOLCHAIN_PATH +// mkdir -p build/Default +// ln -s build//llvm- build/Default/llvm +// ln -s build//swift- build/Default/swift +// ``` +// +// where <$OPENSWIFTUI_SWIFT_TOOLCHAIN_PATH> is the parent directory of the swift repository. + +if !swiftToolchainPath.isEmpty { + sharedCSettings.append( + .unsafeFlags( + [ + "-static", + "-DCOMPILED_WITH_SWIFT", + "-DPURE_BRIDGING_MODE", + "-UIBOutlet", "-UIBAction", "-UIBInspectable", + "-I\(swiftToolchainPath)/swift/include", + "-I\(swiftToolchainPath)/swift/stdlib/public/SwiftShims", + "-I\(swiftToolchainPath)/llvm-project/llvm/include", + "-I\(swiftToolchainPath)/llvm-project/clang/include", + "-I\(swiftToolchainPath)/build/Default/swift/include", + "-I\(swiftToolchainPath)/build/Default/llvm/include", + "-I\(swiftToolchainPath)/build/Default/llvm/tools/clang/include", + "-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING", // Required to fix LLVM link issue + ] + ) + ) } - -// MARK: - [env] OPENSWIFTUI_TARGET_RELEASE - -let releaseVersion = envValue("TARGET_RELEASE", default: 2024) -sharedCSettings.append(.define("OPENSWIFTUI_RELEASE", to: "\(releaseVersion)")) -sharedSwiftSettings.append(.define("OPENSWIFTUI_RELEASE_\(releaseVersion)")) -if releaseVersion >= 2024 { - for year in 2024 ... releaseVersion { +if !swiftToolchainVersion.isEmpty { + sharedCSettings.append( + .define("OPENSWIFTUI_SWIFT_TOOLCHAIN_VERSION", to: swiftToolchainVersion) + ) +} +if swiftToolchainSupported { + sharedCSettings.append(.define("OPENSWIFTUI_SWIFT_TOOLCHAIN_SUPPORTED")) + sharedSwiftSettings.append(.define("OPENSWIFTUI_SWIFT_TOOLCHAIN_SUPPORTED")) +} +if releaseVersion >= 2021 { + for year in 2021 ... releaseVersion { sharedSwiftSettings.append(.define("OPENSWIFTUI_SUPPORT_\(year)_API")) } } +if warningsAsErrorsCondition { + sharedSwiftSettings.append(.unsafeFlags(["-warnings-as-errors"])) +} +if libraryEvolutionCondition { + // NOTE: -enable-library-evolution will cause module verify failure for `swift build`. + // Either set OPENSWIFTUI_LIBRARY_EVOLUTION=0 or add `-Xswiftc -no-verify-emitted-module-interface` after `swift build` + sharedSwiftSettings.append(.unsafeFlags(["-enable-library-evolution", "-no-verify-emitted-module-interface"])) +} +if !compatibilityTestCondition { + sharedCSettings.append(.define("OPENSWIFTUI")) + sharedCxxSettings.append(.define("OPENSWIFTUI")) + sharedSwiftSettings.append(.define("OPENSWIFTUI")) +} -// MARK: - [env] OPENSWIFTUI_DEVELOPMENT - -let development = envEnable("DEVELOPMENT") +if anyAttributeFix { + sharedSwiftSettings.append(.define("OPENSWIFTUI_ANY_ATTRIBUTE_FIX")) +} if development { sharedSwiftSettings.append(.define("OPENSWIFTUI_DEVELOPMENT")) } -// MARK: - [env] OPENSWIFTUI_LINK_COREUI - -let linkCoreUI = envEnable("LINK_COREUI", default: buildForDarwinPlatform && !isSPIBuild) sharedCSettings.append(.define("OPENSWIFTUI_LINK_COREUI", to: linkCoreUI ? "1" : "0")) sharedCxxSettings.append(.define("OPENSWIFTUI_LINK_COREUI", to: linkCoreUI ? "1" : "0")) if linkCoreUI { sharedSwiftSettings.append(.define("OPENSWIFTUI_LINK_COREUI")) } -// MARK: - [env] OPENSWIFTUI_LINK_BACKLIGHTSERVICES - -let linkBacklightServices = envEnable("LINK_BACKLIGHTSERVICES", default: buildForDarwinPlatform && !isSPIBuild) sharedCSettings.append( .define( "OPENSWIFTUI_LINK_BACKLIGHTSERVICES", @@ -208,56 +319,16 @@ if linkBacklightServices { ) } -// MARK: - [env] OPENSWIFTUI_SYMBOL_LOCATOR - -let symbolLocatorCondition = envEnable("SYMBOL_LOCATOR", default: buildForDarwinPlatform) - -// MARK: - [env] OPENSWIFTUI_OPENCOMBINE - -let openCombineCondition = envEnable("OPENCOMBINE", default: !buildForDarwinPlatform) - -// MARK: - [env] OPENSWIFTUI_SWIFT_LOG - -let swiftLogCondition = envEnable("SWIFT_LOG", default: !buildForDarwinPlatform) - -// MARK: - [env] OPENSWIFTUI_SWIFT_CRYPTO - -let swiftCryptoCondition = envEnable("SWIFT_CRYPTO", default: !buildForDarwinPlatform) - -// MARK: - [env] OPENSWIFTUI_RENDER_GTK - -let renderGTKCondition = envEnable("RENDER_GTK", default: !buildForDarwinPlatform) - -let cgtkTarget = Target.systemLibrary( - name: "CGTK", - pkgConfig: "gtk4", - providers: [ - .brew(["gtk4"]), - .apt(["libgtk-4-dev clang"]), - ] -) - -// MARK: - [env] OPENGSWIFTUI_SWIFTUI_RENDER - -let swiftUIRenderCondition = envEnable("SWIFTUI_RENDER", default: buildForDarwinPlatform) if swiftUIRenderCondition { sharedCSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER")) sharedCxxSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER")) sharedSwiftSettings.append(.define("_OPENSWIFTUI_SWIFTUI_RENDER")) } -// MARK: - [env] OPENSWIFTUI_LINK_TESTING - -// This should be disabled for UI test target due to link issue of Testing. -// Only enable for non-UI test targets. -let linkTesting = envEnable("LINK_TESTING") if linkTesting { sharedSwiftSettings.append(.define("OPENSWIFTUI_LINK_TESTING")) } -// MARK: - [env] OPENSWIFTUI_WERROR - -let warningsAsErrorsCondition = envEnable("WERROR", default: isXcodeEnv && development) if warningsAsErrorsCondition { // Hold off the werror feature as we can't avoid the concurrency warning. // Since there is no such group for diagnostic we want to ignore, we enable werror for all known groups instead. @@ -278,54 +349,148 @@ if warningsAsErrorsCondition { sharedSwiftSettings.append(.unsafeFlags(["-Wwarning", "DeprecatedDeclaration"])) // We want to use deprecated APIs in test targets) } -// MARK: - [env] OPENSWIFTUI_LIBRARY_EVOLUTION - -let libraryEvolutionCondition = envEnable("LIBRARY_EVOLUTION", default: buildForDarwinPlatform) if libraryEvolutionCondition && !openCombineCondition && !swiftLogCondition { // NOTE: -enable-library-evolution will cause module verify failure for `swift build`. // Either set OPENSWIFTUI_LIBRARY_EVOLUTION=0 or add `-Xswiftc -no-verify-emitted-module-interface` after `swift build` sharedSwiftSettings.append(.unsafeFlags(["-enable-library-evolution", "-no-verify-emitted-module-interface"])) } -// MARK: - [env] OPENSWIFTUI_COMPATIBILITY_TEST - -let compatibilityTestCondition = envEnable("COMPATIBILITY_TEST") -sharedCSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "1" : "0")) -sharedCxxSettings.append(.define("OPENSWIFTUI", to: compatibilityTestCondition ? "1" : "0")) if !compatibilityTestCondition { sharedSwiftSettings.append(.define("OPENSWIFTUI")) } -// MARK: - [env] OPENSWIFTUI_IGNORE_AVAILABILITY - -let ignoreAvailability = envEnable("IGNORE_AVAILABILITY", default: !isSPIDocGenerationBuild && !compatibilityTestCondition) sharedSwiftSettings.append(contentsOf: [SwiftSetting].availabilityMacroSettings(ignoreAvailability: ignoreAvailability)) -// MARK: - [env] OPENSWIFTUI_INTERNAL_XR_SDK - -// Run @OpenSwiftUIProject/DarwinPrivateFrameworks repo's Scripts/install_internal_sdk.sh XRSimulator to install internal XRSimulator SDK -let internalXRSDK = envEnable("INTERNAL_XR_SDK") sharedCSettings.append(.define("OPENSWIFTUI_INTERNAL_XR_SDK", to: internalXRSDK ? "1" : "0")) sharedCxxSettings.append(.define("OPENSWIFTUI_INTERNAL_XR_SDK", to: internalXRSDK ? "1" : "0")) if internalXRSDK { sharedSwiftSettings.append(.define("OPENSWIFTUI_INTERNAL_XR_SDK")) } -// MARK: - [env] OPENSWIFTUI_ENABLE_PRIVATE_IMPORTS - -let enablePrivateImports = envEnable("ENABLE_PRIVATE_IMPORTS", default: true) if enablePrivateImports { sharedSwiftSettings.append(.define("OPENSWIFTUI_ENABLE_PRIVATE_IMPORTS")) sharedSwiftSettings.append(.unsafeFlags(["-Xfrontend", "-enable-private-imports"])) } -// MARK: - [env] OPENSWIFTUI_ENABLE_RUNTIME_CONCURRENCY_CHECK - -let enableRuntimeConcurrencyCheck = envEnable("ENABLE_RUNTIME_CONCURRENCY_CHECK", default: false) if enableRuntimeConcurrencyCheck { sharedSwiftSettings.append(.define("OPENSWIFTUI_ENABLE_RUNTIME_CONCURRENCY_CHECK")) } +// MARK: - Extension + +extension Target { + func addAGSettings() { + // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message + // "could not determine executable path for bundle 'AttributeGraph.framework'" + dependencies.append(.product(name: "AttributeGraph", package: "DarwinPrivateFrameworks")) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH")) + self.swiftSettings = swiftSettings + } + + func addRBSettings() { + // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message + // "could not determine executable path for bundle 'RenderBox.framework'" + dependencies.append(.product(name: "RenderBox", package: "DarwinPrivateFrameworks")) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENRENDERBOX_RENDERBOX")) + self.swiftSettings = swiftSettings + } + + func addCoreUISettings() { + // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message + // "could not determine executable path for bundle 'CoreUI.framework'" + dependencies.append(.product(name: "CoreUI", package: "DarwinPrivateFrameworks")) + } + + func addBacklightServicesSettings() { + // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message + // "could not determine executable path for bundle 'BacklightServices.framework'" + dependencies.append( + .product( + name: "BacklightServices", + package: "DarwinPrivateFrameworks", + condition: .when(platforms: [.iOS, .visionOS]) + ) + ) + } + + func addOpenCombineSettings() { + dependencies.append(.product(name: "OpenCombine", package: "OpenCombine")) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENSWIFTUI_OPENCOMBINE")) + self.swiftSettings = swiftSettings + } + + func addSwiftLogSettings() { + dependencies.append(.product(name: "Logging", package: "swift-log")) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENSWIFTUI_SWIFT_LOG")) + self.swiftSettings = swiftSettings + } + + func addSwiftCryptoSettings() { + dependencies.append(.product(name: "Crypto", package: "swift-crypto")) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENSWIFTUI_SWIFT_CRYPTO")) + self.swiftSettings = swiftSettings + } +} + +extension [Platform] { + static var darwinPlatforms: [Platform] { + [.macOS, .iOS, .macCatalyst, .tvOS, .watchOS, .visionOS] + } + + static var nonDarwinPlatforms: [Platform] { + [.linux, .android, .wasi, .openbsd, .windows] + } +} + +extension [SwiftSetting] { + /// Settings which define commonly-used OS availability macros. + /// + /// These leverage a pseudo-experimental feature in the Swift compiler for + /// setting availability definitions, which was added in + /// [swift#65218](https://github.com/swiftlang/swift/pull/65218). + fileprivate static func availabilityMacroSettings(ignoreAvailability: Bool) -> Self { + let minimumVersion = "iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, visionOS 1.0" + return [ + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v1_0:\(ignoreAvailability ? minimumVersion : "iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v1_4:\(ignoreAvailability ? minimumVersion : "iOS 13.4, macOS 10.15.4, tvOS 13.4, watchOS 6.2")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_0:\(ignoreAvailability ? minimumVersion : "iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_1:\(ignoreAvailability ? minimumVersion : "iOS 14.2, macOS 11.0, tvOS 14.1, watchOS 7.1")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_3:\(ignoreAvailability ? minimumVersion : "iOS 14.5, macOS 11.3, tvOS 14.5, watchOS 7.4")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_0:\(ignoreAvailability ? minimumVersion : "iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_2:\(ignoreAvailability ? minimumVersion : "iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_4:\(ignoreAvailability ? minimumVersion : "iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_0:\(ignoreAvailability ? minimumVersion : "iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_1:\(ignoreAvailability ? minimumVersion : "iOS 16.1, macOS 13.0, tvOS 16.1, watchOS 9.1")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_4:\(ignoreAvailability ? minimumVersion : "iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_0:\(ignoreAvailability ? minimumVersion : "iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_1:\(ignoreAvailability ? minimumVersion : "iOS 17.1, macOS 14.1, tvOS 17.1, watchOS 10.1, visionOS 1.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_2:\(ignoreAvailability ? minimumVersion : "iOS 17.2, macOS 14.2, tvOS 17.2, watchOS 10.2, visionOS 1.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_4:\(ignoreAvailability ? minimumVersion : "iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, visionOS 1.1")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v6_0:\(ignoreAvailability ? minimumVersion : "iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0")"), + .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v7_0:\(ignoreAvailability ? minimumVersion : "iOS 19.0, macOS 16.0, tvOS 19.0, watchOS 12.0, visionOS 3.0")"), + .enableExperimentalFeature("AvailabilityMacro=_distantFuture:iOS 99.0, macOS 99.0, tvOS 99.0, watchOS 99.0, visionOS 99.0"), + ] + } +} + +// MARK: - Targets + +// MARK: - CGTK Target + +let cgtkTarget = Target.systemLibrary( + name: "CGTK", + pkgConfig: "gtk4", + providers: [ + .brew(["gtk4"]), + .apt(["libgtk-4-dev clang"]), + ] +) + // MARK: - OpenSwiftUISPI Target let openSwiftUISPITarget = Target.target( @@ -478,10 +643,6 @@ let openSwiftUICompatibilityTestTarget = Target.testTarget( swiftSettings: sharedSwiftSettings ) -// MARK: - [env] OPENSWIFTUI_BRIDGE_FRAMEWORK - -let bridgeFramework = Context.environment["OPENSWIFTUI_BRIDGE_FRAMEWORK"] ?? "SwiftUI" - // MARK: - OpenSwiftUIBridge Target let openSwiftUIBridgeTarget = Target.target( @@ -537,11 +698,10 @@ let openSwiftUISymbolDualTestsTarget = Target.testTarget( swiftSettings: sharedSwiftSettings ) -// Workaround iOS CI build issue (We need to disable this on iOS CI) -let supportMultiProducts: Bool = envEnable("SUPPORT_MULTI_PRODUCTS", default: true) +// MARK: - Products let libraryType: Product.Library.LibraryType? -switch Context.environment["OPENSWIFTUI_LIBRARY_TYPE"] { +switch envStringValue("LIBRARY_TYPE") { case "dynamic": libraryType = .dynamic case "static": @@ -562,6 +722,8 @@ if supportMultiProducts { ] } +// MARK: - Package + let package = Package( name: "OpenSwiftUI", products: products, @@ -599,8 +761,6 @@ if buildForDarwinPlatform { package.targets.append(openSwiftUICompatibilityTestTarget) } -// MARK: - SymbolLocator - if symbolLocatorCondition { package.dependencies.append( .package(url: "https://github.com/OpenSwiftUIProject/SymbolLocator.git", from: "0.2.0") @@ -613,68 +773,6 @@ if symbolLocatorCondition { } } -extension Target { - func addAGSettings() { - // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message - // "could not determine executable path for bundle 'AttributeGraph.framework'" - dependencies.append(.product(name: "AttributeGraph", package: "DarwinPrivateFrameworks")) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH")) - self.swiftSettings = swiftSettings - } - - func addRBSettings() { - // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message - // "could not determine executable path for bundle 'RenderBox.framework'" - dependencies.append(.product(name: "RenderBox", package: "DarwinPrivateFrameworks")) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENRENDERBOX_RENDERBOX")) - self.swiftSettings = swiftSettings - } - - func addCoreUISettings() { - // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message - // "could not determine executable path for bundle 'CoreUI.framework'" - dependencies.append(.product(name: "CoreUI", package: "DarwinPrivateFrameworks")) - } - - func addBacklightServicesSettings() { - // FIXME: Weird SwiftPM behavior for test Target. Otherwize we'll get the following error message - // "could not determine executable path for bundle 'BacklightServices.framework'" - dependencies.append( - .product( - name: "BacklightServices", - package: "DarwinPrivateFrameworks", - condition: .when(platforms: [.iOS, .visionOS]) - ) - ) - } - - func addOpenCombineSettings() { - dependencies.append(.product(name: "OpenCombine", package: "OpenCombine")) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENSWIFTUI_OPENCOMBINE")) - self.swiftSettings = swiftSettings - } - - func addSwiftLogSettings() { - dependencies.append(.product(name: "Logging", package: "swift-log")) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENSWIFTUI_SWIFT_LOG")) - self.swiftSettings = swiftSettings - } - - func addSwiftCryptoSettings() { - dependencies.append(.product(name: "Crypto", package: "swift-crypto")) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENSWIFTUI_SWIFT_CRYPTO")) - self.swiftSettings = swiftSettings - } -} - -let useLocalDeps = envEnable("USE_LOCAL_DEPS") - -let attributeGraphCondition = envEnable("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH", default: buildForDarwinPlatform && !isSPIBuild) if attributeGraphCondition { openSwiftUICoreTarget.addAGSettings() openSwiftUITarget.addAGSettings() @@ -686,7 +784,6 @@ if attributeGraphCondition { openSwiftUIBridgeTestTarget.addAGSettings() } -let renderBoxCondition = envEnable("OPENRENDERBOX_RENDERBOX", default: buildForDarwinPlatform && !isSPIBuild) if renderBoxCondition { openSwiftUICoreTarget.addRBSettings() openSwiftUITarget.addRBSettings() @@ -767,44 +864,3 @@ if swiftCryptoCondition { openSwiftUICoreTarget.addSwiftCryptoSettings() openSwiftUITarget.addSwiftCryptoSettings() } - -extension [Platform] { - static var darwinPlatforms: [Platform] { - [.macOS, .iOS, .macCatalyst, .tvOS, .watchOS, .visionOS] - } - - static var nonDarwinPlatforms: [Platform] { - [.linux, .android, .wasi, .openbsd, .windows] - } -} - -extension [SwiftSetting] { - /// Settings which define commonly-used OS availability macros. - /// - /// These leverage a pseudo-experimental feature in the Swift compiler for - /// setting availability definitions, which was added in - /// [swift#65218](https://github.com/swiftlang/swift/pull/65218). - fileprivate static func availabilityMacroSettings(ignoreAvailability: Bool) -> Self { - let minimumVersion = "iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, visionOS 1.0" - return [ - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v1_0:\(ignoreAvailability ? minimumVersion : "iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v1_4:\(ignoreAvailability ? minimumVersion : "iOS 13.4, macOS 10.15.4, tvOS 13.4, watchOS 6.2")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_0:\(ignoreAvailability ? minimumVersion : "iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_1:\(ignoreAvailability ? minimumVersion : "iOS 14.2, macOS 11.0, tvOS 14.1, watchOS 7.1")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v2_3:\(ignoreAvailability ? minimumVersion : "iOS 14.5, macOS 11.3, tvOS 14.5, watchOS 7.4")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_0:\(ignoreAvailability ? minimumVersion : "iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_2:\(ignoreAvailability ? minimumVersion : "iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v3_4:\(ignoreAvailability ? minimumVersion : "iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_0:\(ignoreAvailability ? minimumVersion : "iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_1:\(ignoreAvailability ? minimumVersion : "iOS 16.1, macOS 13.0, tvOS 16.1, watchOS 9.1")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v4_4:\(ignoreAvailability ? minimumVersion : "iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_0:\(ignoreAvailability ? minimumVersion : "iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_1:\(ignoreAvailability ? minimumVersion : "iOS 17.1, macOS 14.1, tvOS 17.1, watchOS 10.1, visionOS 1.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_2:\(ignoreAvailability ? minimumVersion : "iOS 17.2, macOS 14.2, tvOS 17.2, watchOS 10.2, visionOS 1.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v5_4:\(ignoreAvailability ? minimumVersion : "iOS 17.4, macOS 14.4, tvOS 17.4, watchOS 10.4, visionOS 1.1")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v6_0:\(ignoreAvailability ? minimumVersion : "iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0")"), - .enableExperimentalFeature("AvailabilityMacro=OpenSwiftUI_v7_0:\(ignoreAvailability ? minimumVersion : "iOS 19.0, macOS 16.0, tvOS 19.0, watchOS 12.0, visionOS 3.0")"), - .enableExperimentalFeature("AvailabilityMacro=_distantFuture:iOS 99.0, macOS 99.0, tvOS 99.0, watchOS 99.0, visionOS 99.0"), - ] - } -}