Skip to content

Update Windows RTools support and add Windows ARM64 - #864

Open
ndabas wants to merge 14 commits into
stan-dev:developfrom
ndabas:develop
Open

ndabas wants to merge 14 commits into
stan-dev:developfrom
ndabas:develop

Conversation

@ndabas

@ndabas ndabas commented Sep 18, 2026

Copy link
Copy Markdown

Submission Checklist

  • Run unit tests
  • Declare copyright holder and open-source license: see below

Summary

I have updated the RTools installation support on Windows, so versions up to 4.5 are now supported. Critically, that now adds native support for Windows on ARM64. I have updated the rest of the build-related code to work on both AMD64 and ARM64 versions of Windows.

The one thing worth pointing out is that I ran into 4 tests failing only on Windows ARM; this is because those particular tests were running an exe and immediately trying to delete it. On Windows 11 ARM, Windows Defender cannot be disabled, per the readme; and Windows Defender tries to scan every executable when it is run, so deleting it immediately fails.

We can choose to not add Windows ARM to the main workflow, as that workflow has a subset of supported platforms anyway. In that case I can remove the changes to main.yml and the delete-retry workaround, let me know.

I also added lots of tests and a new workflow to test the toolchain installation on Windows.

Copyright and Licensing

Please list the copyright holder for the work you are submitting (this will be you or your assignee, such as a university or company):

Nikhil Dabas

By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses:

@WardBrian WardBrian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @ndabas! This looks very nice overall.

My main concerns are about the overlap this has with the large refactor currently happening in #851. I think that together they will actually clean up a lot of the code, but it will likely require some changes here once that one is merged.

Comment thread .github/workflows/windows-toolchain.yml Outdated
Comment thread cmdstanpy/utils/filesystem.py Outdated
Comment thread cmdstanpy/compilation.py Outdated
Comment on lines +202 to +203
# clang treats backslashes in the -include path as escapes
self._user_header = Path(self._user_header).absolute().as_posix()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might make sense to improve the path handling for this in cmdstan itself:
https://github.com/stan-dev/cmdstan/blob/d3d5df6a22565edbe13edbd4eb40762cc8c5a4d6/make/program#L47

For other variables we use subst to swap backslashes:
https://github.com/stan-dev/cmdstan/blob/d3d5df6a22565edbe13edbd4eb40762cc8c5a4d6/make/program#L83

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the pointers, I'll see how to clean this up a bit.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I had a look, and yes, it would be great to fix it there. I'll submit a PR for CmdStan too, but in the meanwhile, since we will support at least a few older versions of CmdStan, I've kept the code here and updated the comment to clarify.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Comment thread cmdstanpy/install_cmdstan.py Outdated
Comment thread cmdstanpy/install_cxx_toolchain.py Outdated
Comment thread cmdstanpy/install_cxx_toolchain.py
Comment thread docsrc/installation.rst
Comment thread cmdstanpy/utils/__init__.py

@WardBrian WardBrian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The changes look pretty good to me at this point, a couple comments on the tests

Comment thread test/test_compilation.py Outdated
Comment on lines +204 to +213
def test_user_header_is_posix_path() -> None:
"""Backslashes in the -include path are eaten by clang."""
opts = CompilerOptions(
user_header=os.path.join(DATAFILES_PATH, 'return_one.hpp')
)
opts.validate()
assert '\\' not in opts.user_header
assert opts.user_header.endswith('/return_one.hpp')
assert os.path.isfile(opts.user_header)
assert str(opts.cpp_options['USER_HEADER']) == opts.user_header

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test focuses us to do the update, but I think it would be better to have a test that a windows path actually compiles, which would work whether us or CmdStan do the fix up

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, I have extracted a test in tests\test_model.py (test_model_compile_user_header) for this check.

Comment thread test/test_cxx_installation.py Outdated
Comment on lines +519 to +527
def test_parse_cmdline_args(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
sys, 'argv', ['install_cxx_toolchain', '-v', '4.5', '-d', 'somewhere']
)
args = install_cxx_toolchain.parse_cmdline_args()
assert args['version'] == '4.5'
assert args['dir'] == 'somewhere'
assert args['silent'] is False
assert args['progress'] is False

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can go away; it's basically just testing argparse

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, done.

Comment thread .github/workflows/windows-toolchain.yml Outdated
#include <iostream>
int main() { std::cout << "hello\\n"; return 0; }
"""))
subprocess.run(["g++", "-O0", "hello.cpp", "-o", "hello.exe"], check=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think windows runners might already have g++ in their path, so I'm not confident this is really testing all that much. Maybe it could also assert on gcc --version or which gcc?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed, I already had an assert on the gcc path in the previous step of the job, and I have added a gcc --version to this step (in addition to checking the architecture against what is expected.)

@ndabas

ndabas commented Sep 23, 2026

Copy link
Copy Markdown
Author

Thanks for the (re-)review, I have made these changes and everything is passing on my fork.

This branch has not been deployed

No deployments
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.

2 participants