vwindowstoolchain
Installing V on Windows, and the failure that looks like a compiler bug
Getting V working on Windows in under five minutes, plus the version mismatch between v.exe and vlib that produces errors that read like a broken compiler.
V is unusually easy to install. One zip, one directory, no installer, no
registry, no runtime to install separately. That is also the problem: nothing
checks that what you downloaded is internally consistent, so a stale checkout
gives you error messages that blame the compiler.This is the short version, followed by the failure I hit, because the failure is
the part worth reading.The installGrab a release zip, not the source repository:
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest `
-Uri "https://github.com/vlang/v/releases/download/0.5.2/v_windows.zip" `
-OutFile "$env:TEMP\v.zip"
Expand-Archive "$env:TEMP\v.zip" -DestinationPath "$env:LOCALAPPDATA\Programs\v" -Force
Unzipping the release gives you v.exe and a vlib directory, and those two
have to come from the same release. Keep them together:%LOCALAPPDATA%\Programs\v\
v.exe
vlib\
os.v ... (10,690 files)
Then put that directory on PATH. No VROOT is needed for the release build —
it knows where it lives — which is one of the reasons it is less trouble than the
git checkout.Confirming it worksv version is not a sufficient check. A mismatched installation will report a
perfectly plausible version and still be broken. This is the check that
matters:@'
module main
import "time"
fn main() {
println("now -> " + time.now().format_ss_micro())
}
'@ | Set-Content t.v
v run t.v
now -> 2026-09-30 17:10:17.925000
An import of a standard-library module is the part that has to work. A v
hello.v with no imports compiles fine on a broken install, which is exactly why
v version is not enough.Two API details that cost me a few minutesBoth of these are my own mistakes, but they are the kind of thing you hit in the
first ten minutes, so they are worth writing down.exit is a builtin, not a member of os:fn main() {
exit(0) // correct
os.exit(0) // error: unknown function: os.exit
}
String helpers are methods on the type, not functions in a module:parts := "a,b,c".split(",") // correct
parts := strings.split(s, ",") // there is no strings.split
println(parts.join(","))
println("mahdi".to_upper())
println(" x ".trim_space())
The second one surprised me specifically because Go trains you to look in
strings. V's strings module has five public functions. String manipulation
lives on the type:println("a-b-c".replace("-", "/"))
println("x".repeat(3))
v fmt will rewrite your code, and it is not idempotentv fmt reformats aggressively, which is the point — it removes formatting as
something to argue about. It also rewrote a single-line struct into five lines
and dropped the quotes from import "strings" to import strings.The part worth knowing: running it twice gives a different result than running
it once, and v fmt -verify fails on a file it just formatted:fmt.v is not vfmt'ed
> Encountered a total of: 1 formatting errors.
So you cannot put v fmt -verify in CI the way you would gofmt -l. If you want
formatting enforced, the check has to be "run v fmt -w and fail if git reports
a change", which is a different thing and more awkward than it should be. I would
want that fixed before putting V in a repository with other people in it.The failure: v.exe newer than vlibHere is the installation that broke, and the errors it produced.The checkout had been on master and someone had run v self, which rebuilt
v.exe from a much newer commit than the vlib it was left next to. v self
had even left a backup behind, named for the version that used to work:v.exe.bak-0.5.2-c9b806b
Two different errors came out of that state, and neither mentions a version.Programs without imports compiled. Anything importing the standard library
failed to build:main.v:2:1: builder error: cannot import module ""time"" (not found)
That reads like a missing file, and the file was not missing —
vlib/time/chrono.v was right there with module time on line 5. Setting
VROOT did not help.Swapping in a different build made it worse, in the opposite direction:C:/Users/xman/v/vlib/builtin/int.v:202:12: error: unknown type `u128`
Now vlib was too new. The compiler does not know about a 128-bit integer that
the standard library uses.The actual rule, which I had to work out from two broken states:v.exe agevlib ageResultsamesameworksneweroldercannot import module "os" (not found)oldernewerunknown type 'u128'The error names a module or a type, never a version. There is nothing in the
output that says "these two files are from different days".What to do about itUnzip the release again, over the top. Do not try to fix a git checkout with
v self — that is what produced the broken state, because the checkout's vlib
and its compiler come from master at whatever moment each was last touched, and
v self does not reconcile them with anything.If you want to work on V itself rather than use it, treat the checkout as a build
environment, not an installation:git clone https://github.com/vlang/v
cd v
v self # rebuild the compiler from the current source
v version # then verify with an actual stdlib import, not this
And check vlib and v.exe dates against each other when something impossible
happens:Get-Item v.exe, vlib\builtin\int.v | Select-Object Name, LastWriteTime
VerdictFor a language you are evaluating, the release zip is the right way in. It took
five minutes to get working and the failure mode cost twenty, because the error
messages point at the standard library instead of at the installation.That is the main thing I would want changed: a version check between v.exe and
vlib at startup would have turned a confusing half hour into one sentence.