Skip to content

os: add support for windows - #2427

Draft
AmyJeanes wants to merge 7 commits into
commaai:masterfrom
AmyJeanes:windows
Draft

os: add support for windows#2427
AmyJeanes wants to merge 7 commits into
commaai:masterfrom
AmyJeanes:windows

Conversation

@AmyJeanes

@AmyJeanes AmyJeanes commented Sep 7, 2026

Copy link
Copy Markdown

SCons' default tool picks MSVC on Windows; the firmware build and the libpanda test library use the mingw tool with clang there (MSYS2 CLANG64), like openpilot's own Windows build. SCons requires the .dll suffix, so the target and the cffi path are named per platform, and no import library is produced since nothing links against it. The libpanda build inherits the shell's environment so that cmd.exe finds clang on the MSYS2 PATH.

CANPacket_t is memcpy'd onto the USB wire, so the DLL is compiled with -mno-ms-bitfields: mingw's default MS layout would put the checksum at byte 8 instead of 5. cffi's Windows backend follows MSVC bitfield rules and cannot be switched, but MSVC packs same-typed bitfields contiguously, so declaring the three flag bits as unsigned int like addr gives the firmware layout under both rule sets; the layout on Linux and macOS is unchanged.

The signing step runs sign.py through the interpreter running SCons, with SETLEN in the command's environment: cmd.exe, the shell SCons uses on Windows, runs neither a script by its shebang nor a VAR=value prefix. It is the same command on Linux and macOS, spelled out.

Same packet-layout fix as opendbc's libsafety.

panda's own ./test.sh runs on Windows in CI too, which the rest of the change covers:

  • The dev dependencies take the ARM toolchain and cppcheck from PyPI (comma-deps-gcc-arm-none-eabi, comma-deps-cppcheck), like the other comma-deps consumers: the release-* shim branches know only Linux and macOS. Those wheels need Python 3.12, hence the markers; bumping panda's Python floor instead would be the other option.
  • setup.sh activates the venv from Scripts/ in an MSYS2 shell and pins uv to a native CPython there (the toolchain's own python comes first on PATH, and its wheels are incompatible).
  • test_misra.sh calls the venv's python instead of python3: setup.sh has activated the venv by then, and a uv venv on Windows has no python3. The mutation test runs the script through the bash found on PATH rather than the platform shell: cmd.exe cannot run it, and a bare bash would reach the WSL launcher in System32 first.
  • test.yaml: a windows-latest entry in the ./test.sh matrix, run from the MSYS2 CLANG64 shell that setup-msys2 provides (only clang is installed on top of the runner's MSYS2; the firmware toolchain comes from uv). Only that entry names its shell; the others keep bash -e {0}, GitHub's implicit default. The existing Windows pip package job stays: it checks the toolchain-free install path on a stock Python.
  • A .gitattributes keeps every checkout LF: Git for Windows defaults to autocrlf, and bash cannot run a CRLF script. The nine ST vendor files that were stored with CRLF are normalised to LF in their own commit (line endings only, git diff --ignore-cr-at-eol is empty), so nothing gets rewritten later on an unrelated edit.

Note: the vast majority of this diff is the nine ST vendor files under board/stm32h7 going from CRLF to LF for the .gitattributes change, in their own commit (9 files, 54,251 lines each way, line endings only: git diff --ignore-cr-at-eol is empty for it). The actual change is the other 10 files, +66/-16.

Tested on Windows: the firmware and libpanda build and sign with the mingw tools from an MSYS2 CLANG64 shell, and panda's own ./test.sh runs green there in 64 s (the firmware for all three boards and libpanda build and sign, ruff passes, and pytest passes all 9 tests, the three misra mutation cases included, about 50 s each in parallel); tests/usbprotocol/test_comms.py passes against the DLL (5/5), which is the packet-layout check; this repo's workflow on this PR, including its existing windows-latest pip package job (the new Windows ./test.sh entry takes about 3.5 min of the job's 10); and openpilot's full unit test suite on its Windows CI job, which builds this branch: commaai/openpilot#38810. The Linux and macOS builds are unchanged, confirmed by the same workflow.

Draft: waiting on commaai/dependencies#107. The Windows CI entry installs comma-deps-gcc-arm-none-eabi and comma-deps-cppcheck for win_amd64 from PyPI, which that PR publishes on merge. Until then the last commit, titled TEMP and marked --- TODO REMOVE AFTER DEPENDENCY PR MERGES ---, points uv at a GitHub release of the same wheels built from that PR's branch on my fork, so the entry runs green here meanwhile. That commit is dropped and this PR marked ready once the wheels are on PyPI; nothing else in it changes.

This PR is part of a larger series of work bringing support for Windows to openpilot:

The dependencies PR goes first: the Windows CI entries here and in the other combined PRs install the wheels it publishes. Otherwise each PR merges independently; only the openpilot one depends on all of them.

The changes in this PR were generated by Claude Fable 5.1 but were human reviewed and fully tested end to end both locally and in CI.

AmyJeanes and others added 2 commits September 6, 2026 01:42
The default SCons tools pick MSVC there. The host-side libpanda test
library is skipped on Windows: -nostdlib does not link as a DLL.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
The test library's own Environment picked MSVC on Windows; use the mingw
tool with clang like the firmware build. SCons requires the .dll suffix
there, so name the target and the cffi path per platform, and skip the
import library nobody links against.

CANPacket_t is memcpy'd onto the USB wire, so the DLL must use the packed
GCC bitfield layout (-mno-ms-bitfields): mingw's MS layout puts the checksum
at byte 8 instead of 5. cffi's Windows backend follows MSVC bitfield rules
and cannot be switched, but MSVC packs same-typed bitfields contiguously, so
declaring the three flag bits as unsigned int like addr gives the firmware
layout under both rule sets (unchanged layout on Linux and macOS).

tests/usbprotocol/test_comms.py passes on Windows (5/5).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
The signing step ran `SETLEN=1 sign.py ...` as a shell command, which cmd.exe,
the shell SCons uses on Windows, cannot run: it neither starts a script by
its shebang nor understands a VAR=value prefix. The interpreter running SCons
is the one with the dependencies, and SETLEN moves into the command's
environment. Same command on Linux and macOS, spelled out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
@AmyJeanes AmyJeanes changed the title os: add support for windows os: add support for windows (1/2) Sep 7, 2026
AmyJeanes and others added 3 commits September 7, 2026 22:36
SCons' default construction environment on Windows carries only the system
directories in PATH, so cmd.exe cannot find clang unless the mingw tool
happens to locate a toolchain. The MSYS2 shell's PATH has it, like the
firmware environment already inherits.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
Line endings only (git diff --ignore-cr-at-eol is empty), so a .gitattributes
that keeps checkouts LF does not rewrite them on an unrelated edit later.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
The dev dependencies take the ARM toolchain and cppcheck from PyPI, like the
other comma-deps consumers: the release shim branches know only Linux and
macOS. Those wheels need Python 3.12, hence the markers. setup.sh activates
the venv from Scripts/ in an MSYS2 shell and pins uv to a native CPython
there (the toolchain's own python comes first on PATH and its wheels are
incompatible). test_misra.sh calls the venv's python: a uv venv on Windows
has no python3. The mutation test runs the script through the bash found on
PATH rather than the platform shell (cmd.exe on Windows, and a bare "bash"
would reach the WSL launcher in System32 first), and normalises its glob
paths, which Windows returns with backslashes that defeated the ignore list.

test.yaml gets a windows-latest entry running the same ./test.sh from a
CLANG64 shell. Only that entry names its shell; the others keep bash -e {0},
GitHub's implicit default. A .gitattributes keeps every checkout LF: Git for
Windows defaults to autocrlf, and bash cannot run a CRLF script.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
@AmyJeanes
AmyJeanes marked this pull request as draft September 7, 2026 23:22
@AmyJeanes AmyJeanes changed the title os: add support for windows (1/2) os: add support for windows Sep 7, 2026
…ies#107 publishes

--- TODO REMOVE AFTER DEPENDENCY PR MERGES (commaai/dependencies#107) ---

This commit is dropped from the PR once the win_amd64 wheels are on PyPI.
Until then it points uv at a GitHub release of the same wheels, built from
that PR's branch on my fork, so the Windows CI entry runs here meanwhile:
comma-deps-gcc-arm-none-eabi and comma-deps-cppcheck for sys_platform ==
'win32'. Linux and macOS resolve from PyPI as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AgqYZYWLpwE2T5vS3nVEt
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.

1 participant