Skip to content

[build] default_jobs in the global config.toml is parsed and never consulted; ninja runs with its own default #564

Description

@yspbwx2010

Version: mcpp 2026.9.4.3 (release binary, linux-x86_64), ninja 1.12.1 from the xim payload. Line numbers are against main at 1e2137b.

What a user observes. $MCPP_HOME/config.toml is written by mcpp itself with a [build] table holding default_jobs = 0 (the template is src/config.cppm:356-358, written for a fresh home by write_default_config_toml). Setting it to 4 changes nothing: mcpp build on a workspace of seven members launches the backend as ninja -C <output dir> (with --quiet, or -v when verbose) and no -j, so ninja runs its own default, which ninja --help reports as 10 on this 8-core machine. Quoting the value (default_jobs = "4") changes nothing either, and by the value_or(0) at the parse site an absent key and 0 are the same. MCPP_JOBS=4 mcpp build on the same tree launches ninja … -j4, and MCPP_JOBS=2 launches -j2 (--jobs/-j is the same channel, src/cli.cppm:188-191 sets MCPP_JOBS), so the observation method, reading the ninja argv with pgrep -af while a rebuild runs, does see the flag whenever there is one.

Where it goes, read from the source. src/config.cppm:517 parses the key into cfg.defaultJobs, declared at :96 under the comment "From config.toml [build]", and those two lines are the only mentions of the field in the repository: it has no consumer. (The key string itself also appears in four e2e fixtures and one CI action, each of them another copy of the generated file.) resolve_jobs in src/build/schedule/policy.cppm:242-265 reads MCPP_JOBS and the manifest's [build] jobs and returns 0 when neither is set; the precedence comment at :127-129 lists exactly those two before "0, meaning say nothing and leave the backend's own default". That 0 travels through schedule::decide into BuildOptions::parallelJobs (src/build/execute.cppm:774), and src/build/ninja_backend.cppm:2846-2847 omits -j when it is 0. The global config never enters the chain. default_backend in the same table has the same shape: parsed at :518 into defaultBackend, never read.

Why it matters more than a dead key usually does. The precedence comment itself makes the case (policy.cppm:131-136): a single module compile peaks at 0.5–1.0 GB, and on a high-core, modest-RAM machine the backend default swaps. That is a property of the machine, not of a project, and the two knobs that do work are both the wrong shape for it. MCPP_JOBS (or --jobs) has to be said on every invocation, or baked into every wrapper and every recipe that calls mcpp. [build] jobs is per-package, and [workspace.build] rejects it ("has no key 'jobs' (or it is not inheritable)", the known-key list at modules/manifest/src/toml.cppm:2652-2657, which is a reasonable rule), so a seven-member workspace would carry the number seven times and commit a machine property into the repository. The per-machine config is the natural home for it, mcpp already plants the key there, and it is the one place that does nothing. The machine this was found on has 8 cores and 15 GiB; ten concurrent module compiles at the sizes the comment quotes is the arithmetic that makes it unusable while a cold build runs.

What would answer it. Either give resolve_jobs the global value as a parameter and place it between the manifest and the backend default — MCPP_JOBS > [build] jobs > global default_jobs > 0 — so the existing comment stays true with one more step and "0 = say nothing" is unchanged for everyone who has not touched the key. A parameter rather than a config import, because resolve_jobs deliberately carries no dependency beyond the manifest today (:138-139), and because it has a second caller at src/build/execute.cppm:2165 for test-runner concurrency, where 0 falls back to hardware_concurrency() rather than to the backend; wiring the key in would cap that as well, which is probably what someone setting a machine-wide number wants, but it is a second behaviour to name. Or drop default_jobs (and default_backend, if it is likewise unread) from the template and the parser so the generated file stops promising them.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions