From beca086a88005cf571aa90172e666a8cd64a1536 Mon Sep 17 00:00:00 2001 From: Richard Wheeler Date: Wed, 24 Jun 2026 08:45:22 -0400 Subject: [PATCH] builtin: fix GetFinalPathNameByHandleW declaration for TCC on Windows (#27534) TCC''s bundled does not include , so GetFinalPathNameByHandleW had no C declaration in scope when TCC compiled any program that pulled in builtin (e.g. via os.real_path). TCC (in C99 mode) treats implicit function declarations as hard errors. Provide the declaration for TCC only, via a header that is #insert-ed under $if windows and guarded with `#ifdef __TINYC__`: - TCC: __TINYC__ is defined, so the extern is supplied. TCC''s own cannot be used instead because it pulls in , a header TCC does not ship. - GCC/MSVC: __TINYC__ is not defined, so the extern is skipped and the call resolves against the SDK header that pulls in transitively. Emitting a V-side extern here would conflict with the SDK''s `DWORD WINAPI` signature (DWORD is unsigned long, not u32). Gating in the C preprocessor (rather than a comptime `$if tinyc`) is deliberate: it keeps the guard intact under `-cross`, where V emits all declarations unconditionally. The same `#ifdef __TINYC__` idiom is already used for TCC/Windows in vlib/v/gen/c/cheaders.v. Verified on Windows: generated C wraps the extern in `#ifdef __TINYC__` for both normal and -cross GCC builds (gcc compiles both with no conflict), and `vlib/os/` tests pass (24/24) with GCC. Co-authored-by: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Co-authored-by: WOZCODE --- vlib/builtin/cfns.c.v | 8 +++++++- vlib/builtin/cfns_windows_tcc.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 vlib/builtin/cfns_windows_tcc.h diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index e879b0f9e..9fb8e5007 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -295,7 +295,13 @@ fn C.CreateFile(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurit fn C.CreateFileW(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurityAttributes &u16, dwCreationDisposition u32, dwFlagsAndAttributes u32, hTemplateFile voidptr) voidptr -fn C.GetFinalPathNameByHandleW(hFile voidptr, lpFilePath &u16, nSize u32, dwFlags u32) u32 +$if windows { + // The TCC-only declaration is guarded with `#ifdef __TINYC__` in the + // header, so it survives cross compilation; GCC/MSVC use the SDK header. + #insert "@VEXEROOT/vlib/builtin/cfns_windows_tcc.h" + + fn C.GetFinalPathNameByHandleW(hFile voidptr, lpFilePath &u16, nSize u32, dwFlags u32) u32 +} fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool diff --git a/vlib/builtin/cfns_windows_tcc.h b/vlib/builtin/cfns_windows_tcc.h new file mode 100644 index 000000000..c9ff05b50 --- /dev/null +++ b/vlib/builtin/cfns_windows_tcc.h @@ -0,0 +1,15 @@ +// TCC's bundled does not include , and TCC's own +// cannot be used either because it pulls in , a header +// TCC does not ship. As a result GetFinalPathNameByHandleW has no declaration +// in scope when TCC compiles code that uses it (e.g. os.real_path). +// +// Provide the declaration for TCC only. GCC/MSVC get it from the Windows SDK +// (via -> ); emitting a V-side extern there would +// conflict with the SDK's `DWORD WINAPI` signature, since DWORD is +// `unsigned long`, not `unsigned int`. +#ifdef __TINYC__ +#ifndef GetFinalPathNameByHandleW +extern unsigned int GetFinalPathNameByHandleW(void *hFile, unsigned short *lpFilePath, + unsigned int nSize, unsigned int dwFlags); +#endif +#endif -- 2.39.5