| 📦 Turbo Rust 713ea5c k33g 11h ago | 1 | # Reference: the version number |
| 2 | |
| 3 | > Neutral description of where the version Turbo Rust reports comes from, and what each way of building it produces. |
| 4 | |
| 5 | ## Where the number comes from |
| 6 | |
| 7 | Three sources, consulted in this order. The first that answers wins. |
| 8 | |
| 9 | | Order | Source | Set by | |
| 10 | | --- | --- | --- | |
| 11 | | 1 | Linker stamps | `make build`, `make install`, `scripts/install.sh` | |
| 12 | | 2 | Go build information | The Go tool, automatically | |
| 13 | | 3 | `unknown` | Nothing — the value reported when no source could name the build | |
| 14 | |
| 15 | There is **no version constant in the source**. A number written into a `.go` file has to be edited as part of releasing, and is wrong the moment someone forgets. |
| 16 | |
| 17 | ## Linker stamps |
| 18 | |
| 19 | Three package-level variables in `internal/version`, set with `-ldflags -X`. |
| 20 | |
| 21 | | Variable | Filled from | Example | |
| 22 | | --- | --- | --- | |
| 23 | | `stamp` | `git describe --tags --dirty` | `v0.1.0-14-g88a4c38` | |
| 24 | | `commit` | `git rev-parse --short HEAD` | `88a4c38` | |
| 25 | | `built` | `date -u +%Y-%m-%dT%H:%M:%SZ` | `2026-08-31T18:04:05Z` | |
| 26 | |
| 27 | ```sh |
| 28 | go build -ldflags "\ |
| 29 | -X 'rickub.com/turbo-editors/turbo-rust/internal/version.stamp=v0.2.0' \ |
| 30 | -X 'rickub.com/turbo-editors/turbo-rust/internal/version.commit=88a4c38' \ |
| 31 | -X 'rickub.com/turbo-editors/turbo-rust/internal/version.built=2026-08-31T18:04:05Z'" . |
| 32 | ``` |
| 33 | |
| 34 | A leading `v` is dropped for display: the tag is `v0.2.0`, the About box says `0.2.0`. |
| 35 | |
| 36 | ## Go build information |
| 37 | |
| 38 | Read from `runtime/debug.ReadBuildInfo()` when nothing was stamped. |
| 39 | |
| 40 | | Field read | Used for | |
| 41 | | --- | --- | |
| 42 | | `Main.Version` | The number, unless it is empty, `(devel)`, or a pseudo-version | |
| 43 | | `vcs.revision` | The commit, abbreviated to seven characters | |
| 44 | | `vcs.modified` | Whether `-dirty` is appended | |
| 45 | |
| 46 | `vcs.time` is **not** used. It records when the commit was made, not when the binary was linked, so reporting it as a build date would be wrong on every binary built later than its own commit. |
| 47 | |
| 48 | A **pseudo-version** — `v0.1.1-0.20260831165958-88a4c3859bf3` — is the Go tool naming a commit that no tag names. It is reported as `devel`, not shown as written: its `0.1.1` is a patch release that does not exist. |
| 49 | |
| 50 | ## What each build reports |
| 51 | |
| 52 | | Built by | Number | Commit | Built | |
| 53 | | --- | --- | --- | --- | |
| 54 | | `make build`, `make install`, `scripts/install.sh` | `0.1.0-14-g88a4c38` | yes | yes | |
| 55 | | The same, on a tagged commit | `0.2.0` | yes | yes | |
| 56 | | The same, with uncommitted changes | `0.1.0-14-g88a4c38-dirty` | yes | yes | |
| 57 | | `go install rickub.com/turbo-editors/turbo-rust@v0.2.0` | `0.2.0` | no | no | |
| 58 | | `go build .` in a checkout | `devel` | yes | no | |
| 59 | | `go build .` in a checkout with uncommitted changes | `devel-dirty` | yes | no | |
| 60 | | `cargo run` | `unknown` | no | no | |
| 61 | | A checkout with no git, and no stamps | `unknown` | no | no | |
| 62 | |
| 63 | Only the stamped rows can report a tag: the Go build system does not read git tags. |
| 64 | |
| 65 | ## Checked at build time |
| 66 | |
| 67 | A linker stamp is a string, and a wrong one is not an error. `-X` naming a symbol that does not exist links happily and stamps nothing; the binary then falls back to Go build information and reports a version the build never meant — often `devel`, on a binary attached to a release. Nothing but running the binary catches it, so every build that produces one runs it. |
| 68 | |
| 69 | `scripts/check-version.sh` is what runs. |
| 70 | |
| 71 | | Called by | On | A failure fails | |
| 72 | | --- | --- | --- | |
| 73 | | `make build` | `bin/turbo-rust`, with `$(VERSION)` and `$(COMMIT)` | the build | |
| 74 | | `scripts/install.sh` | the staged binary, **before** it is installed | the install, leaving the binary already there untouched | |
| 75 | | `03-build-releases.sh` | the one staged asset this machine can run, with the tag | the release build | |
| 76 | |
| 77 | ```sh |
| 78 | scripts/check-version.sh bin/turbo-rust v0.2.0 88a4c38 # a stamped build |
| 79 | scripts/check-version.sh bin/turbo-rust # nothing to expect |
| 80 | ``` |
| 81 | |
| 82 | | Arguments | Passes when | |
| 83 | | --- | --- | |
| 84 | | binary, version, commit | the reported number **equals** the version with its leading `v` dropped, and the commit appears in the output | |
| 85 | | binary, version | the number equals it | |
| 86 | | binary | the number is anything but `unknown` | |
| 87 | |
| 88 | The version comparison is an equality, not a search. `0.2.0` is a substring of `10.2.0`, and of a commit hash that happens to contain it; a stamp that is nearly right is exactly what this exists to catch. |
| 89 | |
| 90 | | Exit | Meaning | |
| 91 | | --- | --- | |
| 92 | | `0` | The binary reports what the build meant. The line it printed is echoed. | |
| 93 | | `1` | It does not run, is not there, or reports something else. | |
| 94 | | `2` | No binary was named. | |
| 95 | |
| 96 | ## Where it is shown |
| 97 | |
| 98 | ### `-version` |
| 99 | |
| 100 | One line, carrying every part that is known. |
| 101 | |
| 102 | ``` |
| 103 | Turbo Rust 0.2.0 (88a4c38, built 2026-08-31T18:04:05Z) |
| 104 | Turbo Rust 0.2.0 (88a4c38) |
| 105 | Turbo Rust 0.2.0 |
| 106 | ``` |
| 107 | |
| 108 | ### Help ▸ About |
| 109 | |
| 110 | One line per known fact. A fact the build did not record has **no line**, rather than an empty one. |
| 111 | |
| 112 | ``` |
| 113 | Turbo Rust 0.2.0 |
| 114 | |
| 115 | A Turbo C-style editor for Rust, |
| 116 | written in Go. |
| 117 | |
| 118 | Commit: 88a4c38 |
| 119 | Built: 2026-08-31 18:04 UTC |
| 120 | Theme: Turbo Classic |
| 121 | ``` |
| 122 | |
| 123 | `Built` is rendered in UTC as `YYYY-MM-DD HH:MM UTC`. A stamp that is not valid RFC 3339 is shown exactly as it was given, rather than dropped. |
| 124 | |
| 125 | ### `make version` |
| 126 | |
| 127 | Prints what this checkout would stamp, without building. |
| 128 | |
| 129 | ``` |
| 130 | $ make version |
| 131 | v0.1.0-14-g88a4c38 (88a4c38) |
| 132 | ``` |
| 133 | |
| 134 | ### `make ldflags` |
| 135 | |
| 136 | Prints the linker flags a stamped build uses, so a script can reuse them instead of repeating the `-X` paths. |
| 137 | |
| 138 | ``` |
| 139 | $ make ldflags |
| 140 | -X 'rickub.com/turbo-editors/turbo-rust/internal/version.stamp=v0.2.0' -X '….commit=7f8b36a' -X '….built=2026-08-31T19:02:03Z' |
| 141 | ``` |
| 142 | |
| 143 | `03-build-releases.sh` reads it for its cross-compiles, overriding the version with the tag it is releasing — `make ldflags VERSION=v0.2.0` — so the binaries say what the release says rather than what `git describe` says. A binary cross-compiled without it reports `devel`, whatever the release it is attached to says. |
| 144 | |
| 145 | ## See also |
| 146 | |
| 147 | - Cutting a release so the number is right: [How to make a release](../how-to/make-a-release.md) |
| 148 | - What `-version` is **not** for: it is written for a person. A script that needs the number should compare with `grep -F`, or ask git, rather than reading a field out of it. |
| 149 | - Why there is no version constant: [Design decisions](../explanation/design-decisions.md#the-version-is-a-property-of-the-build-not-of-the-source) |
| 150 | - The `-version` flag among the others: [Command line](cli.md) |