diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1dbd425..40b657d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,6 +159,13 @@ jobs: node-version: '24' cache: true + # This example imports Foundation and Security. Run it with the same + # externally selected toolchain pattern supported by swift-node. + - name: Install selected macOS Swift toolchain + uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0 + with: + swift-version: 6.3.3 + - name: Verify toolchain run: | swiftc --version diff --git a/packages/swift-node-unplugin/package.json b/packages/swift-node-unplugin/package.json index d1f3ee3..c3a01c8 100644 --- a/packages/swift-node-unplugin/package.json +++ b/packages/swift-node-unplugin/package.json @@ -1,6 +1,6 @@ { "name": "swift-node-unplugin", - "version": "0.2.0", + "version": "0.3.0", "description": "Unplugin adapters that build and bundle Swift Node native assets.", "type": "module", "types": "./dist/index.d.ts", @@ -102,7 +102,7 @@ "test": "vp test run" }, "peerDependencies": { - "swift-node": "^0.2.0" + "swift-node": "^0.3.0" }, "dependencies": { "unplugin": "3.3.0" diff --git a/packages/swift-node/package.json b/packages/swift-node/package.json index db56b8d..4c7666e 100644 --- a/packages/swift-node/package.json +++ b/packages/swift-node/package.json @@ -1,6 +1,6 @@ { "name": "swift-node", - "version": "0.2.0", + "version": "0.3.0", "type": "module", "description": "Node-API bridge for Swift. Write Node native addons in Swift without C++ glue.", "bin": { diff --git a/packages/swift-node/src/compiler.ts b/packages/swift-node/src/compiler.ts index f4eb5f3..de7835f 100644 --- a/packages/swift-node/src/compiler.ts +++ b/packages/swift-node/src/compiler.ts @@ -275,9 +275,30 @@ export function swiftCompileArgs( return args } +/** + * Invoke the macOS compiler through xcrun so it receives an Xcode SDK. + * Preserve an explicit SDKROOT; otherwise select the default macOS SDK. + * xcrun also honors TOOLCHAINS, which lets callers use a Swift toolchain + * installed alongside Xcode without losing access to Apple frameworks. + */ +export function swiftcInvocation( + args: string[], + platform = process.platform, + sdkRoot = process.env.SDKROOT, +): { command: string; args: string[] } { + if (platform === 'darwin') { + return { + command: 'xcrun', + args: [...(sdkRoot ? [] : ['--sdk', 'macosx']), 'swiftc', ...args], + } + } + return { command: 'swiftc', args } +} + export function compileSwift(config: CompilerConfig): string { const outputFile = path.join(config.objDir, 'swift.o') - run('swiftc', swiftCompileArgs(config), config.projectDir) + const { command, args } = swiftcInvocation(swiftCompileArgs(config)) + run(command, args, config.projectDir) return outputFile } diff --git a/packages/swift-node/test/compiler.test.ts b/packages/swift-node/test/compiler.test.ts index 271712a..3544f61 100644 --- a/packages/swift-node/test/compiler.test.ts +++ b/packages/swift-node/test/compiler.test.ts @@ -10,6 +10,7 @@ import { needsNodeGypInstall, nodeGypDevDir, swiftCompileArgs, + swiftcInvocation, } from '../src/compiler' const config = { @@ -44,6 +45,21 @@ describe('cross-platform compiler commands', () => { ) }) + it('uses xcrun for macOS Swift while preserving an explicit SDK selection', () => { + const swiftArgs = swiftCompileArgs(config, 'darwin', 'arm64') + + expect(swiftcInvocation(swiftArgs, 'darwin', '')).toEqual({ + command: 'xcrun', + args: ['--sdk', 'macosx', 'swiftc', ...swiftArgs], + }) + expect(swiftcInvocation(swiftArgs, 'darwin', '/custom/MacOSX.sdk')).toEqual({ + command: 'xcrun', + args: ['swiftc', ...swiftArgs], + }) + expect(swiftcInvocation(swiftArgs, 'linux')).toEqual({ command: 'swiftc', args: swiftArgs }) + expect(swiftcInvocation(swiftArgs, 'win32')).toEqual({ command: 'swiftc', args: swiftArgs }) + }) + it('uses the configured deployment target consistently on Apple Silicon', () => { expect(macosDeploymentTarget('10.15', 'arm64')).toBe('10.15') expect(macosDeploymentTarget('10.15', 'x64')).toBe('10.15')