Skip to content

Conversation

@TTsangSC
Copy link
Collaborator

@TTsangSC TTsangSC commented Aug 17, 2025

Closes #390... hopefully

  • Updated pyproject.toml::[tool.cibuildwheel.windows] to also target ARM64.
  • Added a corresponding windows-11-arm job for each windows-latest (i.e. x64) CI job in .github/workflows/test.yml::test_binpy_wheels except for the following Python versions:
  • Updated line_profiler/c_trace_callback.h to:
    • Only use the #undef hacks required on 3.12 when we're actually on 3.12, and only use the #undef HAVE_STD_ATOMIC hack on Linux where it is necessary
    • Vendor in the required components from cpython/Include/internal/pycore_atomic.h when on 3.12 + Windows + ARM64, so that the problematic definitions in said files will not be included by the preprocessor
  • Updated tests/test_cython.py so that the tests can be skipped when on Windows-ARM64, which didn't seem to agree with installing Cython packages in an editable manner (EDIT: fixed; it was a CI problem, not a code/test/Cython problem)

@TTsangSC TTsangSC changed the title Win arm64 fix Try building for Windows-ARM64 Aug 17, 2025
@TTsangSC TTsangSC changed the title Try building for Windows-ARM64 DRAFT: Try building for Windows-ARM64 Aug 18, 2025
@da-woods
Copy link
Contributor

da-woods commented Aug 18, 2025

I'm wondering (but not certain) if the includes can be moved into the .c file and that would simplify things: #392 Looks like it doesn't unfortunately

@TTsangSC
Copy link
Collaborator Author

As of 6f3a09e I've gotten line_profiler to build on Windows-ARM64 (example passed build job), but ironically the installation of other Cython packages seems to be problematic (example failed test job).

IDK if the problem lies with how the test fixture was written (#352; installing a local Cython package in editable mode), said test Cython package, or with Cython itself – but I guess that was the original intent behind #390, to make sure that Cython works reliably on the platform so downstream applications can use it.

Guess that it's our turn to turn off some tests so that we can proceed. ;)

@codecov
Copy link

codecov bot commented Aug 27, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.25%. Comparing base (60e928f) to head (95063ef).
⚠️ Report is 19 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #391      +/-   ##
==========================================
+ Coverage   87.56%   90.25%   +2.68%     
==========================================
  Files          18       20       +2     
  Lines        1641     2073     +432     
  Branches      348      447      +99     
==========================================
+ Hits         1437     1871     +434     
- Misses        149      151       +2     
+ Partials       55       51       -4     

see 5 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6153697...95063ef. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TTsangSC TTsangSC changed the title DRAFT: Try building for Windows-ARM64 FIX: building on Windows-ARM64 Aug 27, 2025
@da-woods
Copy link
Contributor

From a quick look, you may have been failing to link to the Python library I think. Although I'm not sure why.

I don't think there's huge issues with Cython on Windows ARM in general. The vast majority of our own test suite works. Apart from the line_profiler test, the only other issue we ran into was an MSVC compiler bug when constructing large tuples or lists, which affected 2 or 3 tests.

@TTsangSC
Copy link
Collaborator Author

TTsangSC commented Aug 27, 2025

... you're right, in hindsight it should've been obvious that (most of) Cython works as intended since the build for line_profiler itself succeeded.* Most probably I misconfigured the environment on the test instances... will double check the CI.

In any case thanks for the input and for writing the initial issue!

* The caveat of course being that the wheel builds happened didn't happen on ARM64.

EDIT: crucial typo... but you probably guessed what was meant anyway.

@Erotemic
Copy link
Member

I will need to think about how to incorporate this CI change into my xcookie CI templates so I we can continue to maintain this as the CI updates. Shouldn't be too hard.

I'm also noticing that we don't seem to have Linux ARM64 builds, and I don't remember if there was a reason they were turned off, or they were just never enabled.

@da-woods Have you tested if this patch fixes #390?

@da-woods
Copy link
Contributor

Yes - if I point our CI at this patch commit then it runs successfully (at least on 3.13; we skip most profiling on 3.12 because it was awkwardly caught between the old system and sys.monitoring, but that isn't your fault...)

@TTsangSC
Copy link
Collaborator Author

TTsangSC commented Aug 29, 2025

A couple things:

EDIT: and of course building more Linux wheels will probably lengthen the pipeline duration (by 50% since we're building and testing for one more arch). But then again it seems that nowadays the macOS job of build_binpy_wheels is usually the rate-limiting one (probably because the universal2 wheel has to be tested on both x86_64 and arm64), so maybe it will be alright.

This partially reverts commit 0a16f5c
but keeps the typing fixes introduced therein.
This reverts commit 072106d.
@TTsangSC
Copy link
Collaborator Author

TTsangSC commented Aug 30, 2025

Hold on, I noticed that for some reasons we stopped building Linux-i686 wheels after merging #369. Was that because of the cibuildwheel version bump from 2.X to 3.X? @Erotemic

} _Py_atomic_int;
# define _Py_atomic_load_relaxed(foo) (0)
# define _Py_atomic_store_relaxed(foo, bar) (0)
# include "internal/pycore_interp.h"
Copy link
Member

Choose a reason for hiding this comment

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

This line 51 is included, and then included again unconditionally on 53.

CIBW_ARCHS_LINUX: ${{ matrix.arch }}
CIBW_ENVIRONMENT: PYTHONUTF8=1
PYTHONUTF8: '1'
# `msvc-dev-cmd` sets this envvar, which intereferes with
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# `msvc-dev-cmd` sets this envvar, which intereferes with
# `msvc-dev-cmd` sets this envvar, which interferes with

volatile int _value;
} _Py_atomic_int;
# define _Py_atomic_load_relaxed(foo) (0)
# define _Py_atomic_store_relaxed(foo, bar) (0)
Copy link
Member

Choose a reason for hiding this comment

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

So explain to me again why we are defining these here. Is anything in our library actually using these structures, or is this all just to make the compiler happy and ultimately this code is unused?

IIUC, maybe it makes sense to make these fail a little louder if they are ever used?

Would something like this make sense?

/* If any stub is referenced, fail the build with an unresolved external.
 * This ensures we never ship wheels that "use" these placeholders. */
#ifdef _MSC_VER
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
__declspec(dllimport) void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
#else
extern void lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(void);
extern void lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(void);
#endif
#define _LP_ATOMIC_PANIC_LOAD_EXPR()  (lp_link_error__stubbed_cpython_atomic_LOAD_relaxed_was_used_this_is_a_bug(), 0)
#define _LP_ATOMIC_PANIC_STORE_STMT() do { lp_link_error__stubbed_cpython_atomic_STORE_relaxed_was_used_this_is_a_bug(); } while (0)

/* Panic-on-use shims (expression/statement forms) */
#undef  _Py_atomic_load_relaxed
#undef  _Py_atomic_store_relaxed
#define _Py_atomic_load_relaxed(obj)       ((void)(obj), _LP_ATOMIC_PANIC_LOAD_EXPR())
#define _Py_atomic_store_relaxed(obj,val)  do { (void)(obj); (void)(val); _LP_ATOMIC_PANIC_STORE_STMT(); } while (0)

Copy link
Collaborator Author

@TTsangSC TTsangSC Oct 8, 2025

Choose a reason for hiding this comment

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

  • We need PyInterpreterState's declaration (i.e. struct _is) from internals/pycore_interp.h. Other than the concrete declaration of PyFrameObject (from internals/pycore_frame.h) #included in Python_wrapper.h, this is the only other internals/pycore_* API that we use in the project.
  • In Python 3.12, said header file#include internals/pycore_atomic.h and uses these names therefrom:
    • _Py_atomic_address is directly used in the declaration.
    • We don't actually need _Py_atomic_load_relaxed() and _Py_atomic_store_relaxed() per se (they aren't related to the declaration), but the names have to be available because they are used in macros defined below in internals/pycore_frame.h.
  • The header file also #include internals/pycore_ceval_state.h, which uses _Py_atomic_int.

In principle it's "safe" to keep things as-is since we're only doing this for 3.12, which is ossified at this point. But yes it'd be nicer to have some failsafes.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the changes. I think this makes it clearer what the workaround is just by reading the code.

Co-authored-by: Jon Crall <erotemic@gmail.com>
@Erotemic Erotemic merged commit 14ae1f0 into pyutils:main Oct 9, 2025
45 checks passed
@TTsangSC TTsangSC deleted the win-arm64-fix branch October 9, 2025 19:35
@TTsangSC
Copy link
Collaborator Author

TTsangSC commented Oct 9, 2025

Thanks for the review!

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.

Doesn't seem to build on arm64 Windows (Python 3.12)

3 participants