Skip to content

feat: mcpp run and mcpp test name a script's missing #! interpreter - #923

Open
NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:feat/run-names-a-missing-script-interpreter
Open

NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:feat/run-names-a-missing-script-interpreter

Conversation

@NopeCharon

Copy link
Copy Markdown
Contributor

Summary

An artefact the run slot executes directly can be a script: emsdk's JavaScript launcher begins #!/usr/bin/env node. An emsdk payload installed before its recipe wrote .mcpp-toolchain.json names no runner, so the launcher runs through that line, and on a host without node on PATH the only output was /usr/bin/env: 'node': No such file or directory. mcpp had started env successfully, so none of its own launcher messages applied.

  • mcpp.build.runner_lookup reads a script's #! line as the kernel reads it (parse_script_interpreter, script_interpreter). The interpreter is the first word after #!. Through env, the program is the first word that is neither -S nor a NAME=value assignment. When the line can't be read with certainty (a relative interpreter, any other env option, env with no program), no program is named, so the note never names the wrong one. Windows reads no #! line and is skipped.
  • missing_interpreter_note applies when the interpreter is not an executable file, or when the program env would look up is not on the artefact's PATH. It names the missing program and says that a toolchain payload names its runner in .mcpp-toolchain.json, and that one installed before its recipe wrote that file names none. It then gives the remedy that mcpp run: a script artefact whose interpreter is missing fails without naming the remedy #621 proposes: mcpp index update, then mcpp toolchain remove <spec> and mcpp toolchain install <spec>. It names no toolchain, because a file's first line does not say which payload built it.
  • mcpp run prints the note before it executes an artefact that has no runner and no execution host. It checks against the PATH the artefact receives (the composed childEnv, else this invocation's). The blank line before the program's output now comes after the environment is composed, so the note stays above it. mcpp test prints the note once per build, for the first test it executes directly. Neither command prints it under --print-launch, and mcpp test does not print it under --message-format json.
  • docs/20-toolchains.md and its Chinese copy describe the note, replacing "which mcpp does not yet explain (mcpp run: a script artefact whose interpreter is missing fails without naming the remedy #621)".
note: 'target/wasm32-emscripten/…/bin/app.js' runs through its first line, `#!/usr/bin/env node`, and 'node' is not on PATH.
      A toolchain payload names the program that runs its artefacts in
      `.mcpp-toolchain.json`; one installed before its recipe wrote that file
      names none, and its artefacts run through their `#!` line.
      fix: `mcpp index update`, then `mcpp toolchain remove <spec>` and
      `mcpp toolchain install <spec>` for the toolchain that built it.

Closes #621.

Criteria

  • The #! line is read as the kernel reads it. RunnerLookup/AShebangNamesItsInterpreter covers a direct interpreter with an argument, env node with a CRLF line end, and env -S NAME=value node --flag. RunnerLookup/AnUncertainShebangNamesNoProgram covers an ELF header, an empty #!, a relative interpreter, env with no program, env -i and env -u X.
  • A missing program is named, and the remedy with it. RunnerLookup/AScriptWhoseInterpreterIsMissingIsNoted uses an env whose program is on no directory of the PATH given, then puts the program on that PATH, and the note goes away. RunnerLookup/AMissingInterpreterPathIsNoted uses an absolute interpreter that does not exist.
  • Nothing is said otherwise. RunnerLookup/AProgramOrAFoundInterpreterIsNotNoted covers a script whose interpreter exists, a binary and a missing file.
  • I compiled the module's code and tests/unit/test_runner_lookup.cpp together outside the engine (Apple clang 21, -std=c++23 -Wall -Wextra, with a stand-in for mcpplibs.mtest). All 16 RunnerLookup cases pass with no warnings. The engine build, the module form of these tests and the other hosts are left to CI. The wiring in execute.cppm did not run locally: it needs a built engine and a script artefact with no runner.
  • check_docs_style.sh, check_docs_structure.sh, check_version_pins.sh and check_workflow_assertions.py pass locally.

Intersections

New rule or feature Invariant it crosses Test at the crossing
mcpp run reads the artefact's #! line before it executes it directly A runner, a payload's runner or an execution host takes precedence, and the artefact is then not executed directly none: the note is gated on choice.tmpl.empty() && host.prefix.empty(), the same condition the direct-exec branch already uses; no e2e sits there
The same --print-launch describes the launch on standard output and starts nothing none: the note is not printed under --print-launch; no test sits there
The same Nothing of mcpp runs after the program starts on POSIX (run_foreground replaces the image) none: the note and the blank separator are printed before run_foreground, and the separator still comes last
mcpp test notes the first directly executed test A refusal that applies to the whole invocation is reported once per build none: once per build through TestBuild::interpreterNoted, skipped for --no-run, a host that cannot reach the tests and an invocation already not run
A missing #! program is named The note names no wrong program RunnerLookup/AnUncertainShebangNamesNoProgram

Compatibility

mcpp run and mcpp test print one more note: on standard error when a directly executed script's interpreter is missing. Otherwise their output, exit codes and the program's environment are unchanged. A program that starts sees the same streams it did before. No cache key or file format changes.

Checks before merging

  • bash .github/tools/check_docs_style.sh, check_docs_structure.sh and check_version_pins.sh pass.
  • python3 .github/tools/check_workflow_assertions.py passes (a step asserts what its name says).
  • No commit on the branch carries an attribution trailer:
    git log origin/main..HEAD -i --grep='Co-Authored-By' prints nothing.
  • The squash merge is given an explicit subject and body, so GitHub does not
    compose one from the branch's commits. Suggested subject: feat: mcpp runandmcpp testname a script's missing#! interpreter.

…eter

An artefact the run slot executes directly can be a script: emsdk's
JavaScript launcher begins `#!/usr/bin/env node`. An emsdk payload
installed before its recipe wrote `.mcpp-toolchain.json` names no
runner, so the launcher runs through that line, and on a host without
`node` on PATH the only output was `/usr/bin/env: 'node': No such file
or directory`. mcpp had spawned `env` successfully, so none of its own
launcher messages applied, and nothing named the cause or the remedy.

mcpp.build.runner_lookup now reads a script's `#!` line as the kernel
reads it (parse_script_interpreter, script_interpreter): the interpreter
is the first word after `#!`, and through `env` the program is the
first word that is neither `-S` nor a `NAME=value` assignment. A form
it does not read with certainty (a relative interpreter, any other
`env` option, `env` with no program) names no program, so the note
never names the wrong one. Windows reads no `#!` line and is skipped.

missing_interpreter_note says, when the interpreter is not an
executable file or the program `env` would look up is on no directory
of the artefact's PATH, which program is missing, that a toolchain
payload names its runner in `.mcpp-toolchain.json` and one installed
before its recipe wrote that file names none, and the remedy:
`mcpp index update`, then `mcpp toolchain remove <spec>` and
`mcpp toolchain install <spec>`. It names no toolchain, because which
payload built a file is not a fact its first line holds.

`mcpp run` prints the note before it executes an artefact with no
runner and no execution host, against the PATH the artefact receives;
the blank line before the program's output now follows the composed
environment so the note stays above it. `mcpp test` prints it once per
build, for the first test it executes directly. Neither prints it for
`--print-launch`, and `mcpp test` not under `--message-format json`.

Tests: five RunnerLookup cases cover the parse (direct, `env`, `env -S`
with an assignment, CRLF), the forms that name no program, a missing
`env` program and a missing interpreter path, and the cases that stay
silent (a found interpreter, a binary, a missing file). docs/20 states
the note in both languages in place of "mcpp does not yet explain it".

Closes mcpp-community#621

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mcpp run: a script artefact whose interpreter is missing fails without naming the remedy

1 participant