Skip to content

Migrate Windows build to MSYS2 UCRT64 (draft, in-progress)#22551

Draft
vkalintiris wants to merge 81 commits into
masterfrom
rwin
Draft

Migrate Windows build to MSYS2 UCRT64 (draft, in-progress)#22551
vkalintiris wants to merge 81 commits into
masterfrom
rwin

Conversation

@vkalintiris

@vkalintiris vkalintiris commented May 23, 2026

Copy link
Copy Markdown
Contributor

Re-opens #22535 as a same-repo PR so workflow-file edits on this branch take effect for this PR's CI. The previous fork-based PR could not modify its own CI behavior — base-branch workflow files were used. Same commits, same content; only the head repository changed.

Summary

  • Pivot the Windows build to MSYSTEM=UCRT64 so the C side of the agent matches the C runtime, data model, and CRT linkage of the Rust toolchain. Unblocks in-process Rust FFI on Windows and lets us drop the bundled MSYS2 root from the installer.
  • Adds a tiny rust-demo staticlib smoke crate (src/crates/rust-demo/) wired into the main netdata target via a new ENABLE_RUST_DEMO option (default Off). The Windows build flips this to On at the end of the migration to validate Rust-on-Windows end-to-end.
  • This PR is intentionally a draft. Phase 2 (shell switch) plus follow-ups are committed; Phases 3-7 (source-level migration) are still to come.
  • A subsequent commit on this PR will temporarily disable all non-Windows CI jobs while the migration iterates. That commit will be reverted before merge.

What's in the PR

Commits already landed:

Commit Purpose
8733eadf Add the rust-demo smoke crate (Cargo.toml, src/lib.rs, hand-written rust_demo.h) and wire it into CMakeLists.txt behind a new ENABLE_RUST_DEMO option. Adds one netdata_log_info(\"RUST FFI smoke: …\") call next to the existing NETDATA STARTUP log line.
0b022181 Pivot the worktree to the UCRT64 migration. Documents the pivot in SOWs. compile-on-windows.sh passes -DENABLE_RUST_DEMO=Off during migration.
da82bd03 Phase 2 (shell switch): set MSYSTEM=UCRT64 in every PowerShell entry point; require it in NetdataPlatform.cmake with a FATAL_ERROR otherwise; drop the explicit -DRust_COMPILER (Corrosion finds rustc/cargo on PATH under UCRT64); replace the MSYS and MINGW64 CLion .bat files with a single UCRT64 variant.
ab6f3e65 Local-dev walkthrough for Linux→Windows VM iteration (packaging/windows/LOCAL_DEV_LINUX.md) plus dev-vm.sh wrapper.
bffb496e Phase 2 follow-up: use UCRT64 cmake (/usr/bin/cmakecmake; install mingw-w64-ucrt-x86_64-{cmake,ninja}). Flip ENABLE_RUST_DEMO default to Off so source-tarball builds without Rust toolchain don't break.
d46fba1d Phase 2 follow-up #2: relax CMAKE_INSTALL_PREFIX check to accept both /opt/netdata and the UCRT64-cmake-canonicalised C:/msys64/opt/netdata.

Background

Full investigation, ABI analysis, and migration plan in SOW-0033. SOW-0032 tracks the rust-demo smoke crate as the Rust-on-Windows validator (resumes at Phase 7 of SOW-0033).

Why draft

  • This is Phase 2 of a multi-week migration. Phases 3-7 will land as further commits on this branch.
  • Each Phase 3-7 commit is expected to surface new failures (cygwin path translation, POSIX↔Winsock2 audit, installer slim-down) that define the next phase's work.

Test plan

  • Windows CI builds — currently failing at CMAKE_INSTALL_PREFIX check (fixed in d46fba1d); next CI signal will be from Phase 3 (cygwin_conv_path removal).
  • After Phase 3 lands: no remaining references to cygwin_conv_path() in netdata C source.
  • After Phase 4 lands: socket / spawn / fd code is Win32-native; no POSIX↔Winsock2 type mismatches.
  • After Phase 6 lands: ntldd netdata.exe against the staged installer payload confirms no transitively-required DLL is missed.
  • After Phase 7 lands: Windows agent log emits RUST FFI smoke: rust-demo 0.1.0 reports nd_rust_add(2, 3) = 5.
  • End-to-end: install MSI on a clean Windows 11 VM (no MSYS2 present), confirm service starts and dashboard loads.

🤖 Generated with Claude Code


Summary by cubic

Migrates the Windows build to MSYS2 UCRT64, drops Cygwin, and adds Windows‑native shims so the agent builds and runs without msys-2.0.dll. Replaces the Event Log pipeline with a Rust wevt-builder and updates packaging to bundle UCRT64 runtime DLLs.

  • Migration

    • Build/tooling: enforce MSYSTEM=UCRT64; use UCRT cmake/ninja; define _CRT_RAND_S; use system libbacktrace via pkg-config; locate protoc.exe under $MINGW_PREFIX/bin; on Windows, use find_package(Protobuf CONFIG) so protobuf::libprotobuf pulls Abseil; accept UCRT‑canonical CMAKE_INSTALL_PREFIX; replace Event Log scripts with the Rust wevt-builder; skip -rdynamic on Windows; bundle UCRT64 runtime DLLs from $MINGW_PREFIX/bin (protobuf+Abseil, yaml, uv, curl/OpenSSL, runtimes, compression libs) and copy certs from $MINGW_PREFIX/etc/ssl.
    • CI/targets: temporarily run only Windows jobs on rwin; gate POSIX‑only targets (nd-run, spawn-tester, ndsudo) to non‑Windows; fix netdata_driver includes via $MINGW_PREFIX/include/ddk; add Linux→Windows VM walkthrough + dev-vm.sh; provide a CLion ucrt64 environment.
  • Portability

    • Sockets: reject AF_UNIX listeners/clients on Windows; route non‑blocking/close‑on‑exec via sock_setnonblock()/sock_setcloexec(); treat MSG_DONTWAIT as no‑op; alias SHUT_* to Winsock SD_*; cast recv/send buffers for Winsock; use pipe() for notification pipes and avoid non‑blocking fcntl() on Windows pipes.
    • FS/Memory: add mmap/munmap/msync shim; posix_memalign() via _aligned_malloc/_aligned_free; introduce nd_mkdir(); add os_dirent_type(); stub readlink()/lstat(); add fchmod() stub, fsync() via _commit, utimensat() via _utime64, and link() via CreateHardLinkA; replace Cygwin path calls with native translators.
    • Logging/Time: route syslog to Event Log/ETW with a clear warning; short‑circuit journald helpers; add nd_tm_gmtoff() and an sscanf() RFC‑3339 parser; provide strsep()/strcasestr()/wcscasecmp(), endian macros, strerror_r() shim, and minimal sysconf()/getrlimit()/getrusage() shims; alias random()/srandom(); set web “Date” header from st_mtime on Windows.
    • Processes/Signals: add close_range(); spawn‑server fixes for native handles and path translation; stub POSIX process/privilege APIs and scheduling (keep a sched_getparam shim); provide POSIX signal‑number shims and hex‑fallback diagnostics; align registry helpers to use DWORD*.

Written for commit d53ddad. Summary will update on new commits. Review in cubic

vkalintiris and others added 6 commits May 22, 2026 14:15
The Windows MSYS2/UCRT64 build path installs the Rust toolchain
(mingw-w64-ucrt-x86_64-rust) and passes -DRust_COMPILER=/ucrt64/bin/rustc
to CMake, but no actual Rust code is ever compiled there because every
Rust-using plugin (OTEL/journal/NetFlow/signal-viewer) is disabled in
packaging/windows/compile-on-windows.sh. That leaves us blind to whether
the Windows toolchain can build Rust at all.

This adds a tiny self-contained staticlib crate at src/crates/rust-demo
exposing nd_rust_add() and nd_rust_version() via the C ABI, gated behind
a new CMake option ENABLE_RUST_DEMO (default ON). The crate is linked
into the main netdata target and called from netdata_main() right after
the NETDATA STARTUP log line, so a draft PR through the existing
packaging workflows will exercise the Rust toolchain on Windows.

The crate is its own workspace root (no runtime dependencies, no
cbindgen) to keep compile time and dependency surface minimal -- the
goal is to test whether Rust can be built, not whether a heavy
workspace builds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The investigation in SOW-0032 showed the Windows build runs in the MSYS
shell with /usr/bin/gcc linking against msys-2.0.dll (Cygwin POSIX
emulation, LP64), while /ucrt64/bin/rustc produces UCRT-linked LLP64
objects. The mismatch is harmless for the trivial smoke crate but blocks
any non-trivial in-process Rust use. Since the project intends to write
"a lot of Rust code", the rwin worktree pivots from a one-shot smoke PR
to the full UCRT64 migration: switch the C side to /ucrt64/bin/gcc so it
shares the same C runtime and data model as Rust, drop the bundled MSYS2
root from the installer, and end with the smoke crate re-enabled on
Windows to validate the migration.

This commit only sets up the pivot:

- packaging/windows/compile-on-windows.sh: pass -DENABLE_RUST_DEMO=Off
  so Windows CI is not noised by Rust-toolchain output while migration
  phases iterate. The override will be removed at the end of the
  migration (Phase 7 of SOW-0033). Linux/macOS keep the default-on
  smoke build.
- CMakeLists.txt: clarify the smoke option's comment to point at the
  Windows opt-out path during the migration.
- SOW-0032: status paused; sub-state explains the pivot and the
  resume condition.
- SOW-0033: new, in-progress, with a filled pre-implementation gate
  and an 8-phase plan from shell switch through installer slim-down
  through final smoke re-enable. Implementation gated on user
  confirmation of phase sequencing.

No source code is migrated in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Windows MSYS2 shell defaults to MSYSTEM=MSYS, which makes the C side
of the agent link against msys-2.0.dll (Cygwin POSIX emulation, LP64).
The Rust toolchain at /ucrt64/bin/rustc produces UCRT-linked LLP64
objects. The mismatch blocks in-process Rust FFI and forces the
installer to ship the entire MSYS2 root just to provide msys-2.0.dll.

This commit pins the Windows build to MSYSTEM=UCRT64. The C compiler
and all runtime DLLs now come from the UCRT64 toolchain, matching the
Rust toolchain. Other MSYS2 environments (MSYS, MINGW64, CLANG64) are
deliberately rejected with a FATAL_ERROR so the failure mode is loud
rather than silent.

Changes:

- packaging/windows/{build,install-dependencies,invoke-msys2,package}.ps1:
  set $env:MSYSTEM = 'UCRT64' before invoking msysbash so /etc/profile
  picks the UCRT64 PATH (adds /ucrt64/bin, /ucrt64/lib/pkgconfig, etc.)
- packaging/cmake/Modules/NetdataPlatform.cmake:
  - drop CYGWIN and MSYS CMAKE_SYSTEM_NAME branches; only Windows now
  - require MSYSTEM=UCRT64 at configure time, FATAL_ERROR otherwise
  - collapse CLion include_directories branches to ucrt64 only
- packaging/windows/compile-on-windows.sh: drop the explicit
  -DRust_COMPILER=/ucrt64/bin/rustc; Corrosion finds rustc/cargo on
  PATH under UCRT64 (see Corrosion's FindRust.cmake)
- packaging/windows/clion-msys-{msys,mingw64}-environment.bat: deleted
- packaging/windows/clion-msys-ucrt64-environment.bat: added as the
  sole supported CLion developer entry point

This commit does not migrate any C source code; the next CI run is
expected to fail on the cygwin_conv_path() call sites and POSIX header
mismatches. Those failures define the work for Phases 3 and 4 of
SOW-0033.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Linux developers need a local way to validate Windows builds without
waiting on GitHub CI, especially while iterating on SOW-0033 (the
UCRT64 migration) where many phases will produce expected breakage
that needs to be observed and fixed in short cycles.

packaging/windows/LOCAL_DEV_LINUX.md walks through:

- Setting up a Windows 11 VM with quickemu/QEMU/KVM (one-time cost,
  ~1 hour to first boot).
- One-time Windows tweaks (long paths, OpenSSH server, default-shell
  -> PowerShell, the admin authorized_keys ACL gotcha).
- Installing MSYS2 inside the VM by running the repo's own
  install-dependencies.ps1 over SSH (one command from the host).
- Mounting the host's worktree into the VM at Z:\ via SSHFS-Win, so
  the host editor and the VM build see the same files live and the
  VM's build artifacts land directly under the host's build/ dir.
- Driving the VM from a Linux shell (or from an LLM assistant like
  Claude Code) via SSH, with a small wrapper script.
- A .claude/settings.json snippet that allowlists the wrapper, so a
  coding assistant can run ./packaging/windows/dev-vm.sh build, read
  the resulting errors, edit on the host, and re-build -- the VM is
  just another subshell from the assistant's perspective.

packaging/windows/dev-vm.sh is the wrapper the walkthrough references:

- build, package, deps, shell -- canned actions that map to the
  existing .ps1 entry points in packaging/windows/.
- run -- '<ps>' -- run an arbitrary PowerShell command.
- msys -- '<sh>' -- run an arbitrary command in a UCRT64 login bash,
  matching what build.ps1 sets up.

Defaults are overridable via VM_HOST and REPO_IN_VM env vars so each
developer can target their own VM without editing the script.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First CI run on draft PR #22535 surfaced two distinct failures unrelated
to the C source migration:

1. Windows build: NetdataPlatform.cmake rejected CMAKE_SYSTEM_NAME=MSYS
   even with MSYSTEM=UCRT64 set, because packaging/windows/compile-on-windows.sh
   hard-coded /usr/bin/cmake -- which is the MSYS-runtime cmake and
   always self-reports as MSYS regardless of $MSYSTEM. Setting
   MSYSTEM=UCRT64 changed PATH for gcc/pkg-config but the absolute path
   to cmake bypassed it.

2. Linux source-tarball builds across all distros, plus the LibreSSL
   and Clang Checks jobs, failed with `rustc not found in PATH`. Root
   cause: the previous default ENABLE_RUST_DEMO=On in CMake forced
   Corrosion to require rustc in every build environment, including
   ones that never needed a Rust toolchain.

Fixes:

- packaging/windows/compile-on-windows.sh: /usr/bin/cmake -> cmake so
  PATH (with /ucrt64/bin in front under MSYSTEM=UCRT64) resolves to
  the UCRT64 cmake.
- packaging/windows/msys2-dependencies.sh: install
  mingw-w64-ucrt-x86_64-cmake and mingw-w64-ucrt-x86_64-ninja so the
  UCRT64 build tools are actually present.
- CMakeLists.txt: flip ENABLE_RUST_DEMO default to Off. The smoke crate
  stays in tree; opt in per build. compile-on-windows.sh still passes
  -DENABLE_RUST_DEMO=Off explicitly during the migration (will flip to
  =On at Phase 7 to validate Rust on Windows end-to-end).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous follow-up commit (bffb496) successfully switched the
Windows build to the UCRT64 cmake, confirmed by CI: CMAKE_SYSTEM_NAME
now reports Windows and _nd_windows_config() is reached.

One step deeper, a new error surfaced:

  CMake Error at packaging/cmake/Modules/NetdataPlatform.cmake:16:
    CMAKE_INSTALL_PREFIX must be set to /opt/netdata, but it is set to
    C:/msys64/opt/netdata

Root cause: the UCRT64 cmake is a native Windows binary; when given
-DCMAKE_INSTALL_PREFIX=/opt/netdata on the command line, it interprets
the path as MSYS2-mounted POSIX and canonicalises it to the equivalent
native Windows path C:/msys64/opt/netdata. Both forms refer to the
same on-disk install location -- only the string differs from what
the MSYS-cmake would have kept verbatim.

Fix: relax the equality check to accept either the exact /opt/netdata
(Linux and MSYS-cmake) or anything ending in /opt/netdata (UCRT64-cmake
canonical form).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added area/packaging Packaging and operating systems support area/docs area/daemon area/build Build system (autotools and cmake). labels May 23, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 issues found across 20 files

Confidence score: 3/5

  • There is a concrete regression risk in packaging/windows/clion-msys-ucrt64-environment.bat: with UCRT64 paths ordered last, other toolchains can take precedence and cause incorrect Windows build/runtime behavior.
  • The other findings are documentation consistency issues in .agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md and .agents/sow/current/SOW-0033-20260522-windows-ucrt64-migration.md; these are lower severity and mainly affect reader/operator clarity rather than runtime code paths.
  • Given one medium-severity, high-confidence environment issue plus minor docs drift, this sits at moderate merge risk rather than a hard blocker.
  • Pay close attention to packaging/windows/clion-msys-ucrt64-environment.bat - PATH precedence should put UCRT64 entries first to avoid toolchain override.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md">

<violation number="1" location=".agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md:147">
P2: Doc says no Windows override, but same SOW says `-DENABLE_RUST_DEMO=Off` is active. State is conflicting. Update this section to match current paused migration behavior.</violation>
</file>

<file name=".agents/sow/current/SOW-0033-20260522-windows-ucrt64-migration.md">

<violation number="1" location=".agents/sow/current/SOW-0033-20260522-windows-ucrt64-migration.md:194">
P3: Pre-Implementation Gate status stale. It says `needs-user-decision` even though execution log shows decision made and implementation started. Mark this gate status as historical snapshot and point readers to Execution Log for current lifecycle state.

(Based on your team's feedback about treating Pre-Implementation Gate as a historical snapshot.) [FEEDBACK_USED]</violation>
</file>

<file name="packaging/windows/clion-msys-ucrt64-environment.bat">

<violation number="1" location="packaging/windows/clion-msys-ucrt64-environment.bat:18">
P2: PATH order wrong. UCRT64 bins come last, so other toolchains can override. Put UCRT64 paths first.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Dev as Linux Dev (Host)
    participant Repo as Git Repo (sshfs)
    participant VM as Windows 11 VM
    participant PS as PowerShell
    participant MSYS as MSYS2 UCRT64 Shell
    participant CMake as CMake (UCRT64)
    participant Cargo as Cargo/Rustc
    participant Netdata as netdata.exe
    participant Logger as Agent Logger

    Note over Dev,Logger: NEW: Rust FFI Smoke Test (rust-demo crate)

    Dev->>Repo: Edit source files
    Dev->>VM: dev-vm.sh build
    VM->>PS: Invoke build.ps1
    PS->>PS: Set MSYSTEM=UCRT64
    PS->>MSYS: compile-on-windows.sh
    MSYS->>CMake: cmake -DENABLE_RUST_DEMO=Off
    CMake->>CMake: Verify MSYSTEM=UCRT64
    alt MSYSTEM not UCRT64
        CMake-->>MSYS: FATAL_ERROR (reject MSYS/MINGW64)
    end
    CMake->>Cargo: corrosion_import_crate(rust_demo)
    Cargo-->>CMake: rust_demo staticlib
    CMake->>CMake: target_compile_definitions(HAVE_RUST_DEMO)
    CMake->>CMake: target_link_libraries(rust_demo)
    MSYS-->>PS: Build complete
    PS-->>VM: netdata.exe

    Note over Dev,Logger: NEW: Rust FFI Execution (runtime)

    Dev->>VM: Start netdata
    VM->>Netdata: netdata_main()
    Netdata->>Logger: "NETDATA STARTUP ..."
    opt HAVE_RUST_DEMO defined
        Netdata->>Netdata: nd_rust_add(2, 3)
        Netdata->>Netdata: nd_rust_version()
        Netdata->>Logger: "RUST FFI smoke: rust-demo 0.1.0 reports nd_rust_add(2, 3) = 5"
    end

    Note over Dev,VM: NEW: MSYS2 Dependency Changes

    MSYS->>MSYS: Install ucrt64 cmake & ninja
    MSYS->>MSYS: pacman -S mingw-w64-ucrt-x86_64-cmake
    MSYS->>MSYS: pacman -S mingw-w64-ucrt-x86_64-ninja

    Note over Dev,VM: CHANGED: CLion Dev Environment

    Dev->>Dev: Use clion-msys-ucrt64-environment.bat (single UCRT64 variant)
    Note over Dev: Removed MSYS & MINGW64 .bat files

    Note over Dev,VM: CHANGED: Path Handling

    CMake->>CMake: Accept /opt/netdata or C:/msys64/opt/netdata
    CMake->>CMake: Only include ucrt64 header path (not msys/mingw64)
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md Outdated
Comment thread packaging/windows/clion-msys-ucrt64-environment.bat Outdated
Comment thread .agents/sow/current/SOW-0033-20260522-windows-ucrt64-migration.md Outdated
To accelerate the iteration loop on the UCRT64 migration (SOW-0033),
this commit disables every CI job except 'Build Windows' (and its
file-check dependency) for the duration of work on the rwin branch.
This is a one-off change; revert (or simply drop this commit) before
merging the PR.

Mechanism:

- packaging/cmake aside: same-repo PR #22551 means GitHub Actions
  uses the head-branch workflow files for pull_request events. Edits
  here apply to this PR only; master and other PRs are unaffected.

build.yml changes:

- Gate non-Windows jobs with `if: github.head_ref != 'rwin' && ...`
  on the entry-point jobs (build-dist, static-matrix, src-matrix,
  macos-build, windows-test). Downstream jobs (build-static,
  prepare-upload, artifact-verification-*, source-build) inherit the
  skip via their `needs:` dependency on a skipped job, per GitHub
  Actions' default cascade.

All other PR-triggering workflows (checks, codeql, coverity,
check-markdown, docker, go-tests, packaging, repoconfig-packages,
review, snmp-topology-tests, tests):

- Replace the existing `pull_request:` trigger with a path filter
  that can never match (`__SOW_0033_DISABLED__`). The workflow keeps
  its push / schedule / workflow_dispatch triggers; only PR events
  are silenced. Each block carries a TEMPORARY comment with the
  revert intent.

Net effect: a push to rwin runs only 'Check Modified Files' and
'Build Windows'. Everything else is skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

12 issues found across 12 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/workflows/tests.yml
Comment thread .github/workflows/codeql.yml
Comment thread .github/workflows/packaging.yml
Comment thread .github/workflows/go-tests.yml
Comment thread .github/workflows/checks.yml
Comment thread .github/workflows/coverity.yml
Comment thread .github/workflows/repoconfig-packages.yml
Comment thread .github/workflows/snmp-topology-tests.yml
Comment thread .github/workflows/build.yml
Comment thread .github/workflows/docker.yml
Continuing SOW-0033 Phase 2 follow-ups.

- packaging/windows/msys2-dependencies.sh: install
  mingw-w64-ucrt-x86_64-libyaml so the UCRT64 cmake finds system
  libyaml instead of falling back to a bundled (and very old)
  cmake_minimum_required(< 3.5) yaml subproject.

- packaging/windows/clion-msys-ucrt64-environment.bat: prepend
  UCRT64 bins to PATH instead of appending. Appending allowed an
  unrelated toolchain already on PATH (e.g. a system MinGW64
  install) to win symbol resolution, which would defeat the whole
  point of the file.

- packaging/windows/dev-vm.sh (`msys` subcommand): switch from
  `bash -lc "MSYSTEM=UCRT64 <cmd>"` to
  `msys2_shell.cmd -ucrt64 -here -no-start -defterm -c "<cmd>"`.
  Setting MSYSTEM inside the bash command string is too late: the
  login shell sources /etc/profile (which configures PATH for the
  current MSYSTEM) before running the command. msys2_shell.cmd sets
  MSYSTEM in the parent env before bash starts, which is what we
  need to match build.ps1's behaviour.

- packaging/windows/compile-on-windows.sh: document why
  -DRust_COMPILER was dropped; under MSYSTEM=UCRT64, rustc/cargo are
  on PATH and Corrosion's FindRust discovers cargo next to rustc.

- .github/workflows/build.yml: hoist the SOW-0033 iteration
  explanation into a single anchor comment above `jobs:` and shorten
  each per-job `if:` comment to point at the anchor. Document the
  cascade-skip contract (build-static, prepare-upload,
  artifact-verification-*, source-build inherit the skip from their
  `needs:` chain) and the revert procedure.

- .agents/sow/current/SOW-0032-...md: sweep stale claims about the
  CMake option default. The original plan set ENABLE_RUST_DEMO=On
  by default; that was flipped to Off in bffb496 after CI showed
  it forced rustc onto every source-tarball build environment. The
  Acceptance Criteria, Risks, Implementation Plan, and Validation
  Plan sections now reflect the current default-Off / opt-in shape.
  The Execution Log and Implications-and-Decisions sections stay as
  the historical record.

- .agents/sow/current/SOW-0033-...md: refresh Status sub-state to
  the actual current state (Phase 2 + 2 follow-ups committed,
  Phase 3 next); update an Acceptance Criterion that mentioned a
  no-longer-existing default-On state; annotate the historical Pre-
  Implementation Gate "Open decisions" with their later resolutions;
  add the revert-the-CI-disable item to the Followup section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vkalintiris

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai please review again

@cubic-dev-ai

cubic-dev-ai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai please review again

@vkalintiris I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

8 issues found across 32 files

Confidence score: 2/5

  • Several workflow changes in .github/workflows/docker.yml, .github/workflows/packaging.yml, .github/workflows/repoconfig-packages.yml, and .github/workflows/coverity.yml effectively disable normal pull_request checks, which creates a clear regression risk by removing key CI and static-analysis gates before merge.
  • The most severe issue is user-impacting in process quality: Docker CI checks are skipped for typical PRs (7/10 severity, high confidence), so breakages are more likely to land undetected.
  • packaging/windows/LOCAL_DEV_LINUX.md has concrete setup problems (missing openssh-server prerequisite and incorrect SSHFS-Win UNC path format), so local Windows/Linux dev setup may fail end-to-end until corrected.
  • Pay close attention to .github/workflows/docker.yml, .github/workflows/packaging.yml, .github/workflows/repoconfig-packages.yml, .github/workflows/coverity.yml, and packaging/windows/LOCAL_DEV_LINUX.md - PR validation is being bypassed and dev setup instructions can break.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packaging/windows/LOCAL_DEV_LINUX.md">

<violation number="1" location="packaging/windows/LOCAL_DEV_LINUX.md:39">
P2: Missing SSH server package in prerequisites. Step 5 needs host `sshd`, but install list only adds client. Add `openssh-server` so setup works end to end.</violation>

<violation number="2" location="packaging/windows/LOCAL_DEV_LINUX.md:226">
P2: Path format wrong for SSHFS-Win UNC. `host_path` uses `/...` and builds `\/home/...`. Use backslash path components so `net use` targets the right folder.</violation>
</file>

<file name=".github/workflows/packaging.yml">

<violation number="1" location=".github/workflows/packaging.yml:5">
P2: This filter disables Packages workflow on all PRs. No PR packaging checks run. Restore normal PR trigger before merge.</violation>
</file>

<file name="packaging/cmake/Modules/NetdataPlatform.cmake">

<violation number="1" location="packaging/cmake/Modules/NetdataPlatform.cmake:21">
P2: Prefix check too loose. Suffix match allows unintended install roots. Tighten accepted Windows form so only canonicalized `/opt/netdata` paths pass.</violation>
</file>

<file name=".github/workflows/repoconfig-packages.yml">

<violation number="1" location=".github/workflows/repoconfig-packages.yml:8">
P2: PR trigger now effectively off. This workflow stops running for real repoconfig changes. Put real paths back so PR CI still catches breakage.</violation>
</file>

<file name=".agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md">

<violation number="1" location=".agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md:238">
P3: This decision line is stale against the rest of this SOW. Update it to the current default-Off state (or clearly mark it as historical) so later readers do not follow the wrong setting.</violation>
</file>

<file name=".github/workflows/coverity.yml">

<violation number="1" location=".github/workflows/coverity.yml:9">
P2: PR Coverity trigger effectively off. Static analysis stops running on normal PR changes. Re-enable real path filters before merge.</violation>
</file>

<file name=".github/workflows/docker.yml">

<violation number="1" location=".github/workflows/docker.yml:18">
P1: PR trigger now effectively off for normal changes. Docker CI checks get skipped. Re-enable default pull_request trigger.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant PS as PowerShell Scripts
    participant MSYS as MSYS2 UCRT64 Shell
    participant CMake as CMake (UCRT64)
    participant Corrosion as Corrosion
    participant Cargo as Rust Toolchain
    participant CC as C Compiler (UCRT64)
    participant Netdata as netdata.exe
    participant CI as GitHub Actions (rwin)

    Note over PS,CI: BUILD ORCHESTRATION

    PS->>MSYS: Set MSYSTEM=UCRT64
    MSYS->>CMake: cmake (UCRT64 binary, not /usr/bin/cmake)
    CMake->>CMake: Validate MSYSTEM=UCRT64
    CMake->>CMake: Accept CMAKE_INSTALL_PREFIX=C:/msys64/opt/netdata
    CMake->>CMake: Add /ucrt64/include to include path

    Note over CMake,Cargo: RUST SMOKE TEST (conditional)

    alt ENABLE_RUST_DEMO=On
        CMake->>Corrosion: Declare FetchContent(Corrosion)
        Corrosion->>Cargo: corrosion_import_crate(rust_demo)
        Cargo->>Cargo: Build src/crates/rust-demo/ as staticlib
        Cargo-->>Corrosion: librust_demo.a
        Corrosion-->>CMake: Static library reference
        CMake->>Netdata: target_compile_definitions(HAVE_RUST_DEMO)
        CMake->>Netdata: target_link_libraries(rust_demo)
    else ENABLE_RUST_DEMO=Off (default)
        CMake->>CMake: Skip Rust/Corrosion (unless other Rust plugins enabled)
    end

    Note over CC,Netdata: COMPILATION

    CC->>Netdata: Compile src/daemon/main.c
    Netdata->>Netdata: Include rust_demo.h (if HAVE_RUST_DEMO)
    Netdata->>Netdata: Link librust_demo.a (if ENABLE_RUST_DEMO)

    Note over CI: CI GATING (rwin branch only)

    alt CI branch == rwin
        CI->>CI: Skip non-Windows jobs (build-dist, static-matrix, etc.)
        CI->>CI: Skip non-Windows workflow triggers (markdown, checks, etc.)
    end

    Note over Netdata: RUNTIME STARTUP

    Netdata->>Netdata: Call nd_rust_add(2, 3)
    Netdata->>Netdata: Call nd_rust_version()
    alt HAVE_RUST_DEMO defined
        Netdata->>Netdata: Log "RUST FFI smoke: rust-demo 0.1.0 reports nd_rust_add(2, 3) = 5"
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

pull_request: null
pull_request: # SOW-0033 iteration on rwin: disable non-Windows CI. Revert this block before merge.
paths:
- '__SOW_0033_DISABLED__'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: PR trigger now effectively off for normal changes. Docker CI checks get skipped. Re-enable default pull_request trigger.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/docker.yml, line 18:

<comment>PR trigger now effectively off for normal changes. Docker CI checks get skipped. Re-enable default pull_request trigger.</comment>

<file context>
@@ -13,7 +13,9 @@ on:
-  pull_request: null
+  pull_request: # SOW-0033 iteration on rwin: disable non-Windows CI. Revert this block before merge.
+    paths:
+      - '__SOW_0033_DISABLED__'
   workflow_dispatch:
     inputs:
</file context>

$mountpoint = "Z:"
$host_user = "vk"
$host_ip = "192.168.122.1" # host as seen from the VM
$host_path = "/home/vk/repos/nd/rwin"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Path format wrong for SSHFS-Win UNC. host_path uses /... and builds \/home/.... Use backslash path components so net use targets the right folder.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packaging/windows/LOCAL_DEV_LINUX.md, line 226:

<comment>Path format wrong for SSHFS-Win UNC. `host_path` uses `/...` and builds `\/home/...`. Use backslash path components so `net use` targets the right folder.</comment>

<file context>
@@ -0,0 +1,378 @@
+$mountpoint = "Z:"
+$host_user  = "vk"
+$host_ip    = "192.168.122.1"   # host as seen from the VM
+$host_path  = "/home/vk/repos/nd/rwin"
+
+net use $mountpoint \\sshfs.r\${host_user}@${host_ip}\${host_path}
</file context>

```bash
sudo apt install qemu-system-x86 qemu-utils ovmf libvirt-clients \
libvirt-daemon-system virt-manager \
sshfs openssh-client \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Missing SSH server package in prerequisites. Step 5 needs host sshd, but install list only adds client. Add openssh-server so setup works end to end.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packaging/windows/LOCAL_DEV_LINUX.md, line 39:

<comment>Missing SSH server package in prerequisites. Step 5 needs host `sshd`, but install list only adds client. Add `openssh-server` so setup works end to end.</comment>

<file context>
@@ -0,0 +1,378 @@
+```bash
+sudo apt install qemu-system-x86 qemu-utils ovmf libvirt-clients \
+                 libvirt-daemon-system virt-manager \
+                 sshfs openssh-client \
+                 quickemu quickget
+```
</file context>

Comment on lines +5 to +7
pull_request: # SOW-0033 iteration on rwin: disable non-Windows CI. Revert this block before merge.
paths:
- '__SOW_0033_DISABLED__'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: This filter disables Packages workflow on all PRs. No PR packaging checks run. Restore normal PR trigger before merge.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/packaging.yml, line 5:

<comment>This filter disables Packages workflow on all PRs. No PR packaging checks run. Restore normal PR trigger before merge.</comment>

<file context>
@@ -2,12 +2,9 @@
-      - reopened
-      - labeled
-      - synchronize
+  pull_request: # SOW-0033 iteration on rwin: disable non-Windows CI. Revert this block before merge.
+    paths:
+      - '__SOW_0033_DISABLED__'
</file context>
Suggested change
pull_request: # SOW-0033 iteration on rwin: disable non-Windows CI. Revert this block before merge.
paths:
- '__SOW_0033_DISABLED__'
pull_request:
types:
- opened
- reopened
- labeled
- synchronize

# C:/msys64/opt/netdata). Both refer to the same on-disk location, so
# accept either: the exact string, or anything ending in /opt/netdata.
if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/netdata" AND
NOT "${CMAKE_INSTALL_PREFIX}" MATCHES "/opt/netdata$")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Prefix check too loose. Suffix match allows unintended install roots. Tighten accepted Windows form so only canonicalized /opt/netdata paths pass.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packaging/cmake/Modules/NetdataPlatform.cmake, line 21:

<comment>Prefix check too loose. Suffix match allows unintended install roots. Tighten accepted Windows form so only canonicalized `/opt/netdata` paths pass.</comment>

<file context>
@@ -12,10 +12,27 @@ include_guard()
+  # C:/msys64/opt/netdata). Both refer to the same on-disk location, so
+  # accept either: the exact string, or anything ending in /opt/netdata.
+  if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/netdata" AND
+     NOT "${CMAKE_INSTALL_PREFIX}" MATCHES "/opt/netdata$")
     message(FATAL_ERROR "CMAKE_INSTALL_PREFIX must be set to /opt/netdata, but it is set to ${CMAKE_INSTALL_PREFIX}")
   endif()
</file context>

- packaging/repoconfig/**
- .github/workflows/repoconfig-packages.yml
- .github/data/distros.yml
- '__SOW_0033_DISABLED__'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: PR trigger now effectively off. This workflow stops running for real repoconfig changes. Put real paths back so PR CI still catches breakage.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/repoconfig-packages.yml, line 8:

<comment>PR trigger now effectively off. This workflow stops running for real repoconfig changes. Put real paths back so PR CI still catches breakage.</comment>

<file context>
@@ -3,11 +3,9 @@
-      - packaging/repoconfig/**
-      - .github/workflows/repoconfig-packages.yml
-      - .github/data/distros.yml
+      - '__SOW_0033_DISABLED__'
   push:
     branches:
</file context>
Suggested change
- '__SOW_0033_DISABLED__'
- packaging/repoconfig/**
- .github/workflows/repoconfig-packages.yml
- .github/data/distros.yml

paths:
- .github/workflows/coverity.yml
- packaging/utils/coverity-scan.sh
- '__SOW_0033_DISABLED__'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: PR Coverity trigger effectively off. Static analysis stops running on normal PR changes. Re-enable real path filters before merge.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/coverity.yml, line 9:

<comment>PR Coverity trigger effectively off. Static analysis stops running on normal PR changes. Re-enable real path filters before merge.</comment>

<file context>
@@ -4,10 +4,9 @@ name: Coverity Scan
     paths:
-      - .github/workflows/coverity.yml
-      - packaging/utils/coverity-scan.sh
+      - '__SOW_0033_DISABLED__'
 env:
   DISABLE_TELEMETRY: 1
</file context>

member). Selected by user. Rationale: isolates the smoke test from
the heavy `src/crates` workspace deps; the goal is to prove the
toolchain works, not to prove the workspace builds on Windows.
2. CMake gating: `ENABLE_RUST_DEMO` default ON. Selected by user.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: This decision line is stale against the rest of this SOW. Update it to the current default-Off state (or clearly mark it as historical) so later readers do not follow the wrong setting.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md, line 238:

<comment>This decision line is stale against the rest of this SOW. Update it to the current default-Off state (or clearly mark it as historical) so later readers do not follow the wrong setting.</comment>

<file context>
@@ -0,0 +1,372 @@
+   member). Selected by user. Rationale: isolates the smoke test from
+   the heavy `src/crates` workspace deps; the goal is to prove the
+   toolchain works, not to prove the workspace builds on Windows.
+2. CMake gating: `ENABLE_RUST_DEMO` default ON. Selected by user.
+   Rationale: easy to opt out for bisecting, but ON by default so the
+   smoke test runs everywhere.
</file context>
Suggested change
2. CMake gating: `ENABLE_RUST_DEMO` default ON. Selected by user.
2. CMake gating: originally `ENABLE_RUST_DEMO` defaulted ON (historical user decision), then was flipped to Off in commit `bffb496eec` during migration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR is a draft, in-progress migration of the Windows build to MSYS2 UCRT64 so the C toolchain/runtime matches the Rust toolchain’s UCRT/LLP64 model, unblocking in-process Rust FFI and enabling eventual removal of the bundled MSYS2 root from the installer. It also introduces an optional Rust “smoke” staticlib crate and adds local Linux→Windows VM build workflow documentation/scripts to speed iteration during the migration.

Changes:

  • Add an opt-in rust-demo staticlib crate and wire it into the netdata binary behind ENABLE_RUST_DEMO / HAVE_RUST_DEMO.
  • Hard-cut the Windows build environment to MSYSTEM=UCRT64 across PowerShell entry points and enforce it in NetdataPlatform.cmake; update Windows dependency installation and build tooling to use UCRT64 CMake/Ninja.
  • Add Linux→Windows local dev walkthrough + dev-vm.sh wrapper; temporarily adjust CI workflow triggers/conditions to focus iteration.

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/daemon/main.c Calls the Rust FFI smoke functions at startup and logs the result under HAVE_RUST_DEMO.
src/crates/rust-demo/Cargo.toml Defines the standalone Rust workspace/package for the smoke staticlib.
src/crates/rust-demo/src/lib.rs Implements nd_rust_add / nd_rust_version exported via the C ABI.
src/crates/rust-demo/rust_demo.h Hand-written C header for the two exported Rust FFI symbols.
src/crates/rust-demo/Cargo.lock Lockfile for the standalone smoke crate workspace.
CMakeLists.txt Adds ENABLE_RUST_DEMO, imports the crate via Corrosion when enabled, and links it into netdata.
packaging/cmake/Modules/NetdataPlatform.cmake Enforces MSYSTEM=UCRT64 on Windows and relaxes CMAKE_INSTALL_PREFIX validation for native-UCRT64 CMake canonicalization.
packaging/windows/build.ps1 Forces MSYSTEM=UCRT64 for Windows builds.
packaging/windows/install-dependencies.ps1 Forces MSYSTEM=UCRT64 when installing MSYS2 dependencies.
packaging/windows/invoke-msys2.ps1 Forces MSYSTEM=UCRT64 for generic MSYS2 invocation.
packaging/windows/package.ps1 Forces MSYSTEM=UCRT64 for packaging.
packaging/windows/msys2-dependencies.sh Adds UCRT64 CMake/Ninja/libyaml packages to support the new toolchain path.
packaging/windows/compile-on-windows.sh Uses UCRT64 cmake from PATH and keeps ENABLE_RUST_DEMO=Off during migration.
packaging/windows/clion-msys-ucrt64-environment.bat Consolidates CLion tooling to a single UCRT64 environment setup.
packaging/windows/clion-msys-msys-environment.bat Removed legacy MSYS CLion environment.
packaging/windows/clion-msys-mingw64-environment.bat Removed legacy MINGW64 CLion environment.
packaging/windows/LOCAL_DEV_LINUX.md Documents a Linux-host workflow for driving Windows builds in a VM over SSH/sshfs.
packaging/windows/dev-vm.sh Provides a host-side wrapper to run build/deps/package and ad-hoc commands in the Windows VM.
.github/workflows/build.yml Adds temporary SOW-0033 gating commentary/conditions for iteration (needs correction per review).
.github/workflows/tests.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/snmp-topology-tests.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/review.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/repoconfig-packages.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/packaging.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/go-tests.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/docker.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/coverity.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/codeql.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/checks.yml Temporarily disables PR trigger via a never-matching paths filter.
.github/workflows/check-markdown.yml Temporarily disables PR trigger via a never-matching paths filter.
.agents/sow/current/SOW-0032-20260522-rust-on-windows-smoke.md Documents the smoke crate SOW and the temporary Windows opt-out during migration.
.agents/sow/current/SOW-0033-20260522-windows-ucrt64-migration.md Tracks the UCRT64 migration plan, phases, risks, and current execution status.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/daemon/main.c
Comment on lines +1214 to +1217
int32_t rust_sum = nd_rust_add(2, 3);
const char *rust_ver = nd_rust_version();
netdata_log_info("RUST FFI smoke: %s reports nd_rust_add(2, 3) = %d",
rust_ver ? rust_ver : "(null)", rust_sum);
Comment on lines +19 to +21
# accept either: the exact string, or anything ending in /opt/netdata.
if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/netdata" AND
NOT "${CMAKE_INSTALL_PREFIX}" MATCHES "/opt/netdata$")
Comment on lines +60 to +64
run)
shift
[ "${1:-}" = "--" ] && shift
ssh "$VM_HOST" "powershell -NoProfile -ExecutionPolicy Bypass -Command \"$*\""
;;
Comment on lines +65 to +73
msys)
shift
[ "${1:-}" = "--" ] && shift
# Use msys2_shell.cmd -ucrt64 so MSYSTEM is set in the parent env
# before /etc/profile is sourced. Setting MSYSTEM inside the bash
# -c string is too late: the login shell already configured PATH
# for the default MSYS subsystem.
ssh "$VM_HOST" "C:\\msys64\\msys2_shell.cmd -ucrt64 -here -no-start -defterm -c \"$*\""
;;

[profile.release]
opt-level = 3
lto = true
Comment on lines +27 to +42
# Several jobs below carry `if: github.head_ref != 'rwin' && ...`. This
# gates them off for the duration of the UCRT64 migration so only
# `windows-build` and its `file-check` dependency run on rwin pushes.
# Cascade-skip: jobs that `needs:` a gated entry-point (build-dist,
# static-matrix, src-matrix, macos-build) -- e.g. build-static,
# prepare-upload, artifact-verification-*, source-build -- inherit the
# skip via GitHub Actions' default behaviour (skipped dependency =
# skipped dependent).
#
# Predicate is safe in this workflow's trigger context:
# - pull_request events: `head_ref` is set to the source branch.
# - push events: only fire on `master` (see `on:` above); head_ref is
# empty, condition is true, jobs run normally.
# - workflow_dispatch: jobs that run on this event have their own
# `if: github.event_name != 'workflow_dispatch'` filter.
#
vkalintiris and others added 3 commits May 23, 2026 21:58
The OS_WINDOWS branch of netdata_detect_protobuf() hardcoded
PROTOBUF_PROTOC_EXECUTABLE="/bin/protoc". Under the previous
MSYS-cmake/MSYS-ninja stack that POSIX path resolved through the
msys-2.0.dll path-translation layer. Under the new UCRT64
cmake/ninja stack -- both native Windows binaries -- ninja sees
'/bin/protoc' as a literal filesystem path that does not exist,
and the build fails with:

  ninja: error: '/bin/protoc', needed by
  'src/aclk/aclk-schemas/proto/aclk/v1/lib.pb.cc', missing and no
  known rule to make it

Replace the hardcoded fallback with find_program(PROTOBUF_PROTOC_EXECUTABLE
NAMES protoc.exe protoc). Under MSYSTEM=UCRT64 the shell PATH begins
with /ucrt64/bin, so find_program returns the Windows-canonical
form of /ucrt64/bin/protoc.exe which ninja can resolve. The
existing $ENV{PROTOBUF_PROTOC_EXECUTABLE} override still wins if
the user wants to point at a different protoc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous attempt at finding protoc via plain `find_program(NAMES
protoc.exe protoc)` returned NOTFOUND under MSYSTEM=UCRT64 even
though `mingw-w64-ucrt-x86_64-protobuf` was installed and provides
/ucrt64/bin/protoc.exe. PATH propagation from the bash login shell
through to the native-Windows cmake.exe binary is apparently not as
reliable as one might hope; the standard PATH-only search missed
the bin directory.

Add an explicit HINTS pointing at $ENV{MINGW_PREFIX}/bin. MSYS2's
/etc/profile sets MINGW_PREFIX to /ucrt64 under MSYSTEM=UCRT64,
and the UCRT64 cmake canonicalises that to the Windows-native
C:/msys64/ucrt64/bin form. Improve the FATAL_ERROR diagnostic to
include the searched HINTS and the value of MINGW_PREFIX so the
next failure (if any) gives us the actual bash->cmake env state
to debug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous find_program attempt with HINTS at $MINGW_PREFIX/bin
returned NOTFOUND even though the mingw-w64-ucrt-x86_64-protobuf
33.5-4 package archive demonstrably ships protoc.exe at exactly that
location (verified by inspecting the .pkg.tar.zst contents:
ucrt64/bin/protoc.exe is there alongside protoc-gen-upb.exe,
libprotoc.dll, etc.).

The MSYS2 ucrt64 cmake toolchain appears to configure
CMAKE_FIND_ROOT_PATH_MODE_* in a way that masks /ucrt64/bin from
find_program even when explicitly hinted there. Rather than fight
find_program's filtering rules, just check the well-known path
directly with set + EXISTS. The MINGW_PREFIX env var is set by
MSYS2's /etc/profile to /ucrt64 (we already verified this from the
previous FATAL_ERROR diagnostic in CI).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packaging/cmake/Modules/NetdataProtobuf.cmake">

<violation number="1" location="packaging/cmake/Modules/NetdataProtobuf.cmake:102">
P1: Direct env path here can stay POSIX-shaped (`/ucrt64/...`) and break native cmake/ninja tool execution. Resolve protoc with `find_program(... NO_CMAKE_FIND_ROOT_PATH)` so the executable path is Windows-canonical.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

# ucrt64 cmake toolchain configures CMAKE_FIND_ROOT_PATH_*
# in ways that mask /ucrt64/bin from find_program even when
# passed as HINTS.
set(_nd_protoc "$ENV{MINGW_PREFIX}/bin/protoc.exe")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Direct env path here can stay POSIX-shaped (/ucrt64/...) and break native cmake/ninja tool execution. Resolve protoc with find_program(... NO_CMAKE_FIND_ROOT_PATH) so the executable path is Windows-canonical.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packaging/cmake/Modules/NetdataProtobuf.cmake, line 102:

<comment>Direct env path here can stay POSIX-shaped (`/ucrt64/...`) and break native cmake/ninja tool execution. Resolve protoc with `find_program(... NO_CMAKE_FIND_ROOT_PATH)` so the executable path is Windows-canonical.</comment>

<file context>
@@ -93,21 +93,23 @@ macro(netdata_detect_protobuf)
+                        # ucrt64 cmake toolchain configures CMAKE_FIND_ROOT_PATH_*
+                        # in ways that mask /ucrt64/bin from find_program even when
+                        # passed as HINTS.
+                        set(_nd_protoc "$ENV{MINGW_PREFIX}/bin/protoc.exe")
+                        if(EXISTS "${_nd_protoc}")
+                                set(PROTOBUF_PROTOC_EXECUTABLE "${_nd_protoc}")
</file context>

The netdata log subsystem has multiple output channels (file, syslog,
systemd-journal, Windows Event Log + ETW). On Windows, the Event Log
channel (nd_log-to-windows-events.c) is the native logging path and
already provides full functionality, but the syslog channel still
tried to compile in:

- src/libnetdata/log/nd_log-common.h included <syslog.h> unconditionally
  just to pick up the LOG_EMERG..LOG_DEBUG numeric constants that the
  ND_LOG_FIELD_PRIORITY enum aliases. <syslog.h> does not exist under
  MSYS2 UCRT64 (Windows has no syslog daemon and no syslog C API).
- src/libnetdata/log/nd_log-to-syslog.c calls openlog/syslog/closelog;
  those symbols do not exist on Windows.
- src/libnetdata/log/nd_log-init.c calls closelog() directly in the
  post-fork handler.

Make the implementation Windows-correct, and reject 'syslog' as an
output method on Windows at config-parse time with a clear warning
plus a graceful fall-back to a native Windows channel:

- nd_log-config.c: when 'output = syslog' is requested on Windows,
  log a NDLP_WARNING explaining the channel is not supported, then
  fall back to 'wel' (preferred) or 'etw' or 'stderr'. The agent
  stays up; the user's other log channels keep working; the
  misconfiguration is named so a Linux netdata.conf carried across
  is visibly degraded rather than silently honoured. Killing the
  agent here would be the wrong UX because stderr is detached when
  netdata.exe runs as a Windows service (the MSI deployment shape),
  so a fatal-at-parse error would manifest as a silent service start
  failure with no log output anywhere.

- nd_log-common.h: prefer <syslog.h> when available (detected via
  __has_include, with autoconf HAVE_SYSLOG_H as a secondary signal),
  fall back to POSIX-standard numeric LOG_* defines otherwise. Keeps
  this header self-contained for the wevt_netdata_mc_generate.c code
  generator, which compiles without netdata's autoconf chain.

- nd_log-to-syslog.c: wrap the syslog implementation in
  #if !defined(OS_WINDOWS). Provide internal_fatal() stubs for
  nd_log_init_syslog and nd_logger_syslog on Windows so the
  NDLM_SYSLOG case arms in nd_log-init.c still link. With the
  config-parse re-route above these stubs are unreachable; the
  internal_fatal() guards catch any code path that bypasses the
  config gate (dev / NETDATA_INTERNAL_CHECKS builds abort loudly,
  production builds fall through safely).

- nd_log-init.c: wrap the post-fork closelog() / re-init block with
  #if !defined(OS_WINDOWS). nd_log.syslog.initialized is always
  false on Windows, so this block was already dead at runtime there;
  the #if prevents the closelog() symbol from being referenced at
  link time.

Windows users continue to get full logging via Event Log + ETW (see
nd_log-to-windows-events.c). No functional change on Linux/macOS/BSD.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/libnetdata/log/nd_log-config.c">

<violation number="1" location="src/libnetdata/log/nd_log-config.c:119">
P2: Fallback order reversed on Windows. Prefer ETW before WEL to match Netdata’s documented/default Windows logging behavior. Keep same priority in this error path.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment on lines +119 to +124
# if defined(HAVE_WEL)
ls->method = NDLM_WEL;
fallback_name = WEL_NAME;
# elif defined(HAVE_ETW)
ls->method = NDLM_ETW;
fallback_name = ETW_NAME;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Fallback order reversed on Windows. Prefer ETW before WEL to match Netdata’s documented/default Windows logging behavior. Keep same priority in this error path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/libnetdata/log/nd_log-config.c, line 119:

<comment>Fallback order reversed on Windows. Prefer ETW before WEL to match Netdata’s documented/default Windows logging behavior. Keep same priority in this error path.</comment>

<file context>
@@ -107,8 +107,36 @@ void nd_log_set_user_settings(ND_LOG_SOURCES source, const char *setting) {
+        // wrong call when running as a Windows service because stderr is
+        // detached and the user would see a silent service-start failure.
+        const char *fallback_name;
+#  if defined(HAVE_WEL)
+        ls->method = NDLM_WEL;
+        fallback_name = WEL_NAME;
</file context>
Suggested change
# if defined(HAVE_WEL)
ls->method = NDLM_WEL;
fallback_name = WEL_NAME;
# elif defined(HAVE_ETW)
ls->method = NDLM_ETW;
fallback_name = ETW_NAME;
# if defined(HAVE_ETW)
ls->method = NDLM_ETW;
fallback_name = ETW_NAME;
# elif defined(HAVE_WEL)
ls->method = NDLM_WEL;
fallback_name = WEL_NAME;

vkalintiris and others added 2 commits May 23, 2026 23:45
…indows

ExternalProject_Add()'s CONFIGURE_COMMAND for libbacktrace pointed
directly at the autotools-generated configure script. On Linux and
macOS the kernel honours the script's #!/bin/sh shebang and the
command runs. On Windows under MSYSTEM=UCRT64, cmake and ninja are
both native Windows binaries that dispatch commands via cmd.exe,
which has no concept of shebangs and refuses to execute the file:

  'D:\...\libbacktrace-src\configure' is not recognized as an
  internal or external command, operable program or batch file.

Prefix the configure invocation with `bash` on Windows. bash.exe
ships with MSYS2 at /usr/bin/bash.exe and is on PATH under
MSYSTEM=UCRT64, so cmd.exe can dispatch to it and bash can in turn
execute the configure script as a POSIX shell program. Non-Windows
platforms keep the previous direct invocation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vkalintiris and others added 6 commits May 24, 2026 14:26
signal-code.c is pure diagnostics: it converts POSIX signal numbers
and per-signal si_code values into readable strings like
"SIGSEGV/SEGV_MAPERR" for log output. Its ENUM_STR_MAP tables name
50+ POSIX/Linux constants -- SIGUSR1, SIGCHLD, SIGCONT, SIGSTOP,
SIGRTMIN, SI_USER, SI_TIMER, SI_DETHREAD, ILL_ILLOPC, FPE_INTDIV,
SEGV_MAPERR, BUS_MCEERR, TRAP_BRKPT, etc. -- none of which UCRT64
defines and none of which fire on a native Windows process anyway.
The signal model on Windows is entirely different (SEH for memory
faults, SetConsoleCtrlHandler for Ctrl+C).

Rather than mirror 50+ #defines whose only purpose is to give a
pretty name to signals that never occur, gate the entire
table-driven body on !OS_WINDOWS and provide three stub public
functions on Windows:

  * signal_code() -- still combines signo + si_code into the 64-bit
    SIGNAL_CODE the rest of the codebase expects.
  * SIGNAL_CODE_2str_h() -- emits the hex fallback ("0x%llx") that
    the full implementation uses for unknown values anyway.
  * SIGNAL_CODE_2id_h() -- parses hex via strtoull.

Effect: Windows logs that ever surface a signal code show
"0xNNNN..." instead of "SIGSEGV/SEGV_MAPERR". Acceptable because the
underlying signals never actually fire on Windows; if they ever
appeared, it would be through a different mechanism that doesn't use
these constants.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pipe2(fds, O_CLOEXEC) is a Linux extension to POSIX. macOS has no
pipe2 and the existing code already falls back to plain pipe() there;
Windows has neither. Our common.h pipe() macro routes to UCRT's
_pipe(fds, 65536, _O_BINARY), so plain pipe() works fine.

The O_CLOEXEC bit on Linux is a thread-pipe initialisation
convenience -- these notification pipes are used purely for in-process
thread signalling, never inherited by spawned children -- so dropping
it on Windows is correct. Extend the existing __APPLE__ gate to
include OS_WINDOWS.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two standalone executables are POSIX-only:

  * nd-run is a privilege-drop helper that uses <grp.h>, getpwnam(),
    setresuid(), libcap, etc. -- none of which translate to Windows
    (account model is SIDs and ACLs there, and netdata.exe runs as a
    Windows service under a configured service account).

  * spawn-tester exercises the SPAWN_SERVER_VERSION_NOFORK fork+exec
    path via raw fcntl / pipe / socket primitives. Windows uses the
    SPAWN_SERVER_VERSION_WINDOWS path (CreateProcess + named pipes),
    which is a different implementation and is exercised through
    netdata.exe directly.

Wrap both `add_executable` blocks in `if(NOT OS_WINDOWS)`. Linux,
macOS, and FreeBSD builds unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
O_NOFOLLOW is the POSIX <fcntl.h> open flag that makes open() fail
when the trailing path component is a symlink. UCRT64 omits it
because POSIX symlinks don't exist on Windows (NTFS reparse points
are reached through entirely different APIs, not the open() file
model).

apps.plugin's apps_plugin.c sets `procfile_open_flags = O_RDONLY |
O_NOFOLLOW` as a defence-in-depth measure when running as root.
Define O_NOFOLLOW as 0 on Windows so the OR is a no-op -- the open
proceeds without symlink protection, matching what we'd do anyway
given S_IFLNK is also stubbed (Windows reparse points are not
reachable through the POSIX file-mode path).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
apps.plugin (apps_output.c), daemon/pulse (pulse-daemon.c),
exporting (send_internal_metrics.c), and unit_test.c call getrusage()
with struct rusage to report the agent's own user/system CPU
consumption. UCRT64 has neither the function nor the struct.

Provide struct rusage with the full POSIX field set (so any caller
compiles regardless of which field it reads) and an inline
getrusage() backed by GetProcessTimes(). The Win32 call gives us the
process's user and kernel FILETIME ticks (100 ns); we split each
into seconds + microseconds and write to ru_utime / ru_stime. Other
rusage fields (maxrss, page faults, IO blocks, voluntary /
involuntary context switches) stay zero -- they have no direct cheap
Win32 equivalent, and the self-stats charts that read them just
report zero on Windows. RUSAGE_SELF / RUSAGE_THREAD / RUSAGE_CHILDREN
constants are also provided.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
is_filename() in apps_pid.c uses statvfs() to confirm that a leading-slash
path lives on a real filesystem (`/path`-style POSIX paths). UCRT64 has
neither statvfs nor struct statvfs.

On Windows the GetFileAttributesW block immediately above already
handles native paths (`X:\`, `\\server\share\`, `//server/share/`),
so the statvfs path was unreachable in practice on Windows. Wrap the
block in `#if !defined(OS_WINDOWS)` so it compiles. Comment makes the
gating intent explicit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
vkalintiris and others added 3 commits May 24, 2026 15:56
ndsudo is a setuid privilege-drop helper that go.d / charts.d plugins
exec to drop to the netdata user before running. It uses POSIX
setuid()/setgid()/setegid() -- UCRT64 has none of them, and the
concept doesn't translate: netdata.exe runs as a Windows service under
a configured service account, not as root that subsequently drops
privileges.

Add `AND NOT OS_WINDOWS` to the NEED_NDSUDO predicate. Linux/macOS/
FreeBSD with the Go or scripts plugin enabled still build ndsudo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
POSIX wcscasecmp() is the wide-string counterpart to strcasecmp().
UCRT64 doesn't expose the POSIX name but ships Microsoft's
_wcsicmp() with identical signature and semantics (case-insensitive
wide-string compare returning <0 / 0 / >0).

windows-events.plugin's source-name dedup calls wcscasecmp() on the
event-log channel names. Alias it via macro so the call site compiles
without per-platform branching.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
claim/main.c is a standalone Windows-only .exe (NetdataClaim) -- the
GUI/CLI claim-token launcher. It includes <windows.h> plus a few
standard C headers but does not include libnetdata/common.h, so the
wcscasecmp alias added there one commit ago doesn't reach this file.

Repeat the same alias inline. _wcsicmp is the UCRT equivalent with
identical signature and semantics.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
vkalintiris and others added 16 commits May 24, 2026 16:41
The Windows kernel driver target had:

  target_include_directories(netdata_driver PRIVATE BEFORE "/mingw64/include/ddk" ...)

That's a subtle bug. The cmake signature is:

  target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
    <INTERFACE|PUBLIC|PRIVATE> [items1...])

i.e. AFTER/BEFORE must come BEFORE the scope keyword. With PRIVATE
listed first, cmake treats `BEFORE` as an include-path string, and
since it's a relative path, the result on disk is:

  -ID:/a/netdata/netdata/BEFORE    (nonsense)
  -I/mingw64/include/ddk           (correct, but after the nonsense)

ntddk.h was being found via the implicit /ucrt64/include/ddk fallback,
but its `#include <wdm.h>` couldn't resolve because the explicit
/mingw64/include/ddk directive was misordered. Master worked here only
because the same misparse used a path that happened to coincidentally
exist in the MSYS-runtime layout; under UCRT64 it doesn't.

Swap to the correct ordering: BEFORE PRIVATE.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
daemon.c performs POSIX daemonization (fork + setsid + setuid + chown
of run/log directories) and POSIX scheduling priority changes
(sched_setscheduler with SCHED_BATCH/SCHED_IDLE). On Windows the agent
runs as a service hosted by the SCM -- none of these apply. Privileges
are configured via ACLs at install time; scheduling priority is
controlled via SetPriorityClass/SetThreadPriority, not POSIX sched_*.

UCRT64 doesn't declare any of: chown, dirfd, unlinkat, getuid, geteuid,
getgid, getegid, setuid, seteuid, setgid, setegid, setgroups, fork,
setsid, sched_getparam, sched_setscheduler, struct sched_param,
SCHED_OTHER/SCHED_BATCH/SCHED_IDLE.

Stub everything as no-ops in the OS_WINDOWS block. Stubs:

  * chown/fchown -> return 0 (already-stubbed fchown was a hint)
  * dirfd -> return -1 (callers handle "no dir fd")
  * unlinkat -> forwards to unlink() ignoring the dir fd; relative
    paths resolve to CWD, which matches what daemon.c expects when
    the dir fd was supposed to be a parent it had cd'd to anyway.
  * get*id / set*id / setgroups -> succeed silently as the running
    process is effectively root in the Windows-service model.
  * fork / setsid -> return -1 with ENOSYS. daemon.c calls these
    only when -D is set on the command line; that flag is never used
    by the Windows service-host wrapper.
  * sched_* -> succeed silently with priority 0.

Effect on Windows: daemonization is a series of successful no-ops,
the service host then proceeds with its own startup. Linux/macOS/
FreeBSD code paths are untouched -- the real POSIX functions stay
in scope via the system <unistd.h>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ram shim

Previous commit re-declared struct sched_param and sched_setscheduler
in the OS_WINDOWS block, conflicting with the definitions that
winpthreads ships in <sched.h> (transitively included via <pthread.h>).
gcc rejected the duplicates with "redefinition of 'struct sched_param'"
and "conflicting types for 'sched_setscheduler'".

mingw-w64's <sched.h> already provides:

  * struct sched_param
  * SCHED_OTHER / SCHED_FIFO / SCHED_RR
  * sched_setscheduler / sched_getscheduler / sched_yield /
    sched_get_priority_min / sched_get_priority_max

What it does NOT provide -- and what daemon.c actually needs:

  * sched_getparam (read the current priority)
  * SCHED_BATCH / SCHED_IDLE (Linux-only policies)

Include <sched.h> explicitly so the winpthreads pieces are in scope,
then add just sched_getparam() as a no-op stub and SCHED_BATCH/
SCHED_IDLE as fallback constants. Pure addition; no conflicting
redefinitions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… args

Two follow-ups exposed by this round:

1. signal-handler.c references SIGUSR2 (and SIGUSR1 under
   FSANITIZE_ADDRESS) in its signal-action table; signals.c's deadly
   list also needs SIGUSR2/SIGCHLD/etc. Previous round shimmed only
   the deadly-signal subset (BUS/SYS/XCPU/XFSZ); add the remainder
   (HUP/QUIT/USR1/USR2/CHLD).

   Renumber the existing SIGBUS/SIGSYS shims to glibc values to keep
   every SIG* macro distinct -- previously SIGBUS=10 collided with
   the glibc-style SIGUSR1=10. New layout follows glibc/Linux
   numbering throughout, chosen so each macro stays distinct from
   each other AND from the C-standard signals UCRT actually raises.

2. netdata_registry_get_dword / netdata_registry_get_dword_from_open_key
   declared their `out` parameter as `unsigned int *` but
   win_system-info.c (and any other Windows caller) passes `DWORD *`.
   Under LLP64 both are 32-bit but `unsigned int` and `unsigned long`
   are distinct types -- gcc rejects the implicit cast.

   Change the signatures and the function bodies to use `DWORD *`.
   RegQueryValueEx already expects LPBYTE there so the cast inside
   is unchanged. Also fix the length parameter from a hardcoded 260
   (which is FILENAME_MAX, not the size of a DWORD) to sizeof(DWORD).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous `target_include_directories(... "/mingw64/include/ddk")`
literal worked under the MSYS cmake (a Cygwin binary that POSIX-
translated leading-slash paths transparently). Under the UCRT64
cmake we now use, there is no POSIX translation: `/mingw64/...`
gets interpreted as a Windows root-relative path and resolves to
<build-drive>:\mingw64\..., which never exists.

Outcome: ntddk.h was being found via the implicit /ucrt64/include/ddk
fallback (the UCRT64 toolchain's default system include path), but
its `#include <wdm.h>` could not resolve because the explicit
"/mingw64/include/ddk" -I directive pointed nowhere on disk.

Use $ENV{MINGW_PREFIX} so cmake substitutes the real prefix the
toolchain is using (/ucrt64 under MSYSTEM=UCRT64, /mingw64 under
MSYSTEM=MINGW64). The DDK headers ship in the same upstream
mingw-w64-headers package and live under the same <prefix>/include/ddk
relative path in every environment; only the prefix itself differs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three POSIX file-ops UCRT64 doesn't ship:

  * fchmod(fd, mode) -- status-file-io.c uses it to set 0664 on the
    temp file before rename. Windows permissions are ACL-based, not
    POSIX mode bits; stub returns 0 so the call is informational.

  * fsync(fd) -- UCRT's _commit(fd) is the documented equivalent,
    same signature and same semantic (flush buffered modifications
    to disk). Forward via macro.

  * utimensat(dirfd, path, times[2], flags) -- POSIX *at-family
    timestamp updater with nanosecond precision. UCRT has _utime64
    (sec precision, path-based, no dir-fd). machine-guid.c calls
    utimensat(AT_FDCWD, path, times, 0); route through _utime64
    with sec-precision truncation. The persisted GUID-file mtime is
    diagnostic, not load-bearing, so the truncation is acceptable.

AT_FDCWD added as a sentinel value the stub ignores. Linux/macOS/
FreeBSD continue to use the real fchmod/fsync/utimensat from
<unistd.h> / <fcntl.h>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Winsock declares recv() and send() with `char *` / `const char *`
buffer arguments; POSIX uses `void *` / `const void *`. C call sites
(libnetdata/socket/nd-sock.h's static inlines) pass `void *` directly
and rely on the implicit conversion -- which works in C with a warning
but is outright rejected in C++.

ml/ad_charts.cc includes nd-sock.h transitively and hit the failure:
"invalid conversion from 'void*' to 'char*'" on the recv/send calls
inside nd_sock_revc_nowait / nd_sock_peek_nowait / nd_sock_send_nowait.

Same fix pattern as get/setsockopt one commit ago: self-referencing
macros that cast the buffer arg to char * / const char *. C99 6.10.3
guarantees the inner recv/send resolve to the Winsock functions, not
the macros.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
UCRT64 has no POSIX unsetenv(). The documented Microsoft equivalent
is _putenv("NAME=") -- an empty value triggers the delete-the-variable
path. rrdhost-labels.c calls unsetenv() to remove a variable from the
process environment after reading it.

Wrap with the POSIX signature: validate that the name has no '=' (per
POSIX EINVAL), allocate a NUL-terminated "NAME=" string, and call
_putenv. Free the buffer before returning so we don't leak; UCRT's
_putenv copies the value internally and is safe to free after.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
POSIX XSI random()/srandom() are 31-bit linear-congruential RNGs;
UCRT64 has only C-standard rand()/srand() (15-bit per call).
dbengine-stresstest.c uses random() to pick chart/dim indices during
stress runs -- the reduced range from rand (RAND_MAX = 0x7FFF) is
acceptable for a stress-test helper, all the values consumed are
modulo'd to small bounds anyway.

Alias the names via macro. srandom takes the seed as a long; UCRT
srand takes unsigned -- cast in the macro.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
-rdynamic asks the linker to export all dynamic symbols so backtrace()
and friends can resolve them at runtime. ELF (Linux/FreeBSD) and
Mach-O (macOS) linkers support it; the mingw-w64 binutils ld variant
that the UCRT64 toolchain uses on Windows does not -- PE/COFF symbol
export works through __declspec(dllexport) or a .def file instead.

NetdataClaim.exe and windows-events.plugin.exe both failed to link
with "cc.exe: error: unrecognized command-line option '-rdynamic'".

Guard the add_link_options(-rdynamic) call with NOT OS_WINDOWS. The
compile-side frame-pointer / unwind-table flags are unchanged --
those work fine on Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
UCRT64 has no POSIX link() (create hard link). Windows exposes the
equivalent through Win32: CreateHardLinkA(new, existing, NULL).
NTFS supports hard links natively.

The registry rotation in registry_db.c uses link(current, ".old")
followed by unlink(current) to do an atomic backup before writing
the new database -- if anything goes wrong mid-write, the .old copy
still exists. The same pattern works on Windows via the hard-link
equivalent.

Wrap CreateHardLinkA with the POSIX link() signature: int return,
0 on success, -1 with errno on failure. Map the common Win32 error
codes to POSIX errnos so the caller's `errno != ENOENT` test still
behaves correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
POSIX shutdown(fd, how) takes SHUT_RD / SHUT_WR / SHUT_RDWR for the
direction. Winsock's shutdown() takes SD_RECEIVE / SD_SEND / SD_BOTH
-- same numeric values, different names. mingw-w64's <winsock2.h>
defines the SD_* names but not the POSIX SHUT_* aliases.

stream-receiver.c shutdowns the streaming socket with SHUT_RDWR.
Alias the three POSIX names via #define so the call sites compile
unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
POSIX 2008 added the st_mtim / st_atim / st_ctim struct timespec
fields to struct stat for nanosecond-resolution timestamps. UCRT's
struct stat predates this and exposes only the second-resolution
st_mtime / st_atime / st_ctime fields.

The existing #ifdef __APPLE__ ... #else branch picked st_mtimespec
on macOS and st_mtim everywhere else. Add an OS_WINDOWS branch that
reads st_mtime directly. Second precision is fine here -- the value
feeds an HTTP "Date" header that has only second resolution anyway.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
websocket-handshake.c sets the command-pipe read side to non-blocking
via fcntl(F_SETFL, O_NONBLOCK) so the poll-driven thread can drain
all signal bytes without a final blocking read. UCRT64 has no
fcntl(), and anonymous pipes from _pipe() aren't trivially switchable
to non-blocking under Win32 (SetNamedPipeHandleState applies to named
pipes; CRT-fd pipes have no documented per-fd toggle).

The websocket command pipe carries short, well-bounded signal bytes,
not a streaming workload. A blocking short-read of a single signal
byte is fine in practice -- the poll/nd_poll layer wakes the thread,
the read pulls one byte, the loop continues.

Wrap the fcntl() call with `#if !defined(OS_WINDOWS)`. Linux/macOS/
FreeBSD behaviour is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
netdata.exe failed to link at the very end of the build with hundreds
of undefined references to Abseil symbols:

  absl::lts_20260107::status_internal::StatusRep::Unref()
  absl::lts_20260107::hash_internal::MixingHashState::kSeed
  absl::lts_20260107::hash_internal::CombineLargeContiguousImpl...
  google::protobuf::internal::ThreadSafeArena::thread_cache_
  ...

Root cause: the NetdataProtobuf.cmake Windows branch hardcoded
`set(PROTOBUF_LIBRARIES "-lprotobuf")` and stopped there. Protobuf 22+
links against Abseil; MSYS2's mingw-w64-ucrt-x86_64-protobuf (v33.x)
ships protobuf-config.cmake which declares the abseil deps as
transitive requirements of protobuf::libprotobuf. The bare `-lprotobuf`
linker arg pulled in libprotobuf.a only and dropped abseil on the
floor.

Switch the Windows branch to use find_package(Protobuf CONFIG REQUIRED)
-- same path the Linux branch already uses -- so the abseil deps come
along automatically through the protobuf::libprotobuf target. The
protoc.exe location detection stays unchanged (still uses MINGW_PREFIX
explicitly; find_program-via-package would still fail to locate it
under the CMAKE_FIND_ROOT_PATH_* policy on the MSYS2 ucrt64 toolchain).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Windows install step hard-coded three MSYS-runtime DLLs from
/usr/bin: msys-protobuf-32.dll, msys-yaml-0-2.dll, msys-uv-1.dll.
Those are the Cygwin-style libraries the MSYS shell build linked
against. Under MSYSTEM=UCRT64 we link against native Windows libs
from $MINGW_PREFIX/bin with different names -- libprotobuf-33.X.dll,
libyaml-0-2.dll, libuv-1.dll, plus libabsl_*.dll (the Abseil
dependencies that protobuf 22+ pulls in).

The hardcoded path made the install step fail with:

  file INSTALL cannot find "/usr/bin/msys-protobuf-32.dll"

Switch to a globbed list of $MINGW_PREFIX/bin/lib*.dll patterns
that covers everything netdata.exe / plugins are likely to load at
runtime. Glob rather than hard-list the abseil files: 40+ libabsl_*
DLLs exist and the set changes with each upstream release.
CONFIGURE_DEPENDS so cmake re-evals if the MSYS2 package set changes.

Coverage: protobuf + abseil, yaml, uv, openssl/libcrypto, libcurl
and its TLS-stack deps (gnutls, nettle, gmp, hogweed, tasn1,
unistring, p11-kit, libssh2, idn2, psl, nghttp*), the gcc/stdc++
runtime and winpthreads, plus the compression libs (zlib, lz4,
zstd, brotli) and pcre2.

Also relocate the ssl-cert directory copy from /usr/ssl (MSYS
location) to $MINGW_PREFIX/etc/ssl (UCRT64 location); curl looks
for ca-bundle there.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2 Security Hotspots
E Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/aclk area/build Build system (autotools and cmake). area/ci area/claim area/collectors Everything related to data collection area/daemon area/database area/docs area/packaging Packaging and operating systems support area/web collectors/apps

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants