fix(build): embed Windows manifest via target_sources, not /MANIFEST:EMBED#3947
Conversation
…EMBED — Principle XI. CMake's Ninja vs_link_exe wrapper already owns MSVC manifest embedding: link.exe emits a side-car .manifest, then mt.exe merges/embeds it. Passing /MANIFEST:EMBED + /MANIFESTINPUT directly (added in aethersdr#3237 to fix LNK1220) tells link.exe to embed inline instead, so it emits no side-car manifest — CMake's mt.exe step then runs with an empty --manifests list and fails with c10100a7 on cmake 4.x. Fix: list the .manifest file as a target source so CMake feeds it to its own vs_link_exe/mt.exe embed step natively. No linker flags needed. Verified by inspecting the generated build.ninja: LINK_FLAGS no longer carries the conflicting flags, and MANIFESTS now correctly lists the .manifest file for the mt.exe step. Also adds a Windows 11 build section to README.md's "Building from Source", covering vcvars64.bat -> setup-fftw.ps1 -> cmake configure/build, per the secondary ask in the issue. Fixes aethersdr#3835
There was a problem hiding this comment.
Thanks for the careful fix and the clear root-cause writeup, @gauthig — this correctly untangles the /MANIFEST:EMBED vs. CMake's vs_link_exe/mt.exe machinery.
The approach is sound. Listing the .manifest as a target source is the CMake-native way to embed it: CMake feeds it to its own mt.exe step, so the two no longer fight over who owns embedding. I confirmed there's no double-embed hazard — packaging/windows/AetherSDR.rc only declares IDI_ICON1 ICON, not an RT_MANIFEST resource, so nothing else is trying to embed a manifest. The change is correctly scoped inside the if(MSVC) block and uses CMAKE_SOURCE_DIR consistently with the WIN_RC handling just above it. Both files are in scope for the issue.
One minor, non-blocking note on the README: the new Windows 11 section lists Ninja as a prerequisite but the configure command (cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo) doesn't pass -G Ninja. With VS Build Tools installed, CMake's default generator is the Visual Studio generator, not Ninja — so a reader following the steps verbatim won't actually exercise the Ninja path this fix was reproduced against. The fix works under both generators, so this is purely a docs-consistency nit; consider adding -G Ninja (or dropping Ninja from the prereq list) to match intent.
Nice work — the reporter-confirmed link success plus the build.ninja inspection is exactly the kind of evidence that makes a build fix easy to trust.
🤖 aethersdr-agent · cost: $1.5081 · model: claude-opus-4-8
The Windows section as submitted wouldn't produce a working build if followed verbatim: - Missing `-G Ninja`: on Windows CMake defaults to the multi-config Visual Studio generator, which ignores -DCMAKE_BUILD_TYPE=RelWithDebInfo (and `cmake --build` without --config builds Debug) — and takes a different manifest-embed path than the Ninja vs_link_exe one this PR fixes. - No Qt discovery hint: find_package(Qt6 6.2 REQUIRED) can't locate Qt on Windows without CMAKE_PREFIX_PATH / Qt6_DIR, so a bare `cmake -B build` aborts at configure. - vcvars64.bat was hardcoded to the Build Tools edition; Community/Pro/ Enterprise live under different paths. - Prereq said Qt 6.8+ while the source-build floor is 6.7. Add -G Ninja + a CMAKE_PREFIX_PATH example, note the edition-dependent vcvars path, and align the Qt floor to 6.7 (6.8.3 shipped). Keeps the useful bones of the original (vcvars -> setup-fftw.ps1 -> configure/build). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jensenpat
left a comment
There was a problem hiding this comment.
Approving — the fix is correct and it's the right long-term idiom. Verified against CMake's own source (Source/cmcmd.cxx, cmVSLink) plus the repo history; two findings worth putting on the record:
One correction to the root-cause attribution: it's the incremental link path, not cmake 4.x
vs_link_exe parses only /INCREMENTAL[:YES|NO] and /MANIFEST:NO from the link command — it does not recognize /MANIFEST:EMBED. What actually forks the behavior is the link mode:
- Incremental (Debug / RelWithDebInfo, whose default MSVC linker flags are
/debug /INCREMENTAL):vs_link_exeruns its rc/link/mt embed dance and expects link.exe to emit a side-car manifest. The hand-passed/MANIFEST:EMBEDmakes link.exe embed inline and emit no side-car, somt.exegets zero/manifestinputs plus/notify_update→c10100a7. This behaves identically on cmake 3.x — the code path is years old. - Non-incremental (Release,
/INCREMENTAL:NO):vs_link_exedelegates embedding to link.exe entirely and runs no mt step, so the hand-passed flags happen to work.
That's why CI never caught it despite already running CMake 4.3.4 on the windows-2025-vs2026 image: check-windows builds Release. You were simply the first person to do an incremental MSVC build since #3237 merged. (Bonus: pre-#3237, incremental builds on lenient toolsets likely shipped with no DPI manifest at all, since the lone /MANIFESTINPUT was ignored — this PR closes that hole too.)
The squash commit message will carry the corrected attribution so future archaeology on these six lines doesn't chase cmake versions.
This PR became release-blocking this morning
#3934 (merged Jul 1) switched windows-installer.yml — the Microsoft Store / release pipeline — from Release to RelWithDebInfo for PDB/.appxsym symbol packaging. That moves the release link onto the incremental path, so without this fix the next v* tag fails at link with exactly this c10100a7. No run of that workflow has executed since the switch; this PR needs to land first.
Verification story
- Reporter-confirmed on the incremental path (RelWithDebInfo, cmake 4.3.2, MSVC 14.44) ✔
check-windowsgreen on the non-incremental path (Release, cmake 4.3.4, MSVC 19.51) ✔ — and on that pathvs_link_exeitself appends/MANIFEST:EMBED,ID=1+/MANIFESTINPUT:<manifest>, i.e. exactly what #3237 hand-coded, now generated coherently. Release artifacts should carry a byte-equivalent embedded manifest.- No double-embed hazard:
AetherSDR.rcdeclares only the icon, noRT_MANIFEST. - Post-merge I'll dispatch
windows-installer.ymlon main to validate the full RelWithDebInfo Store path — thecheck-dpi-awareness.ps1step hard-gates the embed, and it exercises #3934's-RequirePdbplumbing in the same run.
Follow-up (not this PR): consider aligning check-windows to RelWithDebInfo so PR CI exercises the same link path the release pipeline ships.
Thanks @gauthig for the careful repro and bisect — exemplary first contribution.
#3961) ## Release documentation prep for **v26.7.1** (2026-07-02) 29 commits since v26.6.5. Docs-only + version bump — no code behavior change. ### Version bump 26.6.5 → 26.7.1 The three canonical locations (per `AGENTS.md`): - `CMakeLists.txt:2` — `project(AetherSDR VERSION 26.7.1)` → `AETHERSDR_VERSION` (the app's version string) - `README.md` — Current version line - `AGENTS.md` — Current version line ### `CHANGELOG.md` Promoted `[Unreleased]` → **`## [v26.7.1] — 2026-07-02`** in house style (v-prefix, em-dash, "N commits since…" opener + headline), authored from all merged PRs and categorized: - **Added:** 3D stacked-trace spectrum (#3899), 3D dBm scale (#3937), in-process NVIDIA BNR + AFX download-on-demand (#3902), TX meter mouse-over readouts (#3936), SWR manual sweep range (#3885), CW sidetone capture (#3895), KiwiSDR metadata scaffolding (#3898), bridge verbs (#3920) - **Changed:** BNR container/NIM backend removed, 60 fps + per-pixel GPU FFT trace (#3958), FlexLib-sourced model capabilities (#3954/#2177), RX speaker-latency cut (#3897), Display pane sections (#3935) - **Fixed:** #3922, #3926, #3941, #3940, #3942, #3921, #3903, #3892, #3924, #3891, #3890, #3900, #3947 - Fresh empty `[Unreleased]` restored above the release block. Internal/CI/docs/self-fix PRs (#3931/#3916/#3934/#3929) omitted per house style. ### `ROADMAP.md` - Cycle header → "post-v26.7.1" - NVIDIA BNR removed from **In flight** (shipped this cycle) - Five v26.7.1 highlights prepended to **Recently shipped** ### `README.md` - Highlights: GPU spectrum bullet now notes the **per-pixel FFT trace at up to 60 fps** and the **3D stacked-trace** spectrum mode ### Reviewer notes - Touches protected paths (`*.md` + `AGENTS.md` Tier-1 + `CMakeLists.txt`) — needs `@aethersdr/infrastructure` sign-off. - Tagging `v26.7.1` and cutting the release build are **not** part of this PR (docs prep only). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
vs_link_exewrapper already owns MSVC manifest embedding (link.exe emits a side-car.manifest, thenmt.exemerges/embeds it). Passing/MANIFEST:EMBED+/MANIFESTINPUTdirectly (added in fix(cmake): pair /MANIFESTINPUT with required /MANIFEST:EMBED #3237 to fixLNK1220) makes link.exe embed inline instead, so it emits no side-car manifest — CMake'smt.exestep then runs with an empty--manifestslist and fails withc10100a7on cmake 4.x..manifestfile as a target source so CMake feeds it to its ownvs_link_exe/mt.exeembed step natively, per the root-cause analysis in theaethersdr-agenttriage comment on the issue.README.md's "Building from Source" (the secondary ask in the issue), coveringvcvars64.bat→scripts/setup/setup-fftw.ps1→ configure/build.Test plan
c10100a7link failure on cmake 4.3.2 / MSVC 14.44 / VS 2022 BuildTools, applied this fix locally, and confirmed the link succeeds (per Principle XI — reporter-confirmed fix).build.ninja:LINK_FLAGSno longer carries/MANIFEST:EMBED//MANIFESTINPUT, andMANIFESTSnow correctly listspackaging/windows/AetherSDR.exe.manifestfor themt.exestep.build,check-paths,check-windows) green on this PR.Fixes #3835