Skip to content

Brian2 downstream support: wheels, Windows, and migration from cppyy #39

Description

@Legend101Zz

Hi team , So I'm a contributor to Brian2 and maintain an experimental cppyy code-generation backend for it, a simulator for spiking neural networks (brian-team/brian2#1769, still a draft , we have been working on it for over an year now ).

I had also discussed the platform-support side of this work earlier with Wim Lavrijsen (wlav) in the cppyy repository, wlav/cppyy#311

A bit of context on why I'm asking. Brian2 generates C++ for simulations and currently runs it through Cython. That means compiling and importing each generated code object before it can run. On a cold cache, startup can take tens of seconds, which is especially noticeable for the short, exploratory simulations people tend to run repeatedly.

Replacing that path was the focus of my Google Summer of Code 2025 project (https://brian.discourse.group/t/gsoc-2025-replacing-brians-just-in-time-compilation-mechanism/1450/9 ), Replacing Brian's just-in-time compilation mechanism,
with the Brian2 maintainers (@mstimberg ).

We ended up using cppyy because it gives us an actual in-process JIT instead of doing AOT compilation at runtime. It also lets us keep hot data structures on the C++ side rather than repeatedly crossing the Python/C++ boundary in inner loops.

On Linux and macOS, the backend now does what we wanted it to do and we see a huge performance boost there too. The remaining problem is less about the backend itself and more about whether we can actually ship it to Brian2 users.

Our cppyy surface area is fairly small: cppdef, include, add_include_path, gbl, and the buffer protocol for exposing NumPy arrays to C++ as raw pointers.

I've only recently caught up with the fact that wlav/cppyy is frozen, the three compiler-research forks were archived on August 4, and CppJIT is now the successor. Before we decide how to land our PR, I'd like to understand where CppJIT is heading, particularly around packaging and platform support.

1. Wheels and platform coverage

So I checked and It's good to see #32 and #33 moving toward wheels that bundle LLVM. For Brian2, that would solve one of the biggest problems with the current cppyy stack.

The part I'm less clear on is the intended platform coverage.

Brian2 currently tests on Linux x86-64, Windows x86-64, macOS Intel, and macOS arm64. We publish wheels for manylinux x86-64/aarch64, musllinux x86-64, Windows, and both macOS architectures. Python support follows SPEC-0, so we're on 3.12–3.14 today, which happens to line up exactly with CppJIT's cp312/cp313/cp314 build list.

The important constraint for us is that most Brian2 users are neuroscientists installing through pip or conda. We can't really make a backend the default if installing it means building LLVM locally.

As #22 currently stands, [tool.cibuildwheel] has no Windows section, Linux only builds x86_64, macOS only builds arm64, and musllinux is skipped. That would leave Windows, Linux aarch64, macOS Intel, and musllinux uncovered relative to Brian2.

Are those platforms intended for the first release, or something you'd expect to add later?

A few related questions:

  • What macOS deployment target are you aiming for? MACOSX_DEPLOYMENT_TARGET = "26.0" in the PR would be a fairly high floor for Brian2 users.
  • Is conda-forge part of the plan?
  • I assume a LICENSE will land before the first release. Do you already know which license CppJIT will use?

2. Windows

This is probably the question that matters most for us, and it is also something I had discussed with wlav while working on the original cppyy-based backend.

From the outside, most of the underlying pieces seem to exist already. CppInterOp's win2025-msvc-llvm22 and win2025-msvc-cling jobs are green, ci-workflows' setup-llvm knows about windows-2025, CppJIT still has the IS_WINDOWS handling inherited from cppyy, and conda-forge has llvmdev 20–22 for win-64.

What I can't find is anything connecting those pieces yet. The reusable cppjit.yml installs dependencies only for Linux and macOS, neither ci.yml nor nightly.yml has a Windows job, and none of CppInterOp's Windows jobs enable cppyy: On.

Is Windows simply work that hasn't been reached yet, or is there a known technical blocker?

Also, do you expect to support a particular range of MSVC toolsets?

I'd be happy to help here. I already have a reproducible GitHub Actions workflow that drives a JIT backend end-to-end on Windows runners, so I can put together a Windows CI job if that would be useful.

3. What happens to the frozen cppyy stack?

Should downstream projects treat cppyy 3.5.0 / cppyy-cling 6.32.8 as effectively final?

So actually all four packages were last released on 2024-12-17, and three of the four are still sdist-only across platforms, so even Linux users need a compiler for a normal install today.

There's also the unreleased Windows linker fix from wlav/cppyy#282:

LNK2001: Cppyy::GetNumBasesLongestBranch

As I understand it, CPyCppyy 1.13.0 build-requires cppyy-backend==1.15.2, while its setup.py run-requires 1.15.3. That's fixed on master but was never released.

Is there any chance of one final cppyy release containing fixes like that, or should downstreams assume there won't be another release and work around them?

4. Migration from cppyy to CppJIT

wheel.packages currently lists only cppjit and cppjit_backend, so I'm assuming there won't be a cppyy compatibility alias and downstream projects should migrate imports themselves. Is that the intended path?

Beyond the rename, how much API drift do you expect from cppyy 3.5?

Our usage is deliberately narrow, so most of it looks straightforward. The bit I'm most interested in is the buffer/pointer path, since we rely on passing NumPy-backed memory into generated C++ without copying it.

One smaller question: the README currently asks for LLVM 21, while CMakeLists.txt accepts LLVM 20–22. Which version would you recommend downstream projects target?

5. What would you recommend we do?

This is ultimately the decision we're trying to make.

We have about a year of work behind this backend. It works and gives us the behavior we were aiming for on Linux and macOS, but packaging and Windows support are what stand between an experimental backend and something Brian2 can actually put in front of users.

Would you recommend that we:

  1. land against the existing cppyy stack now, document the Windows limitation, and migrate to CppJIT later; or
  2. wait for the first CppJIT release and target it directly?

If the second path makes more sense, even a rough idea of the release/platform timeline would help us plan the Brian2 side.

Thanks for taking this project on. I'm also happy to help with testing or CI rather than just asking about the roadmap :) .

Brian2 should be a pretty good real-world test case for this too. We generate C++ heavily, pass NumPy-backed memory across the boundary, JIT repeatedly, and already have CI across Linux, Windows, and both macOS architectures.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions