ww output: match Go exact -o parsing
This commit is contained in:
@@ -8658,6 +8658,176 @@ executable, and retained-test-product bytes are unchanged. Build workdir format
|
||||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||||
remains `3`.
|
||||
|
||||
### 11.44 Implemented exact output-option name and value semantics
|
||||
|
||||
The `ww build` and `ww test` output option has the exact registered name `o`.
|
||||
Its accepted forms are `-o VALUE`, `--o VALUE`, `-o=VALUE`, and
|
||||
`--o=VALUE`. An equals form splits at the first `=` and preserves the complete
|
||||
remaining value, including an empty value and additional `=` bytes. Repeated
|
||||
occurrences are last-value-wins. A final empty value means no effective
|
||||
explicit output: a single command uses its ordinary default, a multi-command
|
||||
build performs its ordinary no-public-output build, a running test retains no
|
||||
copy, and compile-only testing uses its ordinary default retained name.
|
||||
Concatenated names such as `-oVALUE` and `--oVALUE` are unknown flags rather
|
||||
than output requests. Build option parsing stops at the first root operand;
|
||||
test parsing continues to recognize known test options, including exact `o`,
|
||||
on either side of its package operands.
|
||||
|
||||
#### Pinned evidence and fact classification
|
||||
|
||||
The sole authority is official Go 1.26.5 at
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `init` registers exactly string flag name `o` for the build command in
|
||||
[`cmd/go/internal/work/build.go`, lines 241–248](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L241-L248),
|
||||
and `invoke` parses that flag set before passing only remaining operands to
|
||||
`runBuild` in
|
||||
[`cmd/go/main.go`, lines 290–322](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L290-L322).
|
||||
- `(*FlagSet).parseOne` accepts one or two leading dashes, splits the first
|
||||
`=`, consumes the next argument only when there was no equals delimiter, and
|
||||
rejects an unregistered concatenated name in
|
||||
[`flag/flag.go`, lines 1074–1146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1146).
|
||||
`(*FlagSet).Parse` stops at the first non-flag operand at lines 1149–1176.
|
||||
`stringValue.Set` and `(*FlagSet).Set` overwrite a repeated string value at
|
||||
lines 240–250 and 494–528. `runBuild` derives effective explicit output from
|
||||
the final value's nonzero length and otherwise selects its default behavior
|
||||
in
|
||||
[`cmd/go/internal/work/build.go`, lines 459–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L478).
|
||||
- Build command testdata uses an equals-delimited output successfully in
|
||||
[`version_buildvcs_nested.txt`, line 57](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/version_buildvcs_nested.txt#L57).
|
||||
`testParse` exercises exact names with two leading dashes and separate
|
||||
values at
|
||||
[`flag_test.go`, lines 164–215](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag_test.go#L164-L215),
|
||||
`TestUserDefined` asserts an equals-delimited string value at lines 251–267,
|
||||
and `TestUsage` asserts unknown-flag failure at lines 153–161.
|
||||
- Test command `init` registers exactly string flag name `o` in
|
||||
[`cmd/go/internal/test/testflag.go`, lines 32–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L32-L38).
|
||||
`cmdflag.ParseOne` accepts one or two dashes, cuts the first `=`, preserves
|
||||
empty and remaining-equals value bytes, and rejects unknown names in
|
||||
[`cmd/go/internal/cmdflag/flag.go`, lines 53–118](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/cmdflag/flag.go#L53-L118).
|
||||
`testFlags` recognizes known flags before and after the package list and
|
||||
rejects an unknown flag with `-c` in
|
||||
[`cmd/go/internal/test/testflag.go`, lines 219–349](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L349).
|
||||
`testNeedBinary` and the output-classification branch treat final empty
|
||||
`testO` as no explicit retained destination in
|
||||
[`cmd/go/internal/test/test.go`, lines 631–646 and 771–781](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L631-L781).
|
||||
- Official command testdata uses compile-only test output successfully in
|
||||
[`devnull.txt`, lines 3–8](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/devnull.txt#L3-L8)
|
||||
and
|
||||
[`test_race_tag.txt`, lines 1–9](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_race_tag.txt#L1-L9).
|
||||
[`test2json_interrupt.txt`, line 10](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test2json_interrupt.txt#L10)
|
||||
places `-o` after a package operand, while
|
||||
[`test_flag.txt`, lines 11–16](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_flag.txt#L11-L16)
|
||||
asserts unknown-flag rejection with `-c` across supported placements.
|
||||
|
||||
Those registrations, parser branches, effective-output branches, and official
|
||||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||||
Applying their exact-name, first-equals, final-value, and command-placement
|
||||
rules to WW's local command surface while retaining WW's diagnostic wording is
|
||||
**behavior derived from the pinned implementation**. The measured WW matrix
|
||||
below is **directly measured WW behavior**; no installed host Go result is used
|
||||
as authority.
|
||||
|
||||
#### Direct pre-fix Cstage and WWstage matrix
|
||||
|
||||
Both stages had identical pre-fix behavior in every row:
|
||||
|
||||
| Route and spelling | Directly measured pre-fix result |
|
||||
| --- | --- |
|
||||
| single build, `-o=name` | exited 0 with empty streams, left `name` absent, and published executable `=name` |
|
||||
| single build, `-oname` | exited 0 with empty streams and incorrectly accepted the concatenated name |
|
||||
| single build, `--o name` or `--o=name` | exited 2 with empty stdout and byte-identical `ww build: unknown flag\n` stderr |
|
||||
| single build, final `-o=` | exited 0 with empty streams and published literal file `=` rather than the default command name |
|
||||
| build values containing `=` | retained an erroneous leading `=`; repeated separate forms were already last-value-wins |
|
||||
| build option after the first root | remained package input rather than being reparsed, matching the required placement boundary |
|
||||
| two-command coordinator, `-o=DIR/` | published both products beneath a literal leading-`=` directory |
|
||||
| two-command coordinator, `-oDIR/` | incorrectly accepted the joined name and published beneath the requested directory |
|
||||
| two-command coordinator, final `-o=` | exited 2 as `cannot use -o with multiple packages` instead of selecting no effective explicit output |
|
||||
| compile-only directory test, `-o=name` | exited 0 with empty streams, left `name` absent, and published test binary `=name` |
|
||||
| compile-only directory test, `-oname` | incorrectly accepted the concatenated name and published that retained binary |
|
||||
| compile-only directory test, `--o=name` | exited 2 with empty stdout and byte-identical `ww test: unknown flag\n` stderr |
|
||||
| compile-only directory test, final `-o=` or a value containing `=` | published literal `=` or an erroneous leading-`=` destination |
|
||||
| test `-o` after its package operand | was already recognized, matching the required test placement boundary |
|
||||
|
||||
The wrong-path single-build executables were stage-byte-identical 4,268-byte
|
||||
files with SHA-256
|
||||
`866c1eb875dad271d37572f43fb9d9b0eb6a2344d2e61646e655bb09f7909bf6`.
|
||||
The wrong-path retained test binaries were stage-byte-identical 112,829-byte
|
||||
files with SHA-256
|
||||
`5ea3ac9add844dc4cd98cc07fb64816415b5e3c03745dc4cc756ec093cf5cea7`.
|
||||
The build and test unknown-flag diagnostics were respectively 23 and 22 bytes,
|
||||
also byte-identical between Cstage and WWstage. These byte counts and hashes
|
||||
describe only the direct pre-fix measurements.
|
||||
|
||||
#### Ownership and complete four-axis result
|
||||
|
||||
The Cstage command owners are `parse_build_flags` and `do_test` in
|
||||
`cmd/ww/main.c`. Their WWstage semantic twins are `dobuild` and `dotest` in
|
||||
`selfhost/cmd/ww/main.ww`. The shared multi-package owner is
|
||||
`packagecommand` in `internal/wwpackage/package.ww`. Each recognizes exact
|
||||
one-/two-dash separate/equals forms, replaces prior occurrences with the final
|
||||
value, and derives effective explicit-output state from that final value's
|
||||
non-emptiness. The build parser retains its first-root stop, while test and the
|
||||
coordinator retain their established after-package recognition. `dorun` and
|
||||
the shared `run` route are not changed. The compiler, assembler, archiver,
|
||||
linker, runtime, package checker, and import resolver do not own this rule.
|
||||
|
||||
- **Go-like build:** exact accepted forms select the same established output
|
||||
path as separate `-o VALUE`; a final empty value selects the existing
|
||||
default/no-public-output branch. Invalid concatenated names reject before
|
||||
loading, graph or action construction, producers, publication, or runtime.
|
||||
- **Go-like test:** the same exact forms select retained destinations on both
|
||||
sides of package operands. Final empty means no running-test retention or
|
||||
the normal compile-only default. Discovery, variants, generated main,
|
||||
filtering, execution, accounting, result annotation, and absence of a
|
||||
test-result cache do not change.
|
||||
- **Go-like package:** output bytes remain presentation metadata. Source
|
||||
eligibility, package clauses, declared names, variants, command
|
||||
classification, canonical package representatives, graph nodes, actions,
|
||||
symbols, artifacts, and persistence keys are unchanged.
|
||||
- **Go-like import:** output spelling creates no binding or edge and changes no
|
||||
dotted import spelling, alias, search, local/vendor/internal rule,
|
||||
visibility, cycle, initialization order, canonical identity, or `.wwi`
|
||||
ownership.
|
||||
|
||||
#### Loading, lifecycle, parity, and proof
|
||||
|
||||
Accepted forms enter the same existing loading, graph, scheduling, compiler,
|
||||
assembler, archiver, linker, runtime, publication, persistence, reuse, and
|
||||
invalidation paths as `-o VALUE`. They add no action, process, transaction,
|
||||
cache, key, artifact byte, or runtime state. Producer or runtime failure,
|
||||
late output rejection, rollback, prior-state preservation, concurrent
|
||||
publication, interruption, and process-group cleanup therefore retain their
|
||||
established owners and results. Output installation keeps the existing
|
||||
transaction, object-safety, mode, null-device, output-directory, and
|
||||
running-retained-test guard rules.
|
||||
|
||||
Invalid concatenated names stop before all loading and work, create no
|
||||
diagnostic competitor or product, and leave no unit, interface, assembly,
|
||||
object, archive, executable, retained test binary, capture, output prefix,
|
||||
`.new`, `.install`, `.wwtxn.*`, or scratch residue. A final empty value cannot
|
||||
create literal `=`, `=.sepwork`, or transaction residue. Cold and warm
|
||||
accepted requests use the ordinary publication and reuse paths; changing only
|
||||
an accepted spelling does not rekey semantic work. Independent concurrent
|
||||
requests own independent argument state, workdirs, stages, captures, and
|
||||
outputs. Build starts no runtime; running tests keep their private executable
|
||||
and publish only after successful execution.
|
||||
|
||||
The WW-native `output_flag_exact_name_and_value_semantics` observer is the
|
||||
focused owner for both public stages and all three parser routes. It covers the
|
||||
four accepted forms, extra and empty equals values, repetition, concatenated
|
||||
name rejection, build/test placement controls, multi-command behavior,
|
||||
diagnostic parity, runnable and retained artifact-byte parity, warm reuse, and
|
||||
absence of literal-equals and transaction residue. Existing transaction,
|
||||
producer/runtime failure, rollback, concurrency, interruption, output-mode,
|
||||
and cleanup observers remain authoritative for the unchanged downstream
|
||||
mechanisms. Post-fix byte counts and hashes are recorded only after direct
|
||||
focused measurement; this section does not infer them from the implementation.
|
||||
|
||||
This is command parsing and output presentation only. No persisted-byte
|
||||
contract changes: build workdir format remains `18`, test workdir format
|
||||
remains `19`, and semantic storage format remains `3`.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
35
docs/spec.md
35
docs/spec.md
@@ -344,7 +344,19 @@ ImportPath = ident { "." ident } .
|
||||
arguments and result; this rule does not adopt Go's source signature. An
|
||||
ordinary import of a package declared `main` is rejected, except for the
|
||||
toolchain's colocated external-test wiring.
|
||||
- For `ww build`, an explicit `-o` names an output directory when ordinary
|
||||
- For `ww build`, the output-option name is exactly `o`. The accepted forms are
|
||||
`-o VALUE`, `--o VALUE`, `-o=VALUE`, and `--o=VALUE`. An equals form splits
|
||||
at its first `=` and preserves every later byte, including further `=`
|
||||
characters; an empty value is valid. Repetition is last-value-wins, and a
|
||||
final empty value means that there is no effective explicit output, so the
|
||||
ordinary default-output or no-public-output rule applies. A concatenated
|
||||
spelling such as `-oVALUE` or `--oVALUE` is an unknown flag, not an output
|
||||
option. Build option parsing stops at the first package or source operand;
|
||||
later flag-like arguments remain operands and are not reparsed as `-o`.
|
||||
These spelling and placement rules select only caller-visible output
|
||||
disposition and never supply package, import, graph, action, symbol,
|
||||
artifact, `.wwi`, or persistence identity.
|
||||
A nonempty effective `-o` names an output directory when ordinary
|
||||
`stat` reports an existing directory (following symlinks) or its spelling
|
||||
ends in `/`. This classification is independent of whether one or many
|
||||
package roots were requested. Each selected command is published beneath
|
||||
@@ -771,11 +783,22 @@ coordinator reports that successful validation exactly as
|
||||
`? <package> [no test files]\n`.
|
||||
|
||||
Every test-bearing directory product links one request-private runnable.
|
||||
`-c` retains an executable copy and suppresses its execution; `-o` retains a
|
||||
copy at the named destination and still executes unless `-c` is present. With
|
||||
no explicit output, `-c` writes `<import-leaf>.test` in the invocation
|
||||
directory. An output ending in `/` or naming an existing directory receives
|
||||
that basename and may have missing parent directories created. One
|
||||
The test output-option name is exactly `o`, with the accepted forms `-o VALUE`,
|
||||
`--o VALUE`, `-o=VALUE`, and `--o=VALUE`. Equals forms split only at their
|
||||
first `=` and preserve an empty value or any additional `=` bytes. Repeated
|
||||
occurrences are last-value-wins. A final empty value means no effective
|
||||
explicit output and therefore requests no running-test retention; with `-c`,
|
||||
the ordinary default retained name applies. A concatenated `-oVALUE` or
|
||||
`--oVALUE` is unknown. Unlike build option parsing, known test options,
|
||||
including these exact output forms, are recognized before or after package
|
||||
operands. Invalid output-option names reject before package loading, product
|
||||
construction, execution, or publication.
|
||||
`-c` retains an executable copy and suppresses its execution; a nonempty
|
||||
effective `-o` retains a copy at the named destination and still executes
|
||||
unless `-c` is present. With no effective explicit output, `-c` writes
|
||||
`<import-leaf>.test` in the invocation directory. An output ending in `/` or
|
||||
naming an existing directory receives that basename and may have missing
|
||||
parent directories created. One
|
||||
non-directory output may name only one package. Multiple packages whose
|
||||
visible import leaves would produce the same test-binary name reject before
|
||||
tools or output creation; exact `/dev/null` is the discard exception. It keeps
|
||||
|
||||
@@ -236,13 +236,23 @@ warning on stderr and accounting on stdout because no coordinator combines its
|
||||
descriptors or emits a package result.
|
||||
|
||||
Directory test binaries are always linked under the coordinator's temporary
|
||||
product root. `-c` independently requests a caller-visible executable copy and
|
||||
suppresses execution. `-o` independently requests a copy and still runs the
|
||||
temporary binary unless `-c` is also present. Without `-o`, `-c` publishes
|
||||
`<import-leaf>.test` in the invocation directory; an output ending in `/` or
|
||||
naming an existing directory receives one such name per selected package and
|
||||
missing parents are created. A single non-directory output is legal for one
|
||||
package only. Multi-package non-directory output and duplicate visible binary
|
||||
product root. The retained-output option has the exact registered name `o` and
|
||||
accepts `-o VALUE`, `--o VALUE`, `-o=VALUE`, and `--o=VALUE`. An equals form
|
||||
splits only at its first `=`, preserving an empty value and any later `=`
|
||||
bytes. Repeated occurrences are last-value-wins. A final empty value is no
|
||||
effective explicit output: it requests no retained copy for a running test,
|
||||
while `-c` falls back to the ordinary `<import-leaf>.test` name. Concatenated
|
||||
`-oVALUE` and `--oVALUE` spell unknown flags and reject before loading, product
|
||||
construction, tools, execution, or publication. Known test flags, including
|
||||
these exact output forms, remain recognized before or after package operands.
|
||||
`-c` independently requests a caller-visible executable copy and suppresses
|
||||
execution. A nonempty effective `-o` independently requests a copy and still
|
||||
runs the temporary binary unless `-c` is also present. Without an effective
|
||||
explicit output, `-c` publishes `<import-leaf>.test` in the invocation
|
||||
directory; an output ending in `/` or naming an existing directory receives
|
||||
one such name per selected package and missing parents are created. A single
|
||||
non-directory output is legal for one package only. Multi-package
|
||||
non-directory output and duplicate visible binary
|
||||
names reject before tools; exact `/dev/null` discards every copy and permits
|
||||
duplicate names. The private test link still runs unless `-c` suppresses it;
|
||||
the raw single-file compatibility route also links into driver-owned private
|
||||
|
||||
Reference in New Issue
Block a user