Skip to content

%o expands to only the first output, not all of them #413

Description

@typeless

%o expands to only the first output, while the docs and tup both promise all of them.

The divergence

docs/reference.md:1010 documents %o as "All output files". Tup, which putup's Tupfile syntax
follows, expands %o to every output separated by spaces — src/tup/parser.c:3946+ iterates the
whole output list (TAILQ_FOREACH(nle, &onl->entries, list)).

putup emits only the first output. Verified at the line in all three independent expanders:

  • src/graph/dag.cpp:933case 'o': appends get_operand_path(cmd->outputs[0])
  • src/index/entry.cpp:446case 'o': resolves cmd.outputs[0] only
  • src/parser/eval.cpp:507 — bare %o appends the single flags.output

Notably the multi-output data is already present: eval.cpp:449-450 implements the numbered form
(%2o) against flags.all_outputs. Bare %o simply does not consult it.

Why it matters beyond the obvious

A rule with two or more outputs silently passes only the first to its command. For the common
one-output rule the behaviour is indistinguishable, which is why this has gone unnoticed.

It also has a testing consequence that reaches past this bug. Any test asserting that some output is
absent from %o passes vacuously today, because %o never emits more than outputs[0]
regardless. A pin of that shape looks like coverage and is not. A discriminating pin must use the
numbered form (%2o) or assert the full expansion of a genuinely multi-output rule.

Disposition

Upstream wins: putup's %o should expand to all outputs, matching both tup and putup's own
documentation. The three expanders should agree by construction rather than by three separate
correct implementations — they are the same question asked in three places.

Found while inventorying output consumers for #370 (extra outputs); #370's discriminating test
depends on this being fixed or accounted for, so the two are ordered.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions