Files
v/doc/compiler-fallback.md
d9adadab74 compiler: report a truncated manual stdlib header before generating C (#30033)
* compiler: report a truncated manual stdlib header before generating C

A compiler built from an incomplete vlib/v/gen/c/manual_stdlib_c_headers.h
embeds a C preamble whose `#ifndef RAND_MAX` block loses its `#endif`. Every
default C build then fails inside the C compiler, and the module cache fails
with `failed to build cached module object`, with no pointer to the header.

Check the embedded header before any C is generated: it must end with a newline
and every conditional directive must be closed. On failure, print the problem
and how to fix it, clear the V3 failure marker so the parent process does not
replay the compile, and exit 1.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

* compiler: validate manual header directives only for programs using them

---------

Co-authored-by: Richard Wheeler <quaesitor.scientiam@gmail.com>
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Alexander Medvednikov <alexander@medvednikov.com>
2026-10-11 03:36:18 +03:00

6.7 KiB

Compiler fallback diagnostics

V automatically retries with the V 0.5.2 compatibility compiler only after a c_compilation_error failure. V errors (compiler_error), including parser and checker errors, and unsupported inline assembly (inline_asm) do not trigger a compatibility retry. They retain the original compiler's failure exit status, without locating, installing, or launching the compatibility compiler.

If a V executable embeds an incomplete vlib/v/gen/c/manual_stdlib_c_headers.h, builds that need its manual libc preamble report the damaged header before generating C and exit 1. The diagnostic appears once and does not trigger a compatibility retry. Restore the header with git restore vlib/v/gen/c/manual_stdlib_c_headers.h, then rebuild V with make. Headerless C output and -target-libc-headers builds do not use this embedded header.

Hard checker errors in dependency functions referenced by the selected source files, including callbacks, stored function values, and transitive calls, are reported at the dependency's source location before C generation. This also applies to standard-library and installed modules. Dependency warnings and notices remain limited to project-owned files.

Compiler builds report ordinary checker diagnostics before C generation, including v -check cmd/v. The compiler entry paths select self-build optimizations; naming an ordinary program v.v does not. Explicit -building-v builds still validate assignments, field access, and mutability.

For a C compiler failure, V prints the saved output when available, without compiling again, before retrying. It is labeled C compiler output from the default V compiler:. Internal arguments used to restart the default compiler are removed before launching the compatibility compiler, so a prior implicit TCC warning cannot cause an unknown-argument error. Option values and arguments passed to a program remain intact during this filtering.

Literal-output programs retain the array iteration helpers used by Linux backtrace formatting. For example, v -show-timings examples/hello_world.v builds without a missing array__get symbol.

If V diagnostics were deferred while a failure marker was armed, V replays only the default compiler with fallback disabled to display them. This diagnostic replay is not a compatibility retry and cannot turn the original failure into success. When saved C output is missing or empty, the same replay recovers the C diagnostic before the compatibility retry. Replayed output is labeled Compiler output from the default V compiler:. The replay uses -skip-running and VNORUN=1, so user programs and .vsh scripts are not executed even if compilation succeeds on the second attempt. Already-merged VFLAGS are not applied twice, and the replay's environment changes do not affect the parent or an actual C-error retry. If the replay produces no output, V reports that explicitly instead of silently omitting the diagnostic.

V diagnostics use the compatibility compiler's colors: errors are red, notices are yellow, and warnings and conflicting declarations are magenta. Source locations, severity labels, and underlines are bold; the highlighted source span uses the severity's color. Diagnostic replay preserves the parent terminal's color support even though it captures the compiler output through a pipe. Use -color or -nocolor to override detection, or VCOLORS=always / VCOLORS=never to set its default. Redirected diagnostics remain plain unless colors are explicitly enabled.

Diagnostic output does not depend on automatic bug reporting being enabled. For C errors, it is shown before locating or launching the fallback, even when that fallback succeeds. A successful C-error fallback still returns success, and unsuccessful retries retain their exit status. Diagnostics already shown are not replayed again if the fallback is unavailable.

Use v -new-compiler ... to disable the C-error compatibility fallback as well. An explicit v -old-compiler ... request still selects V 0.5.2 directly and does not have a failed default compilation to display.

When a compatibility compiler must be built, V searches PATH for make, then gmake. On Windows it also accepts MSYS2's mingw32-make. Install GNU make and ensure that MSYS2's make executable and sh are on PATH: the make v1 target uses POSIX shell recipes.

The -vls-mode compatibility protocol suppresses successful on-demand installation progress so the first response contains only the requested compiler output. Installation failures still include the installer's output and a failing exit status. Other commands retain installation progress.

If a build needs a missing bundled Boehm GC archive, V reports the missing library before invoking the C compiler. Reinstall V to restore the bundled libraries, or pass -d use_bundled_libgc to build GC from source. -gc none compiles without GC. Generating C or an object file does not require this archive. Missing system -lgc libraries retain the linker diagnostic and advice to install the development package.

On Linux amd64, V's TCC fence shim uses a private symbol so it can link alongside TCC's atomic runtime helpers. Boehm GC builds use the canonical GC header under TCC, avoiding a duplicate compatibility definition of GC_noop1_ptr. These builds can use TCC directly without a duplicate-symbol warning and a retry with cc.

The compatibility compiler cache uses V1_FALLBACK_CACHE_DIR when set, followed by XDG_CACHE_HOME/v/v1-fallback and HOME/.cache/v/v1-fallback. On Windows, when those variables are unset, it uses LOCALAPPDATA\v\v1-fallback, reusing the same cache across invocations. Looking up this path does not create directories. If none of these variables is set, V reserves a private cache under the temporary directory; on Windows, that last-resort cache has a fresh random name.

Implicit C compiler selection excludes TCC for -race, because TCC has no ThreadSanitizer runtime. Test build facts follow this rule on every host, including Windows, where race builds themselves are unsupported. Explicit compiler requests are checked separately.

User builds have a default memory safety limit of 10176 MiB. Set -memory-limit <size> (or --memory-limit <size>) before the source or subcommand to choose another limit. Unsuffixed values and M/m values use MiB; K/k use KiB and G/g use GiB. The value must be a nonnegative integer whose converted KiB value fits in a signed 64-bit integer. Missing, empty, malformed, negative, and overflowing values produce a CLI error. An explicit zero disables the limit, as does -no-memory-limit.

The Windows TCC backend supports -cstrict, including the startup code that sets the compiler's VEXE environment variable. Generated CRT calls retain explicit declarations and strict checks for implicit function declarations.