diff --git a/Examples/Embedded/Package.swift b/Examples/Embedded/Package.swift index 5ae19adc..aae08002 100644 --- a/Examples/Embedded/Package.swift +++ b/Examples/Embedded/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:6.0 +// swift-tools-version:6.1 import PackageDescription let package = Package( name: "Embedded", dependencies: [ - .package(name: "JavaScriptKit", path: "../../"), + .package(name: "JavaScriptKit", path: "../../", traits: ["Embedded"]), .package(url: "https://github.com/swiftwasm/swift-dlmalloc", branch: "0.1.0"), ], targets: [ diff --git a/Examples/Embedded/build.sh b/Examples/Embedded/build.sh index f807cdbf..81840e76 100755 --- a/Examples/Embedded/build.sh +++ b/Examples/Embedded/build.sh @@ -1,5 +1,4 @@ #!/bin/bash package_dir="$(cd "$(dirname "$0")" && pwd)" -JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM=true \ - swift package --package-path "$package_dir" \ +swift package --package-path "$package_dir" \ -c release --triple wasm32-unknown-none-wasm js diff --git a/Package.swift b/Package.swift index 85a9a616..5a3a1ca5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,8 @@ -// swift-tools-version:6.0 +// swift-tools-version:6.1 import PackageDescription // NOTE: needed for embedded customizations, ideally this will not be necessary at all in the future, or can be replaced with traits -let shouldBuildForEmbedded = Context.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap(Bool.init) ?? false let useLegacyResourceBundling = Context.environment["JAVASCRIPTKIT_USE_LEGACY_RESOURCE_BUNDLING"].flatMap(Bool.init) ?? false @@ -16,22 +15,23 @@ let package = Package( .library(name: "JavaScriptEventLoopTestSupport", targets: ["JavaScriptEventLoopTestSupport"]), .plugin(name: "PackageToJS", targets: ["PackageToJS"]), ], + traits: [ + "Embedded" + ], targets: [ .target( name: "JavaScriptKit", dependencies: ["_CJavaScriptKit"], exclude: useLegacyResourceBundling ? [] : ["Runtime"], resources: useLegacyResourceBundling ? [.copy("Runtime")] : [], - cSettings: shouldBuildForEmbedded - ? [ - .unsafeFlags(["-fdeclspec"]) - ] : nil, - swiftSettings: shouldBuildForEmbedded - ? [ - .enableExperimentalFeature("Embedded"), - .enableExperimentalFeature("Extern"), - .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"]), - ] : nil + cSettings: [ + .unsafeFlags(["-fdeclspec"], .when(traits: ["Embedded"])) + ], + swiftSettings: [ + .enableExperimentalFeature("Embedded", .when(traits: ["Embedded"])), + .enableExperimentalFeature("Extern", .when(traits: ["Embedded"])), + .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"], .when(traits: ["Embedded"])), + ] ), .target(name: "_CJavaScriptKit"), .testTarget( diff --git a/Package@swift-6.0.swift b/Package@swift-6.0.swift new file mode 100644 index 00000000..85a9a616 --- /dev/null +++ b/Package@swift-6.0.swift @@ -0,0 +1,94 @@ +// swift-tools-version:6.0 + +import PackageDescription + +// NOTE: needed for embedded customizations, ideally this will not be necessary at all in the future, or can be replaced with traits +let shouldBuildForEmbedded = Context.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap(Bool.init) ?? false +let useLegacyResourceBundling = + Context.environment["JAVASCRIPTKIT_USE_LEGACY_RESOURCE_BUNDLING"].flatMap(Bool.init) ?? false + +let package = Package( + name: "JavaScriptKit", + products: [ + .library(name: "JavaScriptKit", targets: ["JavaScriptKit"]), + .library(name: "JavaScriptEventLoop", targets: ["JavaScriptEventLoop"]), + .library(name: "JavaScriptBigIntSupport", targets: ["JavaScriptBigIntSupport"]), + .library(name: "JavaScriptEventLoopTestSupport", targets: ["JavaScriptEventLoopTestSupport"]), + .plugin(name: "PackageToJS", targets: ["PackageToJS"]), + ], + targets: [ + .target( + name: "JavaScriptKit", + dependencies: ["_CJavaScriptKit"], + exclude: useLegacyResourceBundling ? [] : ["Runtime"], + resources: useLegacyResourceBundling ? [.copy("Runtime")] : [], + cSettings: shouldBuildForEmbedded + ? [ + .unsafeFlags(["-fdeclspec"]) + ] : nil, + swiftSettings: shouldBuildForEmbedded + ? [ + .enableExperimentalFeature("Embedded"), + .enableExperimentalFeature("Extern"), + .unsafeFlags(["-Xfrontend", "-emit-empty-object-file"]), + ] : nil + ), + .target(name: "_CJavaScriptKit"), + .testTarget( + name: "JavaScriptKitTests", + dependencies: ["JavaScriptKit"], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ] + ), + + .target( + name: "JavaScriptBigIntSupport", + dependencies: ["_CJavaScriptBigIntSupport", "JavaScriptKit"] + ), + .target(name: "_CJavaScriptBigIntSupport", dependencies: ["_CJavaScriptKit"]), + .testTarget( + name: "JavaScriptBigIntSupportTests", + dependencies: ["JavaScriptBigIntSupport", "JavaScriptKit"] + ), + + .target( + name: "JavaScriptEventLoop", + dependencies: ["JavaScriptKit", "_CJavaScriptEventLoop"] + ), + .target(name: "_CJavaScriptEventLoop"), + .testTarget( + name: "JavaScriptEventLoopTests", + dependencies: [ + "JavaScriptEventLoop", + "JavaScriptKit", + "JavaScriptEventLoopTestSupport", + ], + swiftSettings: [ + .enableExperimentalFeature("Extern") + ] + ), + .target( + name: "JavaScriptEventLoopTestSupport", + dependencies: [ + "_CJavaScriptEventLoopTestSupport", + "JavaScriptEventLoop", + ] + ), + .target(name: "_CJavaScriptEventLoopTestSupport"), + .testTarget( + name: "JavaScriptEventLoopTestSupportTests", + dependencies: [ + "JavaScriptKit", + "JavaScriptEventLoopTestSupport", + ] + ), + .plugin( + name: "PackageToJS", + capability: .command( + intent: .custom(verb: "js", description: "Convert a Swift package to a JavaScript package") + ), + sources: ["Sources"] + ), + ] +) diff --git a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift index 9d0b2c19..559022c2 100644 --- a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift +++ b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift @@ -161,9 +161,11 @@ struct PackageToJSPlugin: CommandPlugin { } // Build products + let selfPackage = try findSelfPackage(in: context.package) let productName = try buildOptions.product ?? deriveDefaultProduct(package: context.package) let build = try buildWasm( productName: productName, + selfPackage: selfPackage, context: context, options: buildOptions.packageOptions ) @@ -178,14 +180,6 @@ struct PackageToJSPlugin: CommandPlugin { } else { context.pluginWorkDirectoryURL.appending(path: "Package") } - guard - let selfPackage = findPackageInDependencies( - package: context.package, - id: Self.JAVASCRIPTKIT_PACKAGE_ID - ) - else { - throw PackageToJSError("Failed to find JavaScriptKit in dependencies!?") - } var make = MiniMake( explain: buildOptions.packageOptions.explain, printProgress: self.printProgress @@ -226,9 +220,11 @@ struct PackageToJSPlugin: CommandPlugin { exit(1) } + let selfPackage = try findSelfPackage(in: context.package) let productName = "\(context.package.displayName)PackageTests" let build = try buildWasm( productName: productName, + selfPackage: selfPackage, context: context, options: testOptions.packageOptions ) @@ -264,14 +260,6 @@ struct PackageToJSPlugin: CommandPlugin { } else { context.pluginWorkDirectoryURL.appending(path: "PackageTests") } - guard - let selfPackage = findPackageInDependencies( - package: context.package, - id: Self.JAVASCRIPTKIT_PACKAGE_ID - ) - else { - throw PackageToJSError("Failed to find JavaScriptKit in dependencies!?") - } var make = MiniMake( explain: testOptions.packageOptions.explain, printProgress: self.printProgress @@ -311,6 +299,7 @@ struct PackageToJSPlugin: CommandPlugin { private func buildWasm( productName: String, + selfPackage: Package, context: PluginContext, options: PackageToJS.PackageOptions ) throws @@ -331,11 +320,7 @@ struct PackageToJSPlugin: CommandPlugin { ) parameters.echoLogs = true parameters.otherSwiftcFlags = ["-color-diagnostics"] - let buildingForEmbedded = - ProcessInfo.processInfo.environment["JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM"].flatMap( - Bool.init - ) ?? false - if !buildingForEmbedded { + if !isBuildingForEmbedded(selfPackage: selfPackage) { // NOTE: We only support static linking for now, and the new SwiftDriver // does not infer `-static-stdlib` for WebAssembly targets intentionally // for future dynamic linking support. @@ -355,6 +340,31 @@ struct PackageToJSPlugin: CommandPlugin { return try self.packageManager.build(.product(productName), parameters: parameters) } + /// Check if the build is for embedded WebAssembly + private func isBuildingForEmbedded(selfPackage: Package) -> Bool { + let coreTarget = selfPackage.targets.first { $0.name == "JavaScriptKit" } + guard let swiftTarget = coreTarget as? SwiftSourceModuleTarget else { + return false + } + // SwiftPM defines "Embedded" compilation condition when `Embedded` experimental + // feature is enabled. + // TODO: This should be replaced with a proper trait-based solution in the future. + return swiftTarget.compilationConditions.contains("Embedded") + } + + /// Find JavaScriptKit package in the dependencies of the given package recursively + private func findSelfPackage(in package: Package) throws -> Package { + guard + let selfPackage = findPackageInDependencies( + package: package, + id: Self.JAVASCRIPTKIT_PACKAGE_ID + ) + else { + throw PackageToJSError("Failed to find JavaScriptKit in dependencies!?") + } + return selfPackage + } + /// Clean if the build graph of the packaging process has changed /// /// This is especially important to detect user changes debug/release