diff --git a/Package.resolved b/Package.resolved index 0d9e88e..d899750 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "24cd5d62b08d90c8d12d94ddb1d84e7d8da76f976a9b8642ccf50d81f29e8bb0", + "originHash" : "5baa2b7b03ddd25a25618a7a83046d7724b256c5e78940b0da177dd2c27e04e8", "pins" : [ { "identity" : "darwinprivateframeworks", diff --git a/Package.swift b/Package.swift index a0a4575..44ff947 100644 --- a/Package.swift +++ b/Package.swift @@ -1,52 +1,166 @@ // swift-tools-version: 6.1 -// The swift-tools-version declares the minimum version of Swift required to build this package. import Foundation import PackageDescription -func envEnable(_ key: String, default defaultValue: Bool = false) -> Bool { - guard let value = Context.environment[key] else { - return defaultValue +/* 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] } - if value == "1" { - return true - } else if value == "0" { - return false - } else { +} + +// MARK: - Env Manager + +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() + } + + /// 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() + } + + 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 + } + } + let primaryKey = keys.first ?? rawKey + if let defaultValue { + print("[Env] \(primaryKey) not set -> \(defaultValue)(default)") + } return defaultValue } + + 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 + } + } + } + + public func envIntValue(rawKey: String, default defaultValue: Int? = nil, searchInDomain: Bool) -> Int? { + envValue(rawKey: rawKey, default: defaultValue, searchInDomain: searchInDomain) { Int($0) } + } + + public func envStringValue(rawKey: String, default defaultValue: String? = nil, searchInDomain: Bool) -> String? { + envValue(rawKey: rawKey, default: defaultValue, searchInDomain: searchInDomain) { $0 } + } +} + +public func envBoolValue(_ key: String, default defaultValue: Bool = false, searchInDomain: Bool = true) -> Bool { + EnvManager.shared.envBoolValue(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: "OpenAttributeGraph") +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("OPENSWIFTUI_BUILD_FOR_DARWIN_PLATFORM", default: true) +let buildForDarwinPlatform = envBoolValue("BUILD_FOR_DARWIN_PLATFORM", default: true) #else -let buildForDarwinPlatform = envEnable("OPENSWIFTUI_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", default: false) -let isSPIBuild = envEnable("SPI_BUILD") - -// MARK: - Env and Config +let isSPIDocGenerationBuild = envBoolValue("SPI_GENERATE_DOCS", searchInDomain: false) +let isSPIBuild = envBoolValue("SPI_BUILD", searchInDomain: false) -let isXcodeEnv = Context.environment["__CFBundleIdentifier"] == "com.apple.dt.Xcode" -let development = envEnable("OPENATTRIBUTEGRAPH_DEVELOPMENT", default: false) +let isXcodeEnv = envStringValue("__CFBundleIdentifier", searchInDomain: false) == "com.apple.dt.Xcode" +let development = envBoolValue("DEVELOPMENT", default: false) +let warningsAsErrorsCondition = envBoolValue("WERROR", default: isXcodeEnv && development) -// From Swift toolchain being installed or from Swift SDK. -func detectLibSwiftPath() -> String { - guard let libSwiftPath = Context.environment["OPENATTRIBUTEGRAPH_LIB_SWIFT_PATH"] else { +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 = Context.environment["OPENATTRIBUTEGRAPH_BIN_SWIFT_PATH"] ?? Context.environment["_"] ?? "/usr/bin/swift" + 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 libSwiftPath = detectLibSwiftPath() +}() + +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 libraryEvolutionCondition = envBoolValue("LIBRARY_EVOLUTION", default: buildForDarwinPlatform) +let compatibilityTestCondition = envBoolValue("COMPATIBILITY_TEST", default: false) + +let useLocalDeps = envBoolValue("USE_LOCAL_DEPS") +let attributeGraphCondition = envBoolValue("ATTRIBUTEGRAPH", default: buildForDarwinPlatform && !isSPIBuild) + +// MARK: - Shared Settings var sharedCSettings: [CSetting] = [ .unsafeFlags(["-I", libSwiftPath], .when(platforms: .nonDarwinPlatforms)), @@ -57,9 +171,9 @@ var sharedSwiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("InternalImportsByDefault"), .enableExperimentalFeature("Extern"), .swiftLanguageMode(.v5), -] -// MARK: [env] OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_PATH + .define("OPENATTRIBUTEGRAPH_RELEASE_\(releaseVersion)"), +] // Modified from: https://github.com/swiftlang/swift/blob/main/SwiftCompilerSources/Package.swift // @@ -74,7 +188,6 @@ var sharedSwiftSettings: [SwiftSetting] = [ // // where <$OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_PATH> is the parent directory of the swift repository. -let swiftToolchainPath = Context.environment["OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_PATH"] ?? (development ? "/Volumes/BuildMachine/swift-project" : "") if !swiftToolchainPath.isEmpty { sharedCSettings.append( .unsafeFlags( @@ -95,60 +208,52 @@ if !swiftToolchainPath.isEmpty { ) ) } - -// MARK: [env] OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_VERSION - -let swiftToolchainVersion = Context.environment["OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_VERSION"] ?? (development ? "6.0.2" : "") if !swiftToolchainVersion.isEmpty { sharedCSettings.append( .define("OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_VERSION", to: swiftToolchainVersion) ) } - -// MARK: - [env] OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_SUPPORTED - -let swiftToolchainSupported = envEnable("OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_SUPPORTED", default: !swiftToolchainVersion.isEmpty) if swiftToolchainSupported { sharedCSettings.append(.define("OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_SUPPORTED")) sharedSwiftSettings.append(.define("OPENATTRIBUTEGRAPH_SWIFT_TOOLCHAIN_SUPPORTED")) } - -// MARK: - [env] OPENATTRIBUTEGRAPH_TARGET_RELEASE - -let releaseVersion = Context.environment["OPENATTRIBUTEGRAPH_TARGET_RELEASE"].flatMap { Int($0) } ?? 2024 -//sharedCSettings.append(.define("OPENATTRIBUTEGRAPH_RELEASE", to: "\(releaseVersion)")) -sharedSwiftSettings.append(.define("OPENATTRIBUTEGRAPH_RELEASE_\(releaseVersion)")) if releaseVersion >= 2021 { for year in 2021 ... releaseVersion { sharedSwiftSettings.append(.define("OPENATTRIBUTEGRAPH_SUPPORT_\(year)_API")) } } - -// MARK: - [env] OPENATTRIBUTEGRAPH_WERROR - -let warningsAsErrorsCondition = envEnable("OPENATTRIBUTEGRAPH_WERROR", default: isXcodeEnv && development) if warningsAsErrorsCondition { sharedSwiftSettings.append(.unsafeFlags(["-warnings-as-errors"])) } - -// MARK: - [env] OPENATTRIBUTEGRAPH_LIBRARY_EVOLUTION - -let libraryEvolutionCondition = envEnable("OPENATTRIBUTEGRAPH_LIBRARY_EVOLUTION", default: buildForDarwinPlatform) - if libraryEvolutionCondition { // NOTE: -enable-library-evolution will cause module verify failure for `swift build`. // Either set OPENATTRIBUTEGRAPH_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] OPENATTRIBUTEGRAPH_COMPATIBILITY_TEST - -let compatibilityTestCondition = envEnable("OPENATTRIBUTEGRAPH_COMPATIBILITY_TEST", default: false) -sharedCSettings.append(.define("OPENATTRIBUTEGRAPH", to: compatibilityTestCondition ? "1" : "0")) if !compatibilityTestCondition { + sharedCSettings.append(.define("OPENATTRIBUTEGRAPH")) sharedSwiftSettings.append(.define("OPENATTRIBUTEGRAPH")) } +// MARK: - Extension + +extension Target { + func addAGSettings() { + dependencies.append( + .product(name: "AttributeGraph", package: "DarwinPrivateFrameworks") + ) + var swiftSettings = swiftSettings ?? [] + swiftSettings.append(.define("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH")) + self.swiftSettings = swiftSettings + } +} + +extension [Platform] { + static var nonDarwinPlatforms: [Platform] { + [.linux, .android, .wasi, .openbsd, .windows] + } +} + // MARK: - Targets let openAttributeGraphTarget = Target.target( @@ -233,35 +338,20 @@ let package = Package( cxxLanguageStandard: .cxx20 ) -extension Target { - func addAGSettings() { - dependencies.append( - .product(name: "AttributeGraph", package: "DarwinPrivateFrameworks") - ) - var swiftSettings = swiftSettings ?? [] - swiftSettings.append(.define("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH")) - self.swiftSettings = swiftSettings - } -} - -if !compatibilityTestCondition { +if compatibilityTestCondition { + openAttributeGraphCompatibilityTestsTarget.addAGSettings() +} else { package.targets += [ openAttributeGraphTestsTarget, openAttributeGraphCxxTestsTarget, openAttributeGraphShimsTestsTarget, ] -} else { - openAttributeGraphCompatibilityTestsTarget.addAGSettings() } if buildForDarwinPlatform { package.targets.append(openAttributeGraphCompatibilityTestsTarget) } -let useLocalDeps = envEnable("OPENATTRIBUTEGRAPH_USE_LOCAL_DEPS") - -let attributeGraphCondition = envEnable("OPENATTRIBUTEGRAPH_ATTRIBUTEGRAPH", default: buildForDarwinPlatform && !isSPIBuild) - if attributeGraphCondition { let privateFrameworkRepo: Package.Dependency if useLocalDeps { @@ -271,8 +361,10 @@ if attributeGraphCondition { } package.dependencies.append(privateFrameworkRepo) openAttributeGraphShimsTarget.addAGSettings() - - let agVersion = Context.environment["DARWIN_PRIVATE_FRAMEWORKS_TARGET_RELEASE"].flatMap { Int($0) } ?? 2024 + + let agVersion = EnvManager.shared.withDomain("DARWIN_PRIVATE_FRAMEWORKS") { + envIntValue("TARGET_RELEASE", default: 2024) + } package.platforms = switch agVersion { case 2024: [.iOS(.v18), .macOS(.v15), .macCatalyst(.v18), .tvOS(.v18), .watchOS(.v10), .visionOS(.v2)] case 2021: [.iOS(.v15), .macOS(.v12), .macCatalyst(.v15), .tvOS(.v15), .watchOS(.v7)] @@ -282,10 +374,3 @@ if attributeGraphCondition { openAttributeGraphShimsTarget.dependencies.append("OpenAttributeGraph") package.platforms = [.iOS(.v13), .macOS(.v10_15), .macCatalyst(.v13), .tvOS(.v13), .watchOS(.v5)] } - - -extension [Platform] { - static var nonDarwinPlatforms: [Platform] { - [.linux, .android, .wasi, .openbsd, .windows] - } -}