Native Windows development

Chimera’s Windows build uses MSVC, the Windows SDK, and libevpl’s native IOCP/Winsock backend. It does not require Cygwin or an MSYS runtime. Build and test both Debug and Release; the CI matrix includes x64 and ARM64.

Build

Install Visual Studio 2022 or 2026 (or its Build Tools) with the Desktop development with C++ workload, a Windows SDK, and the compiler tools for your target architecture. Also install CMake, Git, Python 3, Node.js 22, and WinFlexBison 2.5.25. Use an ARM64 target and dependencies in a Windows ARM VM on Apple silicon.

From PowerShell, starting in a recursive checkout:

git submodule update --init --recursive
git clone https://github.com/microsoft/vcpkg _vcpkg
$baseline = (Get-Content vcpkg.json -Raw | ConvertFrom-Json).'builtin-baseline'
git -C _vcpkg checkout $baseline
./_vcpkg/bootstrap-vcpkg.bat -disableMetrics
$quintVersion = (Get-Content ext/specs/.quint-version).Trim()
npm install -g "@informalsystems/quint@$quintVersion"

# Change both values to x64 / x64-windows for an Intel/AMD target.
$arch = 'ARM64'
$triplet = 'arm64-windows'
# Use 'Visual Studio 17 2022' if that is the version installed locally.
$generator = 'Visual Studio 18 2026'
$parserTools = 'C:/tools/winflexbison'
cmake -S . -B build -G $generator -A $arch `
  "-DCMAKE_TOOLCHAIN_FILE=$pwd/_vcpkg/scripts/buildsystems/vcpkg.cmake" `
  "-DVCPKG_TARGET_TRIPLET=$triplet" "-DVCPKG_HOST_TRIPLET=$triplet" `
  "-DFLEX_EXECUTABLE=$parserTools/win_flex.exe" `
  "-DBISON_EXECUTABLE=$parserTools/win_bison.exe" `
  -DOTEL_SQLITE=ON -DREQUIRE_CTL_MBT=ON -DREQUIRE_DISKFS_MBT=ON
cmake --build build --config Debug --parallel 4

CI builds with Ninja instead, from a Visual Studio developer environment for the target architecture (a Developer PowerShell, or vcvarsall.bat arm64 / x64), which lets the model corpus generate in parallel with the C build and lets ccache cache the compiles. Either generator works locally; with Ninja the configuration is chosen at configure time:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=cl `
  "-DCMAKE_TOOLCHAIN_FILE=$pwd/_vcpkg/scripts/buildsystems/vcpkg.cmake" `
  "-DVCPKG_TARGET_TRIPLET=$triplet" "-DVCPKG_HOST_TRIPLET=$triplet" `
  "-DFLEX_EXECUTABLE=$parserTools/win_flex.exe" `
  "-DBISON_EXECUTABLE=$parserTools/win_bison.exe" `
  -DOTEL_SQLITE=ON -DREQUIRE_CTL_MBT=ON -DREQUIRE_DISKFS_MBT=ON
cmake --build build

When ccache is on PATH, Ninja builds use it and embed debug information in each object (/Z7), which ccache can cache; Visual Studio generators ignore it.

The manifest installs the native dependencies through vcpkg. The parser generators are build tools, not a POSIX runtime dependency. Generated model traces use the pinned Quint release through Node.js, without requiring Unix symlinks or a shell. Model corpus generation can take substantially longer than compiling the C sources; set SPECS_CORPUS_CACHE_DIR to a directory in the build environment to reuse traces whose models and configs have not changed, as CI does.

CI uses prebuilt dependencies from the Windows dependency publisher: VS2022 on windows-2022 for x64, and VS2026 on the explicit windows-11-vs2026-arm image for ARM64. It restores packages with read-only access and --only-binarycaching, then passes that restriction to CMake too. A missing package fails promptly instead of starting a source build. Rerun the publisher on main when the manifest or dependency toolchain changes, then rerun the Windows job. The restore step records its duration in the job summary. The local build commands above still permit source builds when no feed is configured.

Executables and their dependent DLLs are placed in build/bin/Debug or build/bin/Release (build/bin with Ninja). Keep the DLLs beside the executable when running it. Pass an explicit configuration file with chimera.exe -c <file>; the Linux example configuration includes backends that are unavailable on Windows.

Test

Windows uses the same quick and extended tiers as Unix. PR checks run the quick tier on x64 Release; the merge queue and pushes to main run it on x64/ARM64 Debug/Release. The scheduled Extended workflow runs the full matrix and suite. Both call the reusable Windows build/test workflow and publish the same JUnit/duration artifacts as the other platforms.

A Ninja build selects the tier as on Unix: plain ctest runs the quick tier and ctest -C extended runs everything. With a Visual Studio generator, CTest’s -C selects the binary configuration, so the generated quick-tests.txt selects the quick tier separately (CTest 3.29 or newer):

ctest --test-dir build -C Debug --tests-from-file "$pwd/build/quick-tests.txt" --output-on-failure

Some shared fixtures use /tmp and /build/test. Create these directories on the current drive before running the full suite, as the workflow does:

New-Item -ItemType Directory -Force /tmp, /build/test | Out-Null
ctest --test-dir build -C Debug --output-on-failure --parallel 4 --timeout 300
cmake --build build --config Release --parallel 4
ctest --test-dir build -C Release --output-on-failure --parallel 4 --timeout 300

The runtime primitives can be built and tested independently, without vcpkg or model generation:

cmake -S src/common/tests/native -B runtime -G $generator -A $arch
cmake --build runtime --config Debug
ctest --test-dir runtime -C Debug --output-on-failure

The full suite exercises the portable VFS, protocol servers, client APIs, and model replay harnesses. Native POSIX client tests operate on Chimera’s virtual filesystems; they do not implement POSIX semantics for arbitrary Windows host files. Fork-based stress programs, kernel mounts, network namespaces, and external Unix Samba tools remain Unix test paths.

Windows SMB client

src/server/smb/tests/windows_client/windows_smb_client_test.py drives a native daemon with the real Windows SMB client on the same machine. One daemon serves each requested backend (memfs, diskfs, cairn) as a share, and the script maps each with net use /TCPPORT and runs file-level checks through the ordinary Win32 APIs, robocopy and icacls. Port 445 belongs to the kernel’s own SMB server and cannot be freed without a reboot, so the test needs a client that can reach an alternate port: Windows 11 24H2 or Windows Server 2025. It exits 77 (skipped) on older clients, including Server 2022.

python src/server/smb/tests/windows_client/windows_smb_client_test.py `
  build/bin/chimera.exe memfs diskfs cairn --daemon-log daemon.log

--daemon-debug starts the daemon with -d, which dumps every SMB request. If the daemon fails to stop, the script prints every thread’s stack with cdb from the Windows SDK before killing it. CI runs it in the smb-client job of the Windows workflow against the Release build: on Server 2025 for x64 and on Windows 11 for ARM64.

IFSTest

src/server/smb/tests/windows_client/ifstest/ runs Microsoft’s IFS test (IFSTest, from the Windows HLK) through the same client against each backend. fetch_kit.ps1 downloads the IFSTest packages from Microsoft and prints the directory holding ifstest.exe; nothing from the HLK is kept in the repository or in CI caches. ifstest_chimera.py maps each backend and runs IFSTest against it, writing one log per backend, and ifstest_check.py judges those logs against ifstest_expected.csv, the tests known not to pass on each backend and why. A failure not listed there fails the check; a listed test that starts passing is reported so it can be taken off the list.

$kit = & src/server/smb/tests/windows_client/ifstest/fetch_kit.ps1
python src/server/smb/tests/windows_client/ifstest/ifstest_chimera.py `
  build/bin/chimera.exe $kit ifstest-logs 1500 memfs diskfs cairn
python src/server/smb/tests/windows_client/ifstest/ifstest_check.py `
  ifstest-logs src/server/smb/tests/windows_client/ifstest/ifstest_expected.csv `
  memfs diskfs cairn

A run takes about 25 minutes per backend, so CI runs it only at the extended tier, in the ifstest job of the Windows workflow (Server 2025, x64).

Platform choices

  • Native threads, synchronization, scalar atomics, timers and secure randomness replace POSIX dependencies. Windows uses the domain-lock reclamation fallback from common/chimera_rcu.h, backed by native mutexes and condition variables with writer preference. Unix uses liburcu when available; URCU_SUPPORT=OFF exercises the same fallback there. The earlier Windows-specific QSBR implementation and CHIMERA_NATIVE_RCU option have been removed.
  • memfs, diskfs, and cairn use the shared VFS. Windows diskfs uses libevpl’s native implementation of its portable block backend. The Linux passthrough backend, io_uring, libaio, RDMA, XLIO, FUSE, and GPUDirect Storage are unavailable on Windows.
  • Windows TLS uses libevpl’s Schannel backend. SMB signing/encryption, NTLM, REST tokens, S3 authentication, and secure randomness use Windows CNG; Base64 uses Crypt32. Linux and macOS retain OpenSSL. No OpenSSL package or DLL is required on Windows. Without a supplied certificate/key pair, the Windows daemon uses libevpl’s self-signed identity without writing PEM files. The daemon calls evpl_cleanup() after stopping its server and exporters, before Windows unloads the crypto and RPC libraries.
  • The Windows authentication build supports Chimera-managed users and native password verification. MIT Kerberos/GSSAPI defaults off, and requests requiring that provider fail explicitly. NSS, Winbind, and an SSPI/Active Directory provider are not part of this port.
  • Chimera libraries are DLLs on Windows, as they are shared objects on Linux, and VFS backends are loaded at runtime from chimera_vfs_<name>.dll beside chimera_vfs.dll (or $CHIMERA_VFS_MODULE_DIR, or a module_path). A DLL must name the DLL every import comes from, so the libraries form a strict hierarchy with no cycles, and data crossing a DLL boundary is declared through common/export.h. An out-of-tree backend links the import libraries chimera_vfs.lib and chimera_common.lib.
  • The public client API uses chimera_off_t, chimera_dev_t, chimera_dirpos_t, and chimera_posix_stat_t so file offsets, device IDs, directory positions, and metadata remain full width under Windows’ LLP64 ABI. On Unix these alias the corresponding native types. Code consuming the API should use the Chimera names.

The daemon runs as a console application. Windows Service Control Manager integration and an installer are separate work.

The POSIX client preserves quota and stale-handle errors on Windows using EDQUOT (2001) and ESTALE (2002), defined by Chimera because the Windows CRT does not provide them. Compare these symbols when handling errors; the CRT strerror() does not supply descriptions for these two values.

Crypto backend validation

The normal quick suite includes fixed digest, HMAC, CMAC, GMAC, SP800-108 KDF, NTLM key-exchange and AES-128/256 CCM/GCM vectors on every platform. The standalone Windows crypto build needs no third-party libraries. The tests include split MAC input, embedded NULs in KDF labels, multi-block KDF output, and rejection and clearing of unauthenticated plaintext. The same tests exercise OpenSSL in the normal Unix suite, and can run separately:

cmake -S src/common/tests/crypto -B crypto
cmake --build crypto
ctest --test-dir crypto --output-on-failure

SMB and S3 wire probes retain independent protocol encoders and use the shared primitive interface. Windows GMAC currently gathers scatter/gather input as contiguous AAD for CNG; the Unix backend continues streaming it to OpenSSL.


This site uses Just the Docs, a documentation theme for Jekyll.