Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/actions/setup-windows-toolchain/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ runs:
uses: actions/cache@v4
with:
path: ~/AppData/Local/Programs/Swift
key: swift-node-swift-windows-${{ runner.arch }}-6.3.3-RELEASE-v1
key: swift-node-swift-windows-${{ runner.arch }}-6.3.3-RELEASE-v2

- name: Configure restored Swift SDK
if: steps.swift-cache.outputs.cache-hit == 'true'
Expand All @@ -48,6 +48,7 @@ runs:
with:
swift-version: swift-6.3.3-release
swift-build: 6.3.3-RELEASE
build_arch: ${{ runner.arch == 'ARM64' && 'arm64' || 'amd64' }}

# node-gyp downloads Windows Node headers and node.lib on demand into this
# directory. The swift-node CLI needs those files for every C++ build.
Expand Down
30 changes: 26 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,16 @@ jobs:
node-version: '24'
cache: true

# Match the Swift toolchain selected by `swift-node init`'s generated CI.
- name: Prepare Windows native toolchain
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-toolchain

- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
if: runner.os != 'Windows'
with:
swift-version: 6.3.3

- run: node scripts/run-without-node-warnings.mjs vp install
- run: node scripts/run-without-node-warnings.mjs vp -C packages/swift-node pack
- run: node scripts/run-without-node-warnings.mjs vp -C packages/swift-node test
Expand Down Expand Up @@ -107,10 +113,16 @@ jobs:
node-version: '24'
cache: true

# Match the Swift toolchain selected by `swift-node init`'s generated CI.
- name: Prepare Windows native toolchain
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-toolchain

- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
if: runner.os != 'Windows'
with:
swift-version: 6.3.3

- name: Verify toolchain
run: |
swiftc --version
Expand Down Expand Up @@ -159,10 +171,8 @@ 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
# Match the Swift toolchain selected by `swift-node init`'s generated CI.
- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
with:
swift-version: 6.3.3

Expand Down Expand Up @@ -213,10 +223,16 @@ jobs:
node-version: '24'
cache: true

# Match the Swift toolchain selected by `swift-node init`'s generated CI.
- name: Prepare Windows native toolchain
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-toolchain

- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
if: runner.os != 'Windows'
with:
swift-version: 6.3.3

- name: Verify toolchain
run: |
swiftc --version
Expand Down Expand Up @@ -259,10 +275,16 @@ jobs:
node-version: '24'
cache: true

# Match the Swift toolchain selected by `swift-node init`'s generated CI.
- name: Prepare Windows native toolchain
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-toolchain

- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
if: runner.os != 'Windows'
with:
swift-version: 6.3.3

- name: Verify toolchain
run: |
swiftc --version
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Prebuilt binaries make installation faster and more reproducible, and avoid requ

By default, Linux packages include the Swift `.so` runtime libraries and Windows packages include the Swift `.dll` runtime libraries beside their target-qualified `.node` binary. This lets consumers load the package without separately installing Swift. Set `"swiftNode": { "shipSwiftRuntime": false }` only when your deployment supplies a compatible Swift runtime. Linux prebuilds use a glibc baseline; Alpine and other musl systems build locally into a distinct `{platform}-{arch}-musl` target directory.

Publish macOS binaries as `dist_swift-node/{moduleName}.darwin-{arch}.node`, or `dist/{moduleName}.darwin-{arch}.node` when using tsdown. Linux and Windows retain `/{platform}-{arch}/` so their Swift runtime sidecars remain beside the addon. The generated manifest and workflow already include the required runtime sidecars. Start with the [prebuild workflow template](./packages/swift-node/templates/prebuild.yml) when adding this to an existing package.
Publish macOS binaries as `dist_swift-node/{moduleName}.darwin-{arch}.node`, or `dist/{moduleName}.darwin-{arch}.node` when using tsdown. Linux and Windows retain `/{platform}-{arch}/` so their Swift runtime sidecars remain beside the addon. The generated manifest and workflow already include the required runtime sidecars. Start with the [prebuild workflow template](./packages/swift-node/templates/prebuild.yml) when adding this to an existing package; when building Windows targets, also copy its [Windows toolchain action](./packages/swift-node/templates/setup-windows-toolchain.yml) to `.github/actions/setup-windows-toolchain/action.yml`.

## Requirements

Expand Down
4 changes: 2 additions & 2 deletions packages/swift-node-unplugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swift-node-unplugin",
"version": "0.3.0",
"version": "0.3.1",
"description": "Unplugin adapters that build and bundle Swift Node native assets.",
"type": "module",
"types": "./dist/index.d.ts",
Expand Down Expand Up @@ -102,7 +102,7 @@
"test": "vp test run"
},
"peerDependencies": {
"swift-node": "^0.3.0"
"swift-node": "^0.3.1"
},
"dependencies": {
"unplugin": "3.3.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/swift-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ Prebuilt binaries make installation faster and more reproducible, and avoid requ

By default, Linux packages include the Swift `.so` runtime libraries and Windows packages include the Swift `.dll` runtime libraries beside their target-qualified `.node` binary. This lets consumers load the package without separately installing Swift. Set `"swiftNode": { "shipSwiftRuntime": false }` only when your deployment supplies a compatible Swift runtime. Linux prebuilds use a glibc baseline; Alpine and other musl systems build locally into a distinct `{platform}-{arch}-musl` target directory.

Publish macOS binaries as `dist_swift-node/{moduleName}.darwin-{arch}.node`, or `dist/{moduleName}.darwin-{arch}.node` when using tsdown. Linux and Windows retain `/{platform}-{arch}/` so their Swift runtime sidecars remain beside the addon. The generated manifest and workflow already include the required runtime sidecars. Start with the [prebuild workflow template](./templates/prebuild.yml) when adding this to an existing package.
Publish macOS binaries as `dist_swift-node/{moduleName}.darwin-{arch}.node`, or `dist/{moduleName}.darwin-{arch}.node` when using tsdown. Linux and Windows retain `/{platform}-{arch}/` so their Swift runtime sidecars remain beside the addon. The generated manifest and workflow already include the required runtime sidecars. Start with the [prebuild workflow template](./templates/prebuild.yml) when adding this to an existing package; when building Windows targets, also copy its [Windows toolchain action](./templates/setup-windows-toolchain.yml) to `.github/actions/setup-windows-toolchain/action.yml`.

## Requirements

Expand Down
2 changes: 1 addition & 1 deletion packages/swift-node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "swift-node",
"version": "0.3.0",
"version": "0.3.1",
"type": "module",
"description": "Node-API bridge for Swift. Write Node native addons in Swift without C++ glue.",
"bin": {
Expand Down
18 changes: 18 additions & 0 deletions packages/swift-node/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import { commandInvocationForPlatform } from './command.js'
import {
generatePrebuildCiWorkflow,
generatePrebuildWorkflow,
generateWindowsToolchainAction,
packageFilesForPrebuildTargets,
nativeTargetId,
prebuildFilename,
Expand Down Expand Up @@ -477,6 +478,23 @@ export default defineConfig({
}

if (createPrebuildWorkflow) {
if (prebuildTargets.some((target) => target.platform === 'win32')) {
const windowsToolchainActionPath = path.join(
projectDir,
'.github',
'actions',
'setup-windows-toolchain',
'action.yml',
)
if (existsSync(windowsToolchainActionPath)) {
console.log(`Kept existing ${windowsToolchainActionPath}`)
} else {
mkdirSync(path.dirname(windowsToolchainActionPath), { recursive: true })
writeFileSync(windowsToolchainActionPath, generateWindowsToolchainAction())
console.log(`Created ${windowsToolchainActionPath}`)
}
}

const ciWorkflowPath = path.join(projectDir, '.github', 'workflows', 'ci.yml')
if (existsSync(ciWorkflowPath)) {
console.log(`Kept existing ${ciWorkflowPath}`)
Expand Down
104 changes: 98 additions & 6 deletions packages/swift-node/src/prebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,102 @@ export interface PrebuildWorkflowOptions {

const swiftToolchainVersion = '6.3.3'

/**
* Generate the Windows setup action used by workflows created with
* `swift-node init`. Swift's Windows installer is slow, so cache the installed
* SDK and reconstruct its environment on a cache hit. node-gyp's downloaded
* headers and import library are cached for the same reason.
*/
export function generateWindowsToolchainAction(): string {
return `name: Set up Windows native toolchain
description: Restore or install Swift and cache Node development files used by native builds.

outputs:
swift-cache-hit:
description: Whether the installed Swift SDK was restored from cache.
value: \${{ steps.swift-cache.outputs.cache-hit }}
node-gyp-cache-hit:
description: Whether Node development files were restored from cache.
value: \${{ steps.node-gyp-cache.outputs.cache-hit }}

runs:
using: composite
steps:
# gha-setup-swift's built-in cache stores only installer.exe. Cache the
# installed SDK instead: its quiet installer takes about 75 seconds on the
# hosted Windows runner, while the restored SDK only needs its environment
# variables reconstructed below.
- name: Restore installed Swift SDK
id: swift-cache
uses: actions/cache@v4
with:
path: ~/AppData/Local/Programs/Swift
key: swift-node-swift-windows-\${{ runner.arch }}-6.3.3-RELEASE-v2

- name: Configure restored Swift SDK
if: steps.swift-cache.outputs.cache-hit == 'true'
shell: pwsh
run: |
$swiftRoot = Join-Path $env:LOCALAPPDATA 'Programs\\Swift'
$toolchainBin = Join-Path $swiftRoot 'Toolchains\\6.3.3+Asserts\\usr\\bin'
$runtimeBin = Join-Path $swiftRoot 'Runtimes\\6.3.3\\usr\\bin'
$sdkRoot = Join-Path $swiftRoot 'Platforms\\6.3.3\\Windows.platform\\Developer\\SDKs\\Windows.sdk'

foreach ($path in @($toolchainBin, $runtimeBin, $sdkRoot)) {
if (-not (Test-Path $path)) {
throw "The restored Swift SDK is incomplete: $path"
}
}

$toolchainBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
$runtimeBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
"SDKROOT=$sdkRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Install Swift toolchain
if: steps.swift-cache.outputs.cache-hit != 'true'
uses: compnerd/gha-setup-swift@v0.4.0
with:
swift-version: swift-6.3.3-release
swift-build: 6.3.3-RELEASE
build_arch: \${{ runner.arch == 'ARM64' && 'arm64' || 'amd64' }}

# node-gyp downloads Windows Node headers and node.lib on demand into this
# directory. The swift-node CLI needs those files for every C++ build.
- name: Read Node version
id: node-version
shell: pwsh
run: |
$version = node -p 'process.versions.node'
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append

- name: Restore Node development files
id: node-gyp-cache
uses: actions/cache@v4
with:
path: ~/.swift-node/node-gyp
key: swift-node-node-gyp-windows-\${{ runner.arch }}-\${{ steps.node-version.outputs.version }}-v1
`
}

function swiftToolchainWorkflowSteps(targets: readonly PrebuildTarget[]): string[] {
const hasWindowsTarget = targets.some((target) => target.platform === 'win32')

return [
...(hasWindowsTarget
? [
' - name: Prepare Windows native toolchain',
" if: runner.os == 'Windows'",
' uses: ./.github/actions/setup-windows-toolchain',
'',
]
: []),
' - uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0',
...(hasWindowsTarget ? [" if: runner.os != 'Windows'"] : []),
' with:',
` swift-version: ${swiftToolchainVersion}`,
]
}

/**
* The native platforms swift-node supports in generated GitHub Actions
* workflows. IDs intentionally use Node's `process.platform`/`process.arch`
Expand Down Expand Up @@ -224,9 +320,7 @@ export function generatePrebuildCiWorkflow(
'',
...commands.setup,
...(commands.setup.length > 0 ? [''] : []),
' - uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0',
' with:',
` swift-version: ${swiftToolchainVersion}`,
...swiftToolchainWorkflowSteps(targets),
'',
' - name: Install dependencies',
` run: ${commands.install}`,
Expand Down Expand Up @@ -429,9 +523,7 @@ export function generatePrebuildWorkflow(
...commands.setup,
...(commands.setup.length > 0 ? [''] : []),
' # Keep the prebuild ABI reproducible across every target.',
' - uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0',
' with:',
` swift-version: ${swiftToolchainVersion}`,
...swiftToolchainWorkflowSteps(targets),
'',
' - name: Install dependencies',
` run: ${commands.install}`,
Expand Down
5 changes: 5 additions & 0 deletions packages/swift-node/templates/prebuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,12 @@ jobs:
node-version: 24

# Keep the prebuild ABI reproducible across every target.
- name: Prepare Windows native toolchain
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-toolchain

- uses: SwiftyLab/setup-swift@38f54a76b70d989321de9dc7c840618c08cf56e9 # v1.14.0
if: runner.os != 'Windows'
with:
swift-version: 6.3.3

Expand Down
67 changes: 67 additions & 0 deletions packages/swift-node/templates/setup-windows-toolchain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Set up Windows native toolchain
description: Restore or install Swift and cache Node development files used by native builds.

outputs:
swift-cache-hit:
description: Whether the installed Swift SDK was restored from cache.
value: ${{ steps.swift-cache.outputs.cache-hit }}
node-gyp-cache-hit:
description: Whether Node development files were restored from cache.
value: ${{ steps.node-gyp-cache.outputs.cache-hit }}

runs:
using: composite
steps:
# gha-setup-swift's built-in cache stores only installer.exe. Cache the
# installed SDK instead: its quiet installer takes about 75 seconds on the
# hosted Windows runner, while the restored SDK only needs its environment
# variables reconstructed below.
- name: Restore installed Swift SDK
id: swift-cache
uses: actions/cache@v4
with:
path: ~/AppData/Local/Programs/Swift
key: swift-node-swift-windows-${{ runner.arch }}-6.3.3-RELEASE-v2

- name: Configure restored Swift SDK
if: steps.swift-cache.outputs.cache-hit == 'true'
shell: pwsh
run: |
$swiftRoot = Join-Path $env:LOCALAPPDATA 'Programs\Swift'
$toolchainBin = Join-Path $swiftRoot 'Toolchains\6.3.3+Asserts\usr\bin'
$runtimeBin = Join-Path $swiftRoot 'Runtimes\6.3.3\usr\bin'
$sdkRoot = Join-Path $swiftRoot 'Platforms\6.3.3\Windows.platform\Developer\SDKs\Windows.sdk'

foreach ($path in @($toolchainBin, $runtimeBin, $sdkRoot)) {
if (-not (Test-Path $path)) {
throw "The restored Swift SDK is incomplete: $path"
}
}

$toolchainBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
$runtimeBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
"SDKROOT=$sdkRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Install Swift toolchain
if: steps.swift-cache.outputs.cache-hit != 'true'
uses: compnerd/gha-setup-swift@v0.4.0
with:
swift-version: swift-6.3.3-release
swift-build: 6.3.3-RELEASE
build_arch: ${{ runner.arch == 'ARM64' && 'arm64' || 'amd64' }}

# node-gyp downloads Windows Node headers and node.lib on demand into this
# directory. The swift-node CLI needs those files for every C++ build.
- name: Read Node version
id: node-version
shell: pwsh
run: |
$version = node -p 'process.versions.node'
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append

- name: Restore Node development files
id: node-gyp-cache
uses: actions/cache@v4
with:
path: ~/.swift-node/node-gyp
key: swift-node-node-gyp-windows-${{ runner.arch }}-${{ steps.node-version.outputs.version }}-v1
Loading
Loading