From ebec02a8aa8619ca55c7d097ecd8f2dcf52ae64d Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 23 Oct 2026 10:18:49 +0300 Subject: [PATCH] windows: preserve external executable manifests (#31012) --- doc/windows_long_paths.md | 2 ++ vlib/v/driver/driver.v | 2 +- .../long_path_manifest_windows_test.c.v | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/doc/windows_long_paths.md b/doc/windows_long_paths.md index 6099cbca7c..35b368ce6d 100644 --- a/doc/windows_long_paths.md +++ b/doc/windows_long_paths.md @@ -12,6 +12,8 @@ such an executable can create, check and open files past `MAX_PATH`. * An executable that its linker already gave a manifest keeps that manifest unchanged. MinGW GCC links one that declares `longPathAware` already. +* If `.manifest` exists beside the final executable, V leaves that external manifest + in control. Include `longPathAware` there if the program also needs long paths. * Executables linked by MSVC get no manifest: they load `dbghelp.dll` at startup, and its initialization would hang on a long `TMP` (see below) before any V code runs. * Executables built with the FastC backend (`-b fastc`), shared libraries, and Windows diff --git a/vlib/v/driver/driver.v b/vlib/v/driver/driver.v index fcd6947768..7f3449556b 100644 --- a/vlib/v/driver/driver.v +++ b/vlib/v/driver/driver.v @@ -16892,7 +16892,7 @@ Please install the corresponding development package/libraries and make sure the // in a longPathAware process that loops forever on a TMP past MAX_PATH, // before any V code can shorten it, so they stay as the linker made them. if prefs.normalized_target_os() == 'windows' && !is_o && !is_shared - && !c_compiler_is_msvc(c_compiler) { + && !c_compiler_is_msvc(c_compiler) && !os.is_file('${bin_file}.manifest') { add_windows_long_path_manifest(staged_binary) or { // Long build paths need the manifest, so say so when it is missing for them. if verbose || show_cc || cc_dir_moved { diff --git a/vlib/v/driver/long_path_manifest_windows_test.c.v b/vlib/v/driver/long_path_manifest_windows_test.c.v index c11cee54a4..e552db0f35 100644 --- a/vlib/v/driver/long_path_manifest_windows_test.c.v +++ b/vlib/v/driver/long_path_manifest_windows_test.c.v @@ -66,3 +66,25 @@ fn test_v_builds_get_the_manifest() ! { assert os.read_file(exe)!.contains('longPathAware') assert cmdexec.run(exe, []).output.contains('Hello, World!') } + +fn test_side_by_side_manifest_at_final_output_is_kept() ! { + root := manifest_test_root('v3_external_manifest_build')! + defer { os.rmdir_all(root) or {} } + src := os.join_path(@VEXEROOT, 'examples', 'hello_world.v') + exe := os.join_path(root, 'hello_external.exe') + manifest := ' +' + + '' + + '' + + '' + os.write_file('${exe}.manifest', manifest)! + for flags in [[]string{}, ['-nocache']] { + res := cmdexec.run(@VEXE, ['-cc', 'tcc', ...flags, '-o', exe, src]) + assert res.exit_code == 0, res.output + assert !windows_executable_has_manifest(exe)! + assert os.read_file('${exe}.manifest')! == manifest + assert cmdexec.run(exe, []).output.contains('Hello, World!') + } +}