This issue is unique.
Your idea.
Building DesktopEditors on a current Windows toolchain: 14 findings
A local Windows build of DesktopEditors 9.3.1 failed at fourteen separate points between
third-party dependency setup and the finished installer. Each failure was traced to a root cause,
fixed, and the fix verified in isolation before continuing.
This document is written to be actionable: every entry names the file, the observed error, why it
happens, what was changed, and how the change was verified.
Scope
Sections A and C
are independent of any local modification. They are latent bugs that surface on any current MSVC,
Cygwin, Python or Inno Setup, and they reproduce with Boost still pinned at 1.78.
Section B is the cost of one deliberate local change:
boost/nc-build.py was modified to clone Boost without -b boost-1.78.0, so it picks up the latest
release (1.92) instead. If you keep Boost pinned, section B does not apply to you — but it is a
preview of what a future Boost bump will cost.
Line numbers refer to the state of the tree before the changes described here.
Build environment
| Component |
Version |
| Host |
Windows 11 Pro 26200 |
| Compiler |
Visual Studio 18 Community, MSVC 14.51.36231, _MSC_VER 1951, library tag vc145 |
| Windows SDK |
10.0.19041.0 |
| Generator |
Ninja + sccache, -std:c++17 |
| Cygwin |
64-bit, without the python3 package |
| Python |
3.14.7 (native, Microsoft Store build) |
| Inno Setup |
6.2.2, upgraded to 6.7.1 (see C2) |
| Boost |
tracking main (1.92) instead of the pinned boost-1.78.0 tag |
Findings index
| ID |
Failure |
Category |
| A1 |
cmd.exe 8191-char limit, line too long |
Toolchain |
| A2 |
link.exe is not a valid linker |
Toolchain |
| A3 |
/usr/bin/python3: No such file or directory |
Toolchain |
| A4 |
Filename too long, then uncommitted changes |
Toolchain |
| A5 |
gclient_paths.py: patch does not apply |
Toolchain |
| A6 |
C2653: 'stdext': is not a class or namespace |
Toolchain |
| A7 |
Unescaped special character in project-config.jam |
Toolchain |
| A8 |
(vc140, detected vc145), no suitable variant |
Toolchain |
| A9 |
MAX_PATH, cannot find the path specified |
Toolchain |
| B1 |
C1083: Cannot open include file: 'boost/variant.hpp' |
Boost 1.92 |
| B2 |
C2039: 'wpath' is not a member of 'boost::filesystem' |
Boost 1.92 |
| B3 |
LNK1104: cannot open libboost_regex-vc145-mt-x64-1_92.lib |
Boost 1.92 |
| C1 |
ArchitecturesAllowed is invalid |
Version pin |
| C2 |
WizardStyle is invalid |
Version pin |
Files changed
Twelve files. Paths are relative to the repository root.
| File |
Findings |
core/Common/3dParty/icu/nc-build.bat |
A1 |
core/Common/3dParty/icu-desktop/nc-build.bat |
A1 |
core/Common/3dParty/icu/nc-build-cygwin.sh |
A2, A3 |
core/Common/3dParty/icu-desktop/nc-build-cygwin.sh |
A2, A3 |
core/Common/3dParty/v8/nc-build.py |
A4, A5 |
core/Common/3dParty/cryptopp/integer.cpp |
A6 |
core/Common/3dParty/cryptopp/zdeflate.cpp |
A6 |
core/Common/3dParty/boost/nc-build.py |
A7, A8, B1 |
desktop-sdk/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp |
B2 |
core/common.cmake |
B3 |
desktop-apps/package/inno/common.iss |
A9, C1 |
build/windows/build.ps1 |
C2 |
The two icu / icu-desktop pairs received identical changes; icu-desktop is not reached by the
current desktop build but carries the same defects.
Section A. Toolchain drift
Independent of the Boost version. These break on any current MSVC, Cygwin or Inno Setup.
A1. vcvars is invoked twice and overflows the command line
Files: core/Common/3dParty/icu/nc-build.bat, core/Common/3dParty/icu-desktop/nc-build.bat
Symptom
-- Python script error: Aborting ICU: Cygwin build failed: Die eingegebene Zeile ist zu lang.
Syntaxfehler.
("The input line is too long. Syntax error.")
Cause
build/windows/build.ps1 already loads the complete MSVC environment into the process
(Import-VcVars), so VCINSTALLDIR, PATH, INCLUDE and LIB are inherited all the way down to
nc-build.bat. The batch then calls vcvars again, which prepends every MSVC and SDK directory
onto the already long PATH. The result exceeds cmd.exe's 8191-character command-line limit and the
batch dies before doing any work.
The file already reads VSCMD_ARG_TGT_ARCH, so it is aware the caller may have set up MSVC. It just
did not act on it.
Fix
Reuse the inherited environment when it is present:
if defined VCINSTALLDIR (
echo MSVC environment already active ^(VCINSTALLDIR set^) - reusing it, skipping vcvars.
REM Cygwin is already on the inherited PATH; append (not prepend) so MSVC's
REM link.exe still precedes Cygwin's /usr/bin/link.
set "PATH=%PATH%;%CYGWIN_BIN%"
) else (
REM Fresh shell: Cygwin first, then let vcvars prepend MSVC on top -> MSVC first.
set "PATH=%CYGWIN_BIN%;%PATH%"
call "%VCVARS%" || exit /b 1
)
Standalone use from a plain shell is unaffected: that branch still calls vcvars. Note the
deliberate asymmetry in PATH order, which matters for A2.
A2. Cygwin link shadows the MSVC linker
Files: core/Common/3dParty/icu/nc-build-cygwin.sh,
core/Common/3dParty/icu-desktop/nc-build-cygwin.sh
Symptom
configure: error: link.exe is not a valid linker. Your PATH is incorrect.
Please follow the directions in ICU's readme.
Cause
ICU's configure runs link --version and aborts if the output contains GNU coreutils. Cygwin
ships such a link in /usr/bin, and depending on the inherited PATH order it wins over MSVC's
link.exe — even though cl resolves correctly.
Measured on the failing machine:
> where link
C:\cygwin64\bin\link.exe
C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.51.36231\bin\Hostx64\x64\link.exe
> link --version
link (GNU coreutils) 9.0
Fix
Front-load the directory cl lives in, which also contains link.exe, right before
runConfigureICU:
msvc_bin=""
cl_path="$( command -v cl 2>/dev/null || true )"
if [ -n "$cl_path" ]; then
msvc_bin="$( dirname "$cl_path" )"
elif [ -n "$VCToolsInstallDir" ]; then
msvc_bin="$( cygpath -u "$VCToolsInstallDir" )/bin/Hostx64/x64"
fi
if [ -n "$msvc_bin" ] && [ -x "$msvc_bin/link.exe" ]; then
export PATH="$msvc_bin:$PATH"
fi
Verified
With Cygwin deliberately placed first in PATH, ICU's exact test
(link --version | grep 'GNU coreutils') matched before the change and no longer matches after it.
A3. PYTHON is hard coded to a path that need not exist
Files: core/Common/3dParty/icu/nc-build-cygwin.sh,
core/Common/3dParty/icu-desktop/nc-build-cygwin.sh
Symptom
checking for python3... /usr/bin/python3
...
Spawning Python to generate data/rules.mk...
./configure: line 9297: /usr/bin/python3: No such file or directory
configure: error: Python failed to run; see above error.
Cause
The script exported PYTHON=/usr/bin/python3 unconditionally. autoconf accepts a preset value
without testing it, which is why configure reported that it "found" python3 and only failed
when the interpreter was actually executed. On this machine Cygwin's python3 package was not
installed at all.
Fix
Detect instead of assume:
if [ -x /usr/bin/python3 ]; then
export PYTHON=/usr/bin/python3
elif command -v python3 >/dev/null 2>&1; then
export PYTHON="$( command -v python3 )"
elif command -v python >/dev/null 2>&1; then
export PYTHON="$( command -v python )"
else
echo "ERROR: no Python 3 found. Install Cygwin's python3, or ensure a native python3 is on PATH." >&2
exit 1
fi
Verified
Falling back to a native Windows Python is safe, because ICU's icutools.databuilder normalizes
path separators to / regardless of platform (python/icutools/databuilder/__main__.py, IO.glob).
Running the databuilder with native Python 3.14 produced exit code 0, a valid 28,840-line
rules.mk, and zero backslashes in the output.
A4. git needs long path support for the v8 dependency tree
File: core/Common/3dParty/v8/nc-build.py
Symptom
v8/buildtools/third_party/libc++/trunk (ERROR)
----------------------------------------
Error: 24>
24> ____ v8\buildtools\third_party\libc++\trunk at d9040c75cfea5928c804ab7c235fed06a63f743a
24> You have uncommitted changes.
24> cd into v8\buildtools\third_party\libc++\trunk, run git status to see changes,
24> and commit, stash, or reset.
Cause
Some v8 dependency paths exceed MAX_PATH — for example
buildtools/third_party/libc++/trunk/test/std/thread/... at 264 characters. git cannot write those
files, reports Filename too long, and the unwritten file then shows up as a local deletion, which
is what produces the misleading "uncommitted changes" abort.
The Windows-wide LongPathsEnabled registry flag does not cover this. git needs its own opt-in.
Fix
Set it for every git process, including the ones gclient spawns internally, which cannot be reached
with -c:
if nc.is_windows():
os.environ[ "GIT_CONFIG_COUNT" ] = "1"
os.environ[ "GIT_CONFIG_KEY_0" ] = "core.longpaths"
os.environ[ "GIT_CONFIG_VALUE_0" ] = "true"
GIT_CONFIG_COUNT / KEY / VALUE (git >= 2.31) outranks system and global config, so this needs
no change to the user's ~/.gitconfig — which on this machine did not exist, producing the harmless
Failed to read your global Git config warning from depot_tools.
Do not also set core.autocrlf=false
depot_tools recommends it and it looks harmless. It is not.
The v8 trees are checked out with CRLF, while the patches under tools/8.9/ are LF. git apply
only matches their context when git normalizes line endings, that is, with autocrlf=true (the
Git-for-Windows default). Forcing it to false makes every patch fail with
patch does not apply.
Measured on the same tree: git apply --check jinja2.patch succeeds with autocrlf=true and
fails with autocrlf=false. Only core.longpaths is needed here.
A5. The gclient paths patch no longer applies
File: core/Common/3dParty/v8/nc-build.py
(patch: core/Common/3dParty/v8/tools/8.9/x64-linux-dynamic/gclient_paths.patch)
Symptom
-- Python script error: Aborting V8: Applying patch: gclient_paths.patch failed:
error: patch failed: gclient_paths.py:20
error: gclient_paths.py: patch does not apply
Cause
depot_tools is cloned from main and then pulled, so it always tracks HEAD. The patch context no
longer matches:
|
Patch expects |
Current depot_tools |
| Quoting |
filename='.gclient' |
filename=".gclient" |
| Cached helpers |
4 |
5, _GetGClientConfigInner was added |
git apply is context-sensitive, so any upstream reformatting breaks it.
Fix
The patch's only effect was neutralizing @functools.lru_cache decorators. Expressing that intent
textually is formatting-independent, idempotent, and also covers helpers added later:
def disable_gclient_paths_cache():
target = depot_tools_path / "gclient_paths.py"
if not target.is_file():
print( "[WARNING] gclient_paths.py not found, skipping lru_cache removal!" )
return
lines = target.read_text( encoding = "utf-8" ).splitlines( keepends = True )
kept = [ l for l in lines
if not re.match( r"^\s*@functools\.lru_cache(\s*\(.*\))?\s*$", l ) ]
removed = len( lines ) - len( kept )
if removed:
target.write_text( "".join( kept ), encoding = "utf-8" )
print( f"Disabled { removed } @functools.lru_cache decorator(s) in gclient_paths.py" )
gclient_paths.patch was removed from the patches list and this function is called from
apply_patches() instead. Dropping a memoization decorator cannot change results, only speed.
Verified
Five decorators removed; a second run removes zero (idempotent); the file still compiles. The other
four patches (jinja2, buildgn, win_toolchain, vs_toolchain) were confirmed to still apply
with git apply --check and were left untouched.
Worth considering upstream: pin depot_tools to a known commit instead. That makes the build
reproducible, at the cost of possibly needing an older Python — note that create_fake_pipes_shim()
in the same file already works around pipes having been removed in Python 3.13.
A6. stdext iterator extensions were removed from the MSVC STL
Files: core/Common/3dParty/cryptopp/integer.cpp, core/Common/3dParty/cryptopp/zdeflate.cpp
Symptom
core\Common\3dParty\cryptopp\integer.cpp(3061): error C2653: 'stdext': is not a class or namespace
core\Common\3dParty\cryptopp\integer.cpp(3061): error C3861: 'make_checked_array_iterator': identifier not found
Cause
stdext::make_checked_array_iterator, stdext::unchecked_mismatch and
stdext::make_unchecked_array_iterator are Microsoft extensions that have been removed from the
MSVC STL. Not a single occurrence remains in the 14.51 headers.
cryptopp selects them through raw version comparisons, which can never be correct for a removal:
| Guard |
Value on this toolchain |
Result |
_MSC_VER |
1951 |
|
_STDEXT_BEGIN |
undefined |
the namespace is gone |
_MSC_VER >= 1500 (integer.cpp) |
true |
selects stdext, error |
_MSC_VER >= 1600 (zdeflate.cpp) |
true |
selects stdext, error |
Fix
Use the feature test the file already uses for its function-name selection — zdeflate.cpp:416
tests defined(_STDEXT_BEGIN):
// integer.cpp
#if (_MSC_VER >= 1500) && defined(_STDEXT_BEGIN)
// zdeflate.cpp
#if _MSC_VER >= 1600 && defined(_STDEXT_BEGIN)
_STDEXT_BEGIN is the macro the MSVC headers use to open that namespace, so this is correct in both
directions: older MSVC keeps the existing path, newer MSVC takes the portable one. The wrappers only
added debug-time bounds checking and warning suppression, so the fallback branches are semantically
equivalent.
Verified
Both files compile clean with the exact flags ninja used for CryptoPPLib. zdeflate.cpp would
have failed immediately after integer.cpp, so both were fixed together rather than one build cycle
apart.
A7. The generated jam file gets an unescaped Windows path
File: core/Common/3dParty/boost/nc-build.py
Symptom
project-config.jam:7: Unescaped special character in argument
C:Program FilesMicrosoft Visual Studio18CommunityVCToolsMSVC14.51.36231\binHostx64x64cl.exe
warning: Did not find command for MSVC toolset. If you have Visual Studio 2017 installed
you will need to specify the full path to the command...
Cause
The generated project-config.jam contained single backslashes inside a quoted string. Jam treats
\ as an escape character, so the path collapses and b2 silently falls back to whatever cl.exe
happens to be on PATH. The build only worked by accident.
The file already contains a jam_path() helper that doubles separators for exactly this purpose. It
was never called.
Fix
cl_path = jam_path(
Path( os.environ[ "VCToolsInstallDir" ] ) / "bin" / host_subdir / "cl.exe"
)
…used as using msvc : { msvc_version } : "{ cl_path }";. The path is built outside the f-string
because backslashes inside f-string expressions require Python >= 3.12.
Verified
Simulating jam's escape handling, the old form resolves to C:Program FilesMicrosoft... — exactly
matching the warning above — and the new form to the correct path.
A8. The MSVC toolset version is hard coded
File: core/Common/3dParty/boost/nc-build.py
Symptom
CMake Error: Found package configuration file:
.../boost/lib/cmake/boost_filesystem-1.92.0/boost_filesystem-config.cmake
but it set boost_filesystem_FOUND to FALSE so package "boost_filesystem" is
considered to be NOT FOUND. Reason given by package:
No suitable build variant has been found.
* libboost_filesystem-vc140-mt-x64-1_92.lib (vc140, detected vc145, set Boost_COMPILER to override)
Cause
project-config.jam declared using msvc : 14.0 while pointing at cl.exe from MSVC 14.51. Boost
derives the library name tag from that declaration — common.jam's toolset-tag joins major
and minor, so 14.0 becomes vc140 and 14.5 becomes vc145.
The libraries were therefore compiled by the correct compiler but named vc140, while CMake's
BoostConfig computes vc145 from the compiler it detects and rejects them.
This is independent of the Boost version: it breaks on any MSVC that is not 14.0.
Fix
Derive it from the toolchain actually in use. MSVC's tag keeps only the first digit of the minor
version:
def boost_msvc_toolset_version() -> str:
ver = os.environ.get( "VCToolsVersion", "" ) # e.g. 14.51.36231
parts = ver.split( "." )
if len( parts ) < 2 or not parts[ 0 ].isdigit() or not parts[ 1 ][ :1 ].isdigit():
nc.abort_op(
f"Cannot derive the MSVC toolset version from VCToolsVersion={ ver!r }. "
"Is the MSVC environment loaded (vcvars)?"
)
return f"{ parts[ 0 ] }.{ parts[ 1 ][ 0 ] }"
Verified
Across every MSVC generation:
VCToolsVersion |
Derived |
Tag |
Toolset |
| 14.51.36231 |
14.5 |
vc145 |
VS 18 |
| 14.44.35207 |
14.4 |
vc144 |
VS2022 17.10+ |
| 14.39.33519 |
14.3 |
vc143 |
VS2022 |
| 14.29.30133 |
14.2 |
vc142 |
VS2019 |
| 14.16.27023 |
14.1 |
vc141 |
VS2017 |
| 14.00.24210 |
14.0 |
vc140 |
VS2015 |
| (empty) |
— |
aborts with a clear message |
vcvars not loaded |
A9. The Inno source path overflows MAX_PATH
File: desktop-apps/package/inno/common.iss
Symptom
After successfully compressing roughly 3,600 files:
Compressing: C:\...\desktop-apps\package\inno\..\build\x64\desktop\converter\templates\RU\Forms\[32]2CP5...===.pdf
Error in C:\...\desktop-apps\package\inno\common.iss: Das System kann den angegebenen Pfad nicht finden.
("The system cannot find the path specified.")
Cause
iscc runs with inno\ as its working directory — make_inno.ps1 does Push-Location "inno" —
and BUILD_DIR was relative:
#define BUILD_DIR '..\build\' + ARCH
The resolved path therefore contains the detour package\inno\..\build\..., which is eight extra
characters. The longest staged file, a base32-named template, is 256 characters canonically; with the
detour it is 264, past MAX_PATH (260).
Confirmed at the Win32 layer: GetFileAttributes returns err=0 on the canonical path and err=3
(ERROR_PATH_NOT_FOUND) on the detour path, which is exactly the message above.
Fix
Build it absolute and already normalized:
#define BUILD_DIR ExtractFileDir(ExtractFileDir(SourcePath)) + '\build\' + ARCH
ExtractFileDir is applied twice because ISPP's SourcePath carries a trailing backslash, so one
call only strips that (verified with a probe script). The #ifndef BUILD_DIR guard is kept, so an
external /DBUILD_DIR=... still wins.
Verified
Measured over the whole staging tree: 3,636 files, longest canonical path 256 characters. With the
detour exactly one file exceeds the limit; without it, none.
Only four characters of headroom remain. A deeper checkout path will break this again. If you
want this robust rather than merely working, either shorten the staging layout or move to
long-path-aware packaging.
Section B. Fallout from unpinning Boost
These appear only because Boost is no longer pinned to boost-1.78.0. Boost 1.92 is fourteen
releases newer and has removed a lot of v2-era API in between.
B1. Four Boost submodules are no longer pulled in transitively
File: core/Common/3dParty/boost/nc-build.py
Symptom
third_party\install\apple\libetonyek\src\lib\IWORKTypes.h(20): fatal error C1083:
Cannot open include file: 'boost/variant.hpp': No such file or directory
Cause
The script checks out only a subset of Boost submodules; everything else has to arrive as a
boostdep-resolved dependency of one of them. Boost has been migrating away from Boost.Variant
towards std::variant, so on 1.92 these four are no longer dragged in:
| Module |
Needed by |
variant |
libetonyek (IWORKTypes.h) |
spirit |
librevenge (RVNGPropertyList.cpp), OFDFile |
ptr_container |
libetonyek |
serialization |
librevenge, the base64 iterators under boost/archive/ |
Easy to get wrong: boost/archive/** ships in the serialization module. There is no Boost
module called archive (confirmed against .gitmodules). Those base64 iterators are pure
templates, so headers alone are enough and serialization does not have to be built.
Fix
header_only_modules_needed = [ "any", "asio", "beast", "foreach", "format", "functional",
"multi_index", "ptr_container", "serialization", "spirit",
"uuid", "variant" ]
Verified
Rather than discovering one missing header per build cycle, all 75 distinct
#include <boost/...> paths in the compiled sources were cross-checked against the install tree.
Exactly 16 headers were missing, and all 16 map to those four modules.
B2. boost filesystem wpath no longer exists
File: desktop-sdk/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp
Symptom
client_renderer_wrapper.cpp(2001): error C2039: 'wpath' is not a member of 'boost::filesystem'
client_renderer_wrapper.cpp(2001): error C2065: 'wpath': undeclared identifier
client_renderer_wrapper.cpp(2001): error C2146: syntax error: missing ';' before identifier 'current_path'
Cause
wpath is Boost.Filesystem v2 and has been removed. In v3, boost::filesystem::path is already
wide on Windows: its value_type is wchar_t.
Fix
wpath becomes path at all six occurrences, lines 2001-2004 and 4430-4433:
boost::filesystem::path current_path = m_sLocalFileSrc;
boost::filesystem::path request_path = sRequestPath;
boost::filesystem::path relativePath = boost::filesystem::relative(request_path, current_path.parent_path());
The surrounding code passes std::wstring in and calls .wstring() on the result; both remain
valid, so this is a drop-in replacement. A project-wide search found no other uses of wpath.
Verified
The file compiles clean with the exact flags ninja used for ascdocumentscore.
B3. Header only Boost regex still triggers auto linking
File: core/common.cmake
Symptom
While linking x2tlib:
LINK : fatal error LNK1104: Datei "libboost_regex-vc145-mt-x64-1_92.lib" kann nicht geöffnet werden.
…although that file exists in third_party/install/boost/lib.
Cause
Boost.Regex is header-only since Boost 1.77, so Boost::regex is now an INTERFACE imported
target. The compiled artifact survives only as the legacy Boost::regex_old.
For compiled components, Boost's own CMake config sets BOOST_<LIB>_NO_LIB as an interface
compile definition. That is where -DBOOST_FILESYSTEM_NO_LIB and friends on the compiler command
line come from, and it switches off the auto-link #pragma in the headers because CMake passes the
.lib path itself.
A header-only target gets neither that define nor a library directory, yet
boost/regex/v5/cregex.hpp:29 still emits the pragma. On Boost 1.78, regex was a compiled
component, so the define came for free and this never surfaced.
Fix
Restore what Boost's own CMake used to do, right after find_package:
find_package( Boost REQUIRED COMPONENTS system filesystem regex date_time )
add_definitions(-DBOOST_REGEX_NO_LIB)
Verified
Reproduced in isolation, with no library directory on the link line:
| Translation unit |
Result |
#include <boost/regex.hpp>, no define |
links fine, does not trigger auto-link |
#include <boost/cregex.hpp>, no define |
Linking to lib file: libboost_regex-vc145-mt-x64-1_92.lib then LNK1104 |
#include <boost/cregex.hpp>, -DBOOST_REGEX_NO_LIB |
links clean |
A runtime check confirmed regex works fully header-only (regex_search matched as expected), so no
library is needed at all.
Section C. Version pins in the build scripts
C1. ArchitecturesAllowed uses the wrong version threshold
File: desktop-apps/package/inno/common.iss
Symptom
Error on line 83 in ...\common.iss: Value of [Setup] section directive "ArchitecturesAllowed" is invalid.
Compile aborted.
Cause
The gate assumed the x64compatible identifier exists from Inno Setup 6.0. It was introduced in
6.3. Every compiler from 6.0 to 6.2.x therefore takes the second branch and emits a value it does
not know.
Fix
#if Ver < EncodeVer(6,3,0) & ARCH == "x64"
ArchitecturesAllowed = x64
ArchitecturesInstallIn64BitMode = x64
#elif Ver >= EncodeVer(6,3,0) & ARCH == "x64"
ArchitecturesAllowed = x64compatible
ArchitecturesInstallIn64BitMode = x64compatible
#elif ARCH == "arm64"
...
| Inno version |
Value |
|
| < 6.0 |
x64 |
unchanged |
| 6.0 - 6.2.x |
x64 |
was broken, now correct |
| >= 6.3 |
x64compatible |
unchanged |
Verified
On Inno 6.2.2 the corrected gate takes the pre-6.3 branch and compiles successfully.
This fix is moot if you require Inno >= 6.3 (see
C2), but it costs nothing and makes the
script correct on its own terms.
C2. The Inno Setup version pin contradicts the scripts
File: build/windows/build.ps1
Symptom
Error on line 104 in ...\common.iss: Value of [Setup] section directive "WizardStyle" is invalid.
Compile aborted.
Cause
common.iss uses three directives that require Inno Setup 6.3 or newer, and the matching assets
are already in the repository — seven sizes each of WizImage-Dark-*.png and
WizSmallImage-Dark-*.png:
| Line |
Directive |
Since |
| 104 |
WizardStyle=classic dynamic |
6.3 |
| 107 |
WizardImageFileDynamicDark |
6.3 |
| 109 |
WizardSmallImageFileDynamicDark |
6.3 |
build.ps1 installed 6.2.2. The same file pins the unofficial language files to is-6_7_1, with
the comment "Pin $issTag to the tag matching your Inno version". The two pins contradict each
other:
$issTag = 'is-6_7_1' # line 190
choco install innosetup --version=6.2.2 -y --no-progress # line 280
Fix
choco install innosetup --version=6.7.1 -y --no-progress
Verified available on Chocolatey; the resulting compiler reports Inno Setup 6.7.1 and accepts all
three directives. Sync-InnoLanguages re-stages the language files on every packaging build, so
compiler and translations end up consistent automatically.
The alternative — gating the three directives behind #if Ver >= EncodeVer(6,3,0) — was rejected
because it would silently drop dark-mode wizard artwork that is already shipped in the repository.
Recommendations
-
Sections A and C are worth taking upstream as-is. They are latent bugs that surface on any
current MSVC, Cygwin, Python or Inno Setup, independent of the Boost question.
-
Two build scripts hard-code a value where they should detect one:
A3 (PYTHON) and
A8 (the MSVC toolset). Both now derive it from the
environment. That pattern is worth applying to similar spots.
-
Two guards use a version comparison where a feature test is correct:
A6 (stdext) and, in a different
form, C1. A version comparison cannot
express "this API was removed" — only a feature test can.
-
Decide explicitly whether Boost stays pinned. Section B is the full cost of unpinning it at
1.92. If you do unpin, note that the module list in boost/nc-build.py becomes load-bearing:
every Boost header the project includes must be reachable from it, and Boost keeps shrinking the
transitive closure with each release.
-
The Inno path budget is nearly exhausted
(A9, four characters spare). Worth addressing
before the staging layout grows.
How these fixes were verified
Each fix was checked on its own rather than by re-running the full build and hoping, using whichever
of these applied:
- compiling the affected translation unit with the exact flags ninja used for its target
(A6,
B2);
- reproducing the failure with and without the change in a minimal test case
(B3,
C1);
- measuring the underlying condition directly —
GetFileAttributes error codes
(A9), link --version output
(A2), path-length statistics over the whole staging tree
(A9);
- checking the derived value against every input it must handle
(A8, six MSVC generations plus the empty case);
- enumerating the full problem space instead of one instance
(B1, all 75 Boost includes
cross-checked against the install tree; git apply --check run against all remaining v8 patches).
This issue is unique.
Your idea.
Building DesktopEditors on a current Windows toolchain: 14 findings
A local Windows build of DesktopEditors 9.3.1 failed at fourteen separate points between
third-party dependency setup and the finished installer. Each failure was traced to a root cause,
fixed, and the fix verified in isolation before continuing.
This document is written to be actionable: every entry names the file, the observed error, why it
happens, what was changed, and how the change was verified.
Scope
Sections A and C
are independent of any local modification. They are latent bugs that surface on any current MSVC,
Cygwin, Python or Inno Setup, and they reproduce with Boost still pinned at 1.78.
Section B is the cost of one deliberate local change:
boost/nc-build.pywas modified to clone Boost without-b boost-1.78.0, so it picks up the latestrelease (1.92) instead. If you keep Boost pinned, section B does not apply to you — but it is a
preview of what a future Boost bump will cost.
Line numbers refer to the state of the tree before the changes described here.
Build environment
_MSC_VER 1951, library tagvc145-std:c++17python3packagemain(1.92) instead of the pinnedboost-1.78.0tagFindings index
link.exe is not a valid linker/usr/bin/python3: No such file or directoryFilename too long, then uncommitted changesgclient_paths.py: patch does not applyC2653: 'stdext': is not a class or namespaceUnescaped special characterin project-config.jam(vc140, detected vc145), no suitable variantC1083: Cannot open include file: 'boost/variant.hpp'C2039: 'wpath' is not a member of 'boost::filesystem'LNK1104: cannot open libboost_regex-vc145-mt-x64-1_92.libArchitecturesAllowedis invalidWizardStyleis invalidFiles changed
Twelve files. Paths are relative to the repository root.
core/Common/3dParty/icu/nc-build.batcore/Common/3dParty/icu-desktop/nc-build.batcore/Common/3dParty/icu/nc-build-cygwin.shcore/Common/3dParty/icu-desktop/nc-build-cygwin.shcore/Common/3dParty/v8/nc-build.pycore/Common/3dParty/cryptopp/integer.cppcore/Common/3dParty/cryptopp/zdeflate.cppcore/Common/3dParty/boost/nc-build.pydesktop-sdk/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cppcore/common.cmakedesktop-apps/package/inno/common.issbuild/windows/build.ps1The two
icu/icu-desktoppairs received identical changes;icu-desktopis not reached by thecurrent desktop build but carries the same defects.
Section A. Toolchain drift
Independent of the Boost version. These break on any current MSVC, Cygwin or Inno Setup.
A1. vcvars is invoked twice and overflows the command line
Files:
core/Common/3dParty/icu/nc-build.bat,core/Common/3dParty/icu-desktop/nc-build.batSymptom
("The input line is too long. Syntax error.")
Cause
build/windows/build.ps1already loads the complete MSVC environment into the process(
Import-VcVars), soVCINSTALLDIR,PATH,INCLUDEandLIBare inherited all the way down tonc-build.bat. The batch then callsvcvarsagain, which prepends every MSVC and SDK directoryonto the already long
PATH. The result exceeds cmd.exe's 8191-character command-line limit and thebatch dies before doing any work.
The file already reads
VSCMD_ARG_TGT_ARCH, so it is aware the caller may have set up MSVC. It justdid not act on it.
Fix
Reuse the inherited environment when it is present:
Standalone use from a plain shell is unaffected: that branch still calls
vcvars. Note thedeliberate asymmetry in
PATHorder, which matters for A2.A2. Cygwin link shadows the MSVC linker
Files:
core/Common/3dParty/icu/nc-build-cygwin.sh,core/Common/3dParty/icu-desktop/nc-build-cygwin.shSymptom
Cause
ICU's
configurerunslink --versionand aborts if the output containsGNU coreutils. Cygwinships such a
linkin/usr/bin, and depending on the inheritedPATHorder it wins over MSVC'slink.exe— even thoughclresolves correctly.Measured on the failing machine:
Fix
Front-load the directory
cllives in, which also containslink.exe, right beforerunConfigureICU:Verified
With Cygwin deliberately placed first in
PATH, ICU's exact test(
link --version | grep 'GNU coreutils') matched before the change and no longer matches after it.A3. PYTHON is hard coded to a path that need not exist
Files:
core/Common/3dParty/icu/nc-build-cygwin.sh,core/Common/3dParty/icu-desktop/nc-build-cygwin.shSymptom
Cause
The script exported
PYTHON=/usr/bin/python3unconditionally. autoconf accepts a preset valuewithout testing it, which is why
configurereported that it "found" python3 and only failedwhen the interpreter was actually executed. On this machine Cygwin's
python3package was notinstalled at all.
Fix
Detect instead of assume:
Verified
Falling back to a native Windows Python is safe, because ICU's
icutools.databuildernormalizespath separators to
/regardless of platform (python/icutools/databuilder/__main__.py,IO.glob).Running the databuilder with native Python 3.14 produced exit code 0, a valid 28,840-line
rules.mk, and zero backslashes in the output.A4. git needs long path support for the v8 dependency tree
File:
core/Common/3dParty/v8/nc-build.pySymptom
Cause
Some v8 dependency paths exceed
MAX_PATH— for examplebuildtools/third_party/libc++/trunk/test/std/thread/...at 264 characters. git cannot write thosefiles, reports
Filename too long, and the unwritten file then shows up as a local deletion, whichis what produces the misleading "uncommitted changes" abort.
The Windows-wide
LongPathsEnabledregistry flag does not cover this. git needs its own opt-in.Fix
Set it for every git process, including the ones gclient spawns internally, which cannot be reached
with
-c:GIT_CONFIG_COUNT/KEY/VALUE(git >= 2.31) outranks system and global config, so this needsno change to the user's
~/.gitconfig— which on this machine did not exist, producing the harmlessFailed to read your global Git configwarning from depot_tools.A5. The gclient paths patch no longer applies
File:
core/Common/3dParty/v8/nc-build.py(patch:
core/Common/3dParty/v8/tools/8.9/x64-linux-dynamic/gclient_paths.patch)Symptom
Cause
depot_tools is cloned from
mainand then pulled, so it always tracks HEAD. The patch context nolonger matches:
filename='.gclient'filename=".gclient"_GetGClientConfigInnerwas addedgit applyis context-sensitive, so any upstream reformatting breaks it.Fix
The patch's only effect was neutralizing
@functools.lru_cachedecorators. Expressing that intenttextually is formatting-independent, idempotent, and also covers helpers added later:
gclient_paths.patchwas removed from thepatcheslist and this function is called fromapply_patches()instead. Dropping a memoization decorator cannot change results, only speed.Verified
Five decorators removed; a second run removes zero (idempotent); the file still compiles. The other
four patches (
jinja2,buildgn,win_toolchain,vs_toolchain) were confirmed to still applywith
git apply --checkand were left untouched.A6. stdext iterator extensions were removed from the MSVC STL
Files:
core/Common/3dParty/cryptopp/integer.cpp,core/Common/3dParty/cryptopp/zdeflate.cppSymptom
Cause
stdext::make_checked_array_iterator,stdext::unchecked_mismatchandstdext::make_unchecked_array_iteratorare Microsoft extensions that have been removed from theMSVC STL. Not a single occurrence remains in the 14.51 headers.
cryptopp selects them through raw version comparisons, which can never be correct for a removal:
_MSC_VER_STDEXT_BEGIN_MSC_VER >= 1500(integer.cpp)stdext, error_MSC_VER >= 1600(zdeflate.cpp)stdext, errorFix
Use the feature test the file already uses for its function-name selection —
zdeflate.cpp:416tests
defined(_STDEXT_BEGIN):_STDEXT_BEGINis the macro the MSVC headers use to open that namespace, so this is correct in bothdirections: older MSVC keeps the existing path, newer MSVC takes the portable one. The wrappers only
added debug-time bounds checking and warning suppression, so the fallback branches are semantically
equivalent.
Verified
Both files compile clean with the exact flags ninja used for
CryptoPPLib.zdeflate.cppwouldhave failed immediately after
integer.cpp, so both were fixed together rather than one build cycleapart.
A7. The generated jam file gets an unescaped Windows path
File:
core/Common/3dParty/boost/nc-build.pySymptom
Cause
The generated
project-config.jamcontained single backslashes inside a quoted string. Jam treats\as an escape character, so the path collapses and b2 silently falls back to whatevercl.exehappens to be on
PATH. The build only worked by accident.The file already contains a
jam_path()helper that doubles separators for exactly this purpose. Itwas never called.
Fix
…used as
using msvc : { msvc_version } : "{ cl_path }";. The path is built outside the f-stringbecause backslashes inside f-string expressions require Python >= 3.12.
Verified
Simulating jam's escape handling, the old form resolves to
C:Program FilesMicrosoft...— exactlymatching the warning above — and the new form to the correct path.
A8. The MSVC toolset version is hard coded
File:
core/Common/3dParty/boost/nc-build.pySymptom
Cause
project-config.jamdeclaredusing msvc : 14.0while pointing atcl.exefrom MSVC 14.51. Boostderives the library name tag from that declaration —
common.jam'stoolset-tagjoins majorand minor, so
14.0becomesvc140and14.5becomesvc145.The libraries were therefore compiled by the correct compiler but named
vc140, while CMake'sBoostConfigcomputesvc145from the compiler it detects and rejects them.This is independent of the Boost version: it breaks on any MSVC that is not 14.0.
Fix
Derive it from the toolchain actually in use. MSVC's tag keeps only the first digit of the minor
version:
Verified
Across every MSVC generation:
VCToolsVersionvc145vc144vc143vc142vc141vc140A9. The Inno source path overflows MAX_PATH
File:
desktop-apps/package/inno/common.issSymptom
After successfully compressing roughly 3,600 files:
("The system cannot find the path specified.")
Cause
isccruns withinno\as its working directory —make_inno.ps1doesPush-Location "inno"—and
BUILD_DIRwas relative:The resolved path therefore contains the detour
package\inno\..\build\..., which is eight extracharacters. The longest staged file, a base32-named template, is 256 characters canonically; with the
detour it is 264, past
MAX_PATH(260).Confirmed at the Win32 layer:
GetFileAttributesreturnserr=0on the canonical path anderr=3(
ERROR_PATH_NOT_FOUND) on the detour path, which is exactly the message above.Fix
Build it absolute and already normalized:
ExtractFileDiris applied twice because ISPP'sSourcePathcarries a trailing backslash, so onecall only strips that (verified with a probe script). The
#ifndef BUILD_DIRguard is kept, so anexternal
/DBUILD_DIR=...still wins.Verified
Measured over the whole staging tree: 3,636 files, longest canonical path 256 characters. With the
detour exactly one file exceeds the limit; without it, none.
Section B. Fallout from unpinning Boost
These appear only because Boost is no longer pinned to
boost-1.78.0. Boost 1.92 is fourteenreleases newer and has removed a lot of v2-era API in between.
B1. Four Boost submodules are no longer pulled in transitively
File:
core/Common/3dParty/boost/nc-build.pySymptom
Cause
The script checks out only a subset of Boost submodules; everything else has to arrive as a
boostdep-resolved dependency of one of them. Boost has been migrating away from Boost.Varianttowards
std::variant, so on 1.92 these four are no longer dragged in:variantIWORKTypes.h)spiritRVNGPropertyList.cpp), OFDFileptr_containerserializationboost/archive/Fix
Verified
Rather than discovering one missing header per build cycle, all 75 distinct
#include <boost/...>paths in the compiled sources were cross-checked against the install tree.Exactly 16 headers were missing, and all 16 map to those four modules.
B2. boost filesystem wpath no longer exists
File:
desktop-sdk/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cppSymptom
Cause
wpathis Boost.Filesystem v2 and has been removed. In v3,boost::filesystem::pathis alreadywide on Windows: its
value_typeiswchar_t.Fix
wpathbecomespathat all six occurrences, lines 2001-2004 and 4430-4433:boost::filesystem::path current_path = m_sLocalFileSrc; boost::filesystem::path request_path = sRequestPath; boost::filesystem::path relativePath = boost::filesystem::relative(request_path, current_path.parent_path());The surrounding code passes
std::wstringin and calls.wstring()on the result; both remainvalid, so this is a drop-in replacement. A project-wide search found no other uses of
wpath.Verified
The file compiles clean with the exact flags ninja used for
ascdocumentscore.B3. Header only Boost regex still triggers auto linking
File:
core/common.cmakeSymptom
While linking
x2tlib:…although that file exists in
third_party/install/boost/lib.Cause
Boost.Regex is header-only since Boost 1.77, so
Boost::regexis now anINTERFACEimportedtarget. The compiled artifact survives only as the legacy
Boost::regex_old.For compiled components, Boost's own CMake config sets
BOOST_<LIB>_NO_LIBas an interfacecompile definition. That is where
-DBOOST_FILESYSTEM_NO_LIBand friends on the compiler commandline come from, and it switches off the auto-link
#pragmain the headers because CMake passes the.libpath itself.A header-only target gets neither that define nor a library directory, yet
boost/regex/v5/cregex.hpp:29still emits the pragma. On Boost 1.78, regex was a compiledcomponent, so the define came for free and this never surfaced.
Fix
Restore what Boost's own CMake used to do, right after
find_package:Verified
Reproduced in isolation, with no library directory on the link line:
#include <boost/regex.hpp>, no define#include <boost/cregex.hpp>, no defineLinking to lib file: libboost_regex-vc145-mt-x64-1_92.libthen LNK1104#include <boost/cregex.hpp>,-DBOOST_REGEX_NO_LIBA runtime check confirmed regex works fully header-only (
regex_searchmatched as expected), so nolibrary is needed at all.
Section C. Version pins in the build scripts
C1. ArchitecturesAllowed uses the wrong version threshold
File:
desktop-apps/package/inno/common.issSymptom
Cause
The gate assumed the
x64compatibleidentifier exists from Inno Setup 6.0. It was introduced in6.3. Every compiler from 6.0 to 6.2.x therefore takes the second branch and emits a value it does
not know.
Fix
x64x64x64compatibleVerified
On Inno 6.2.2 the corrected gate takes the pre-6.3 branch and compiles successfully.
This fix is moot if you require Inno >= 6.3 (see
C2), but it costs nothing and makes the
script correct on its own terms.
C2. The Inno Setup version pin contradicts the scripts
File:
build/windows/build.ps1Symptom
Cause
common.issuses three directives that require Inno Setup 6.3 or newer, and the matching assetsare already in the repository — seven sizes each of
WizImage-Dark-*.pngandWizSmallImage-Dark-*.png:WizardStyle=classic dynamicWizardImageFileDynamicDarkWizardSmallImageFileDynamicDarkbuild.ps1installed 6.2.2. The same file pins the unofficial language files tois-6_7_1, withthe comment "Pin
$issTagto the tag matching your Inno version". The two pins contradict eachother:
Fix
Verified available on Chocolatey; the resulting compiler reports
Inno Setup 6.7.1and accepts allthree directives.
Sync-InnoLanguagesre-stages the language files on every packaging build, socompiler and translations end up consistent automatically.
The alternative — gating the three directives behind
#if Ver >= EncodeVer(6,3,0)— was rejectedbecause it would silently drop dark-mode wizard artwork that is already shipped in the repository.
Recommendations
Sections A and C are worth taking upstream as-is. They are latent bugs that surface on any
current MSVC, Cygwin, Python or Inno Setup, independent of the Boost question.
Two build scripts hard-code a value where they should detect one:
A3 (
PYTHON) andA8 (the MSVC toolset). Both now derive it from the
environment. That pattern is worth applying to similar spots.
Two guards use a version comparison where a feature test is correct:
A6 (
stdext) and, in a differentform, C1. A version comparison cannot
express "this API was removed" — only a feature test can.
Decide explicitly whether Boost stays pinned. Section B is the full cost of unpinning it at
1.92. If you do unpin, note that the module list in
boost/nc-build.pybecomes load-bearing:every Boost header the project includes must be reachable from it, and Boost keeps shrinking the
transitive closure with each release.
The Inno path budget is nearly exhausted
(A9, four characters spare). Worth addressing
before the staging layout grows.
How these fixes were verified
Each fix was checked on its own rather than by re-running the full build and hoping, using whichever
of these applied:
(A6,
B2);
(B3,
C1);
GetFileAttributeserror codes(A9),
link --versionoutput(A2), path-length statistics over the whole staging tree
(A9);
(A8, six MSVC generations plus the empty case);
(B1, all 75 Boost includes
cross-checked against the install tree;
git apply --checkrun against all remaining v8 patches).