Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows Arm64 support for emsdk.py only #1186

Merged

Conversation

Blackhex
Copy link
Contributor

@Blackhex Blackhex commented Feb 14, 2023

This PR add support for Visual Studio Build Tools 2022 (Preview) compilation of packages using emsdk.py on and for Windows Arm64.

@@ -256,7 +253,8 @@ def vswhere(version):
if not program_files:
program_files = os.environ['ProgramFiles']
vswhere_path = os.path.join(program_files, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-property', 'installationPath', '-format', 'json']))
tools_arch = ('ARM64' if ARCH == 'aarch64' else 'x86.x64')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-products', '*', '-prerelease', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.' + tools_arch, '-property', 'installationPath', '-format', 'json']))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The -products * allows detection of Build Tools, the -prerelease allows detection of Preview version of Visual Studio and Build Tools.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps put this in a comment on the line above?

@Blackhex Blackhex changed the title Windows Arm64 support Windows Arm64 support for emsdk.py only Feb 14, 2023
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

lgtm with comments addressed.

Thanks for working on this!

emsdk.py Outdated
elif ARCH == 'x86_64':
return 'x64'
else:
return 'x86'
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about writing this a dict so it will crash accordingly on unknown arch instead of defaulting to x86. e.g.

  cmake_arch = { 'aarch64': 'arm64' ... }
  return cmake_arch[ARCH]

Also should ARM64 and ARM be capitalized here. I'd rather keep them all lowercase if that works?

Copy link
Contributor Author

@Blackhex Blackhex Feb 15, 2023

Choose a reason for hiding this comment

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

The code style fixed and the values changed according to the source reference though the source does not mention Arm values. Experimentally was proven that it needs to be capital.

emsdk.py Outdated
@@ -256,7 +253,8 @@ def vswhere(version):
if not program_files:
program_files = os.environ['ProgramFiles']
vswhere_path = os.path.join(program_files, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-property', 'installationPath', '-format', 'json']))
tools_arch = ('ARM64' if ARCH == 'aarch64' else 'x86.x64')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can arm64 be lowercase here?

Should we switch our internal ARCH=aarch64 to ARCH=arm64 maybe?

No need for brackets around this expression.

Copy link
Contributor Author

@Blackhex Blackhex Feb 15, 2023

Choose a reason for hiding this comment

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

This is driven by VS component IDs so it should be capital: https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022.

aarch64 came from Unix-like systems and the value is used both for Linux, MacOS and Windows. I'd keep it as is unless we want to distinguish between different OSes.

emsdk.py Outdated
elif hasattr(tool, 'arch') and tool.arch == 'x86_64':
return 'x64'
elif hasattr(tool, 'arch') and tool.arch == 'x86':
return 'x86'
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about just one if hasattr(tool, 'arch') here.

e.g.

if hasattr(tool, 'arch'):
   tools_arch_map = {'aarch64': ARM64' ...}
   return tool_arch_map[tool.arch]
// Fall back to host arch. 
if ARCH == 'aarch64':
    return 'ARM64'
  else:
    return 'x64' if tool.bitness == 64 else 'x86'

Should we call decide_cmake_host_platform for the fallback case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The code style has changed and the values fixed according to the source references added. The host platform and target platform values has different syntax as you can see in the sources.

emsdk.py Outdated
args += ['-A', 'x64' if tool.bitness == 64 else 'x86']
args += ['-Thost=x64']
args += ['-A', decide_cmake_target_platform(tool)]
args += ['-Thost=' + decide_cmake_host_platform()]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we drop the decide_ here and just use cmake_target_platform? Or maybe use get_ if you think we need a prefix at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to be consistent with with decide_cmake_build_type but OK.

emsdk.py Outdated
@@ -1360,7 +1383,7 @@ def build_binaryen_tool(tool):
return False

# Make
success = make_build(build_root, build_type, 'x64' if tool.bitness == 64 else 'Win32')
success = make_build(build_root, build_type)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess maybe the removal of this third unused argument could be its own NFC (non-functional-change)? But its not a big deal if you want to leave it as part of this one..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You decide, I had those changes written before VS 2022 support was added upstream so when I was updating my old changes including VS 2022 support to the new upstream state, this change was some kind of leftover of the code adding the VS 2022 support.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I always prefer smaller and separate changes. So I would prefer a separate PR in this case if you have time.

@Blackhex Blackhex force-pushed the emsdk-vs2022-arm64 branch 4 times, most recently from 4ff3dd7 to 7149e8b Compare February 15, 2023 08:23
@Blackhex Blackhex requested a review from sbc100 February 15, 2023 08:27
@@ -256,7 +253,9 @@ def vswhere(version):
if not program_files:
program_files = os.environ['ProgramFiles']
vswhere_path = os.path.join(program_files, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-property', 'installationPath', '-format', 'json']))
# Source: https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022
tools_arch = 'ARM64' if ARCH == 'aarch64' else 'x86.x64'
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is supposed to be uppercase why isn't the else case "X86.X64"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was referring to Arm64 variant only. x86.x64 should be lower case. See https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022 for the reference.

@@ -256,7 +253,8 @@ def vswhere(version):
if not program_files:
program_files = os.environ['ProgramFiles']
vswhere_path = os.path.join(program_files, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-property', 'installationPath', '-format', 'json']))
tools_arch = ('ARM64' if ARCH == 'aarch64' else 'x86.x64')
output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-products', '*', '-prerelease', '-version', '[%s.0,%s.0)' % (version, version + 1), '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.' + tools_arch, '-property', 'installationPath', '-format', 'json']))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps put this in a comment on the line above?

emsdk.py Outdated
if ARCH == 'aarch64':
return 'ARM64'
else:
return 'x64' if tool.bitness == 64 else 'Win32'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the return value here supposed to be uppercase?

What happens when this function is called on non-windows platforms?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

According to https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2017%202022.html#platform-selection yes. This method should not be called on non-Windows platforms as it is called only when generator is "Visual Studio".

emsdk.py Outdated
else:
return cmake_target_platform_no_tool_arch(tool)
else:
return cmake_target_platform_no_tool_arch(tool)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you can remove the to final else blocks here and just return cmake_target_platform_no_tool_arch.

Also since cmake_target_platform_no_tool_arch is very simple and (after the above change) has just one calls site maybe just inline it here?

emsdk.py Show resolved Hide resolved
@Blackhex Blackhex force-pushed the emsdk-vs2022-arm64 branch 3 times, most recently from ce32e10 to 07d652c Compare February 15, 2023 18:52
@@ -142,9 +142,6 @@ def exit_with_error(msg):
ARCH = 'x86'
elif machine.startswith('aarch64') or machine.lower().startswith('arm64'):
ARCH = 'aarch64'
if WINDOWS:
errlog('No support for Windows on Arm, fallback to x64')
ARCH = 'x86_64'
Copy link
Collaborator

Choose a reason for hiding this comment

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

On macOS it was useful for a while to run the x86 prebuilt binaries on arm.. does that approach also work on windows (i.e. is there binary emulation?) . If so, would this change cause a regression since today you can just install the x86 binaries and have a working installation?

Copy link
Contributor Author

@Blackhex Blackhex Feb 15, 2023

Choose a reason for hiding this comment

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

You are right, as far as there are no publicly available Arm64 binaries we should install the x64 ones running in emulation. But having this code here prevents form possiblility to build the Arm64 binaries from sources using emsdk.py. For that reason, I've move this check into the install_tool() method. The code is not nice but this should be only a temporary solution.

Copy link
Collaborator

Choose a reason for hiding this comment

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

One option is that we drop the hacks and folks can use EMSDK_ARCH=x86_64 emsdk install latest if they want to force the install the x86 binaries? Or do you think we should continue to make it automatic?

Copy link
Contributor Author

@Blackhex Blackhex Feb 15, 2023

Choose a reason for hiding this comment

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

I guess the hack is better because it keeps the current behaviour. I can rember when I started with emsdk that it took me a while to figure out that the EMSDK_ARCH even exists. On the other, hand note that there is this "strange" behavior: If you have Arm64 Python installed on your system and you do emsdk.bat install latest and emsdk.bat activate latest, the x64 version of emsdk Python is installed and activated and since then, emsdk.bat install xxx installs or compiles x64 versions anyway (without the error message). You either need to force Arm64 with EMSDK_ARCH=aarch64, or use system Python with python emsdk.py install xxx. If your system Python is x64, you need to force EMSDK_ARCH=aarch64 in all cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, the python based system detection is a bit boring, as the architecture of your python dictates which platform you have. As you mentioned, if you have an x64 python (emulated on arm64), it will say you're on an x64 cpu.

The other way to detect this under Windows is to use PROCESSOR_ARCHITECTURE env var. Same joke, from cmd.exe, it says you're on an arm64 system, and from powershell, that you're on an x64 system (because default powershell install is x64).

For this kind of case, IMHO, having an explicit option (available through help) would be the best solution. Or at least, to mention EMSDK_ARCH in help and official documentation.

@Blackhex Blackhex requested a review from sbc100 February 15, 2023 18:55
@sbc100
Copy link
Collaborator

sbc100 commented Feb 15, 2023

lgtm! Thanks for working on this.

I suppose the next step would be try to build release binaries for windows/arm64 so folks don't need to build from source all the time. Do you think we are that point where that it worth the investment? How many windows/arm64 users are out there right now?

@sbc100 sbc100 merged commit 7bcf144 into emscripten-core:main Feb 15, 2023
@Blackhex Blackhex deleted the emsdk-vs2022-arm64 branch February 16, 2023 08:47
@Blackhex
Copy link
Contributor Author

I suppose the next step would be try to build release binaries for windows/arm64 so folks don't need to build from source all the time. Do you think we are that point where that it worth the investment? How many windows/arm64 users are out there right now?

@sbc100 Thank you for your help with the review and merging.

We already have some experimental binaries and now we are ensuring they can pass all the emscripten repository unit tests and some useful projects can be compiled with them. You can check out our https://github.com/Windows-on-ARM-Experiments/emsdk fork. As our team's mission is an enablement of smooth developer experience on Windows Arm64, we are happy to listen any requests or suggestions in that regards.

@sbc100
Copy link
Collaborator

sbc100 commented Feb 16, 2023

Great. Once you have some binaries you are happen with we could consider adding them emscripten-releases-tags.json like we have to latest-arm64-linux:

{                                                                                   
  "aliases": {                                                                      
    "latest": "3.1.31",                                                             
    "latest-sdk": "latest",                                                         
    "latest-arm64-linux": "3.1.21",                                                 
    "latest-64bit": "latest",                                                       
    "sdk-latest-64bit": "latest",                                                   
    "latest-upstream": "latest",                                                                              
    "latest-clang-upstream": "latest",                                           
    "latest-releases-upstream": "latest"                                         
  }, 

Note that latest-arm64-linux is not necessarily up-to-date because we don't build the binaries with the same automatic process. We could potentially do the same for arm64-windows?

@Blackhex
Copy link
Contributor Author

Why not target to build the Windows Arm64 regularly together with x64 ones? Cross-compilation is always the option.

@sbc100
Copy link
Collaborator

sbc100 commented Feb 16, 2023

Sure, we do that for macOS, so if its easy for windows we can do that too

shlomif pushed a commit to shlomif/emsdk that referenced this pull request Sep 29, 2023
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