Skip to content

Commit 83af60d

Browse files
committed
Finished states how the time was spent from one minute, names the longest compile by its source file, and states the profile's descriptor on the fast path
Build output design revision 3, decision D4 (section 7.3). Below a minute Finished states the profile and the total alone. The step record carries, per compile step, its first input relative to the innermost package root that holds it, and Finished names the longest step by it (longest slow: src/main.cpp 1m08s) where it named the object file. The record's header carries the profile's descriptor, which the fast path reads alone, so a build with nothing to do states [unoptimized + debuginfo] as a full build does. One function, profile_descriptor, spells the descriptor for both, from the plan's manifest that compute_flags reads. The docs, the CHANGELOG and the design state it; D3 is recorded as no change.
1 parent 72a9a51 commit 83af60d

9 files changed

Lines changed: 207 additions & 48 deletions

‎.agents/docs/2026-09-30-build-output-refinement-design.md‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ status: landed
88
- Status: landed (revision 3). Implemented in #743, released as 2026.9.30.1.
99
It refines `2026-09-29-build-progress-display-design.md` (revision 2,
1010
landed in #742, released as 2026.9.29.5) and replaces the parts listed in
11-
section 6. Decision D3 of section 16 was settled after the implementation
12-
as no change: the configuration lines stay as they are, and T6 is dropped.
13-
Decision D4 is open, so the part of T4 it covers (the 60 s threshold, the
14-
profile descriptor on the fast path, and the source file of `longest`) is
15-
not implemented; `Finished` keeps revision 2's form there.
11+
section 6. Decisions D3 and D4 of section 16 were settled after the first
12+
implementation: D3 as no change (the configuration lines stay as they are,
13+
and T6 is dropped), and D4 as recommended (section 7.3: the 60 s threshold,
14+
the profile descriptor on the fast path, and the source file of `longest`),
15+
implemented in the same pull request.
1616
- Date: 2026-09-30
1717
- Origin: a report on `mcpp build` in the xlings repository with mcpp
1818
2026.9.29.5. It raised three questions: why the build prints warnings;
@@ -1358,8 +1358,11 @@ of silence.
13581358
from the consumer's key, since a package reached through `[feature-deps]`
13591359
has no entry in the consumer's `[dependencies]`. A version 1 record is read
13601360
with both empty, and its subject then carries what version 1 wrote there,
1361-
until the next plan writes version 2. The profile descriptor on the fast
1362-
path and the source file of `longest` (section 7.3) wait for decision D4.
1361+
until the next plan writes version 2. Version 2 also carries the profile's
1362+
descriptor in the header, which the fast path reads alone, and an `S` line
1363+
per compile step: the step's first input, relative to the innermost package
1364+
root that holds it, which `Finished` names for the longest step
1365+
(section 7.3).
13631366
- **Unchanged**: the log reader and its recompaction handling, the
13641367
attribution in the generator, the action-start file, and the heartbeat.
13651368

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ records one lock entry per identity again.
7979
- **A build program has a line when it runs or fails**; a reused program has
8080
one under `--verbose`. The folded `build.mcpp N dependencies` line is gone.
8181
- **A failure names its package**: `error: build failed in <package>`.
82+
- **`Finished` states how the time was spent from one minute**, where it did
83+
from ten seconds; below a minute it states the profile and the total alone.
84+
The longest step, when it took at least a quarter of the build, is named
85+
by its source file for a compile (`longest slow: src/main.cpp 1m08s`), not
86+
by its object file. A build with nothing to do states the profile's
87+
descriptor as a full build does (`Finished dev [unoptimized + debuginfo]
88+
in 0.02s`): the step record's header carries it for the fast path.
8289
- **The status row is aligned with the verbs** (` Building 612/707 · 0:35`),
8390
its phases are `Planning`, `Running`, `Building`, `Stopping` and `Checking`,
8491
and no blank row separates it from the output.

‎docs/09-commands-by-scenario.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ $ mcpp build
243243
Compiling mcpplibs.xpkg v0.0.59
244244
Compiling xlings v2026.9.29.1 (.)
245245

246-
Finished dev [unoptimized + debuginfo] in 33.63s · plan 3.06s · programs 0.64s · build 29.94s
246+
Finished dev [unoptimized + debuginfo] in 1m08s · plan 16.90s · programs 0.98s · build 50.99s
247247
```
248248

249249
- A package's line is written when the first of its steps finishes (a
@@ -264,9 +264,11 @@ $ mcpp build
264264
- A failed step is reported when it fails: `error: build failed in
265265
<package>`, then its diagnostics, while ninja waits for the steps still
266266
running.
267-
- `Finished` states the whole command's time. A command of ten seconds or
268-
more also states how the time was spent, and names the step that took at
269-
least a quarter of the build when there is one.
267+
- `Finished` states the profile and the whole command's time, whether the
268+
build had work to do or not. A command of a minute or more also states how
269+
the time was spent, and names the step that took at least a quarter of the
270+
build when there is one: a compile by its source file, relative to its
271+
package, and an action by its label.
270272

271273
On a terminal one status row is drawn below the output and updated in place:
272274

‎docs/zh/09-commands-by-scenario.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ $ mcpp build
224224
Compiling mcpplibs.xpkg v0.0.59
225225
Compiling xlings v2026.9.29.1 (.)
226226

227-
Finished dev [unoptimized + debuginfo] in 33.63s · plan 3.06s · programs 0.64s · build 29.94s
227+
Finished dev [unoptimized + debuginfo] in 1m08s · plan 16.90s · programs 0.98s · build 50.99s
228228
```
229229

230230
- **何时写出**:包的第一个步骤完成时(依赖扫描不计),或它的第一个 `check`、`prepare` 动作开始时,写出该包的行;此后这一行不再改变。
@@ -238,7 +238,7 @@ $ mcpp build
238238
- **来源配色**:在终端上,名字的颜色表示来源。官方索引为青色,其他索引为品红,git 仓库为蓝色,项目自身的包为默认色。
239239
- **构建程序**:构建程序在运行或失败时有一行,并给出耗时。结果被复用的构建程序只在 `--verbose` 下有行。
240240
- **失败**:失败的步骤在失败时即报告:先写 `error: build failed in <包>`,再写它的诊断信息;与此同时 ninja 等待仍在运行的步骤。
241-
- **Finished**:`Finished` 给出整个命令的耗时。命令耗时达到十秒时,还说明时间的构成;若某一步骤占构建时间的四分之一以上,则给出该步骤。
241+
- **Finished**:`Finished` 给出配置档和整个命令的耗时,构建有无事可做都一样。命令耗时达到一分钟时,还说明时间的构成;若某一步骤占构建时间的四分之一以上,则给出该步骤:编译步骤给出其源文件(相对于所在包),动作给出其标签。
242242

243243
在终端上,输出下方画一行状态行,并原地更新:
244244

‎src/build/execute.cppm‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import mcpp.freestanding.linkline;
3030
import mcpp.build.graph_shape; // #407: which mode wrote this build.ninja
3131
import mcpp.build.backend;
3232
import mcpp.build.ninja;
33-
import mcpp.build.flags; // realises_optimization — one answer for the level (#694)
33+
import mcpp.build.flags; // profile_descriptor — one answer for the level (#694)
3434
import mcpp.build.runtime_validation;
3535
import mcpp.bmi_cache;
3636
import mcpp.bmi_cache.maintenance; // dir_size + human_bytes, for `clean --stale`
@@ -1066,16 +1066,12 @@ export int run_build_plan(BuildContext& ctx, bool verbose, bool no_cache,
10661066
if (!mcpp::diag::flush(ctx.strict)) return 1;
10671067

10681068
// The descriptor reads the level the compile realised, from the one
1069-
// function `compute_flags` spells it from (#694). It once read the declared
1070-
// level while the compile used another, and said `[optimized]` over `-Og`.
1071-
{
1072-
const auto& bc = ctx.manifest.buildConfig;
1073-
std::string descriptor =
1074-
mcpp::build::realises_optimization(bc) ? "optimized" : "unoptimized";
1075-
if (bc.debug) descriptor += " + debuginfo";
1076-
if (bc.lto) descriptor += " + lto";
1077-
mcpp::build::progress::finished(ctx.profile, descriptor);
1078-
}
1069+
// function `compute_flags` spells it from (#694), and from the plan's
1070+
// manifest, which `compute_flags` reads. It once read the declared level
1071+
// while the compile used another, and said `[optimized]` over `-Og`. The
1072+
// step record's header carries the same value for the fast path.
1073+
mcpp::build::progress::finished(
1074+
ctx.profile, mcpp::build::profile_descriptor(ctx.plan.manifest.buildConfig));
10791075
report_freestanding_size(ctx);
10801076
return 0;
10811077
}
@@ -1689,7 +1685,10 @@ export std::optional<int> try_fast_build(const std::filesystem::path& projectRoo
16891685
*validatedBefore))
16901686
return fast_path_declined("build", "ninja relinked an artifact, whose closure the full path validates"); // relinked: full path reconstructs + validates closure
16911687

1692-
mcpp::build::progress::finished(want->profile, "");
1688+
// The descriptor the plan recorded (revision 3, §7.3); empty for a record
1689+
// written before it was carried.
1690+
mcpp::build::progress::finished(want->profile,
1691+
mcpp::build::progress::read_descriptor(outputDir));
16931692
return 0;
16941693
}
16951694

@@ -1799,7 +1798,10 @@ export std::optional<int> try_fast_workspace_build(
17991798
if (!mcpp::build::runtime_validation::artifact_snapshot_unchanged(r.validated))
18001799
return fast_path_declined("workspace", "ninja relinked an artifact, whose closure the full path validates");
18011800
}
1802-
mcpp::build::progress::finished(profile, "");
1801+
// The groups share the profile, and so its descriptor.
1802+
mcpp::build::progress::finished(
1803+
profile, ready.empty() ? std::string{}
1804+
: mcpp::build::progress::read_descriptor(ready.front().outputDir));
18031805
return 0;
18041806
}
18051807

‎src/build/flags.cppm‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,13 @@ std::string realised_opt_level(const mcpp::manifest::BuildConfig& bc);
203203
// Whether `realised_opt_level` names an optimizing level.
204204
bool realises_optimization(const mcpp::manifest::BuildConfig& bc);
205205

206+
// The profile as `Finished` describes it: `optimized` or `unoptimized` by the
207+
// realised level, then `+ debuginfo` and `+ lto` when they are on. The full
208+
// path states it from the plan it built, and the step record's header carries
209+
// it for the fast path, which has no plan (build output design revision 3,
210+
// §7.3): both read this one function.
211+
std::string profile_descriptor(const mcpp::manifest::BuildConfig& bc);
212+
206213
// The sysroot of an ELF link over a graph-supplied C library: an empty
207214
// directory inside the build directory, so the driver derives no library
208215
// search from the host (#696). `compute_flags` names it and the backend creates
@@ -606,6 +613,13 @@ bool realises_optimization(const mcpp::manifest::BuildConfig& bc) {
606613
return realised_opt_level(bc) != "0";
607614
}
608615

616+
std::string profile_descriptor(const mcpp::manifest::BuildConfig& bc) {
617+
std::string d = realises_optimization(bc) ? "optimized" : "unoptimized";
618+
if (bc.debug) d += " + debuginfo";
619+
if (bc.lto) d += " + lto";
620+
return d;
621+
}
622+
609623
std::filesystem::path graph_link_sysroot(const std::filesystem::path& outputDir) {
610624
return outputDir / kGraphLinkSysrootDir;
611625
}

‎src/build/ninja_backend.cppm‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,7 +1226,12 @@ mcpp::build::progress::Record step_record(const BuildPlan& plan,
12261226
declared.reserve(plan.packages.size());
12271227
for (auto const& p : plan.packages)
12281228
declared.push_back({p.name, p.requested, p.subject, p.cachedUnits, 0, p.detail, p.source});
1229-
return attribution.record(declared);
1229+
// A compile's source is stated relative to its package's root, and the
1230+
// profile's descriptor is the one `Finished` states on the full path, so
1231+
// that the fast path states it too (build output design revision 3, §7.3).
1232+
auto record = attribution.record(declared, plan.packageRoots);
1233+
record.descriptor = profile_descriptor(plan.manifest.buildConfig);
1234+
return record;
12301235
}
12311236

12321237
// The aggregate target for everything staged out of the global cache. Named

0 commit comments

Comments
 (0)