Skip to content

Use x86_64 emulation for windows arm64 - #138

Open
tobil4sk wants to merge 5 commits into
krdlab:masterfrom
tobil4sk:feature/windows-arm64-emulation
Open

tobil4sk wants to merge 5 commits into
krdlab:masterfrom
tobil4sk:feature/windows-arm64-emulation

Conversation

@tobil4sk

Copy link
Copy Markdown
Contributor

No description provided.

@MRK2009

MRK2009 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Fire 🔥

@krdlab krdlab left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this.

I had taken the absence of upstream ARM64 archives to mean Windows ARM64 was out of reach, so using the existing x86/x64 builds under emulation is not an approach I had considered. All three windows-11-arm jobs are green, including 3.4.7 on the 32-bit toolchain.

Four changes are needed before merge: the README update below, and three points in inline comments on src/asset.ts and src/asset.test.ts.

That assumption of mine is written into the README, so please update it in this PR. Line 20 still says Windows ARM64 is unsupported, and the "Supported combinations" table has no windows-11-arm row. README.md is not in this diff, so I am raising it here rather than inline.

Suggested row:

| `windows-11-arm` (Windows 11 ARM64) | stable / `latest` (x86/x64 binaries under emulation) |

Suggested note:

- Windows ARM64 has no upstream Haxe / Neko ARM64 archives. This action installs the Windows
  x64 builds and relies on the emulation built into Windows 11 on ARM. For Haxe 3.x it selects
  the 32-bit x86 builds of both Haxe and Neko, because Haxe 3's Windows haxelib is 32-bit.

Once the source changes are in: dist/ is committed, so please run npm run dist and include the regenerated bundle.

Comment thread src/asset.ts Outdated
Comment on lines +35 to +40
export function resolveTarget(input: ResolveInput): Resolution {
const { tool, platform, arch } = input;
let { tool, platform, arch } = input;

if (platform === 'win32' && arch === 'arm64') {
return {
kind: 'unsupported',
reason: 'Windows ARM64 is not supported (no upstream Haxe/Neko archives).',
};
core.info('Windows ARM64 has no upstream Haxe/Neko archives, falling back to x86_64 emulation.');
arch = 'x64';

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Telling users what is happening here is worth doing. Before merge, though, please move the notice out of resolveTarget() and adjust the wording.

resolveTarget() was a pure mapping function, and core.info() gives it a side effect. Since cachePlatform, downloadUrl and fileNameWithoutExt each call it, the notice is emitted five times when neither tool is cached and once when both are, both visible in the 3.4.7 job on this PR.
The wording also misses the Haxe 3.x case: there the action selects haxe-3.4.7-win.zip and neko-2.3.0-win.zip, which are 32-bit x86 builds.

A shared predicate keeps the selection rule in one place, and setup() owns the notice. In asset.ts, this replaces the destructuring and the Windows ARM64 block:

// NOTE: no upstream Haxe/Neko ARM64 archives for Windows; the x86/x64 builds run under the
// emulation built into Windows 11 on ARM.
export function usesWindowsEmulation(platform: NodeJS.Platform, arch: string): boolean {
  return platform === 'win32' && arch === 'arm64';
}

export function resolveTarget(input: ResolveInput): Resolution {
  const { tool, platform } = input;
  const arch = usesWindowsEmulation(platform, input.arch) ? 'x64' : input.arch;

setup() then gains the notice. os and core are already imported there; usesWindowsEmulation needs adding to the ./asset import:

if (usesWindowsEmulation(os.platform(), os.arch())) {
  core.info('Windows ARM64: using the Windows x86/x64 builds under emulation.');
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the warning into setup() as suggested. I used x86 to mean generic x86, whether 32 or 64 bit.

Comment thread src/asset.test.ts Outdated
['win32', 'x64', '2.4.0', false, 'neko-2.4.0-win64.zip', 'v2-4-0'],
['win32', 'x64', '2.3.0', true, 'neko-2.3.0-win.zip', 'v2-3-0'],
['win32', 'arm64', '2.4.0', false, 'neko-2.4.0-win64.zip', 'v2-4-0'],
['win32', 'arm64', '2.3.0', true, 'neko-2.3.0-win.zip', 'v2-3-0'],

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These pin the archive names well, but two gaps are left.

They pass force32 directly, so NekoAsset.resolveFromHaxeVersion, which decides to force 32-bit on Windows, is never exercised on ARM64. The existing test for it, Haxe 3.4.7 on Windows -> force32=true, covers x64 only. Before merge, please add a case to the NekoAsset.resolveFromHaxeVersion describe:

it('Haxe 3.4.7 on Windows ARM64 selects 32-bit Neko', () => {
  setOs('win32', 'arm64');
  const neko = NekoAsset.resolveFromHaxeVersion('3.4.7', false);

  expect(neko.version).toBe('2.3.0');
  expect(neko.cachePlatform).toBe('win');
});

The resolveTarget cachePlatform (haxelib cache key compatibility) table also has no Windows ARM64 rows. It pins the Haxe cachePlatform values that feed the haxelib cache key, and Windows ARM64 now shares win64 and win with Windows x64. That seems right to me, since the archives are identical, but the values are worth pinning. Before merge, please add these after the ['neko', '2.4.0', 'linux', 'arm64', false, 'linux-arm64'], row, line 228 on this head. The Neko rows do not feed the cache key; they are useful as resolver coverage:

    ['haxe', '4.3.7', 'win32', 'arm64', false, 'win64'],
    ['haxe', '3.4.7', 'win32', 'arm64', false, 'win'],
    ['haxe', 'latest', 'win32', 'arm64', true, 'win64'],
    ['neko', '2.4.0', 'win32', 'arm64', false, 'win64'],
    ['neko', 'latest', 'win32', 'arm64', true, 'win64'],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the resolveFromHaxeVersion test. Because of the refactor, the arm64 emulation check happens before reaching resolveTarget, and therefore the suggested arm64 cases for it no longer make sense (arm64 should now always call resolveTarget with x64/ia32).

This way the same logic can be reused to implement x86 emulation on
windows arm64.
@tobil4sk
tobil4sk force-pushed the feature/windows-arm64-emulation branch from 9960aa0 to 59b9ff1 Compare October 7, 2026 15:18
@tobil4sk
tobil4sk force-pushed the feature/windows-arm64-emulation branch from 59b9ff1 to f37045f Compare October 7, 2026 15:19
@tobil4sk

tobil4sk commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

I've updated the README so it mentions the windows emulation. I also refactored the code a bit, so the same mechanism can be used for the 32-bit fallback for Haxe 3, and the x86 fallback in general for arm64 windows. It was a bit messy before, because the override happened in different places for NekoAsset and HaxeAsset.

I also thought that only neko was using the 32-bit binaries, because haxe 3 had 64-bit archives available (the issue was in fact that the 64-bit haxe archive had a 32-bit haxelib, requiring 32-bit neko). So once this is merged I think that can be corrected, so haxe is always 64-bit, and only 32-bit neko is used when that is needed for haxelib. That should also make the situation clearer to document.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants