Skip to content

feat: a build program declares a runtime library directory; a passing check moves its stamp #701

Description

@Sunrisepeak

Motivation

A build program can link a prebuilt library (link_flag, link_search) and place a file beside the program (deploy), but it cannot say where the program's shared libraries are found at run time. The manifest key [runtime] library_dirs does exactly that — it reaches mcpp run's loader path and mcpp pack's closure search — but it is a fixed TOML array, and the directories in question are known only to the build program: a vcpkg prefix's bin/, a Qt SDK's bin/ resolved through mcpp::xpkg_dir.

Measured against the engine: mcpp pack's PE closure searches plan.runtimeLibraryDirs only (src/pack/pipeline.cppm), which is fed from [runtime] library_dirs and never from link_search/link_flag (src/build/plan.cppm). A plugin that installs a vcpkg prefix therefore has no way to make its DLLs reach mcpp run or the packed tree except one mcpp::deploy per file — and on a project's first build the files do not exist yet when the build program runs.

Found while implementing the same plugins: a role = "check" action whose command writes no stamp (the engine writes it, 2026.8.29.1+) re-runs on every build after one of its inputs changes. __action-stamp only creates a missing stamp and leaves an existing one alone, so after the input changes and the check passes again, the stamp stays older than the input forever.

Design

  1. mcpp::runtime_library_dir(const char* dir), wire mcpp:runtime-library-dir=<dir>, protocol 12: the build-program form of [runtime] library_dirs. Transform::AbsPath, Scope::LinkGlobal, persisted in the build-program cache. apply() folds it into RuntimeConfig::libraryDirs — the field the manifest key fills — so run, pack and the ELF/Mach-O rpath rendering treat it as they treat the manifest key. The root package's own directive is mirrored into the plan snapshot the way deploy already is.
  2. __action-stamp records each stamp's modification time before the command runs; on success it creates a missing stamp and moves an existing stamp it did not write to the present. A stamp the command created or rewrote is left alone, so wrapper scripts keep working.

Scope

src/build/hostprogram.cppm, modules/buildmcpp/src/{directives,program_protocol}.cppm, src/build/prepare.cppm, src/cli.cppm, docs/04 and docs/30 (en, zh), unit tests, e2e 779 and 780.

Consumer: mcpp-community/mcpp-plugins 0.13.0 (deps-vcpkg, deps-cmake, rules-qt).

Activity

  1. speak-agent commented on Sep 26, 2026

    @speak-agent
    Member

    Released in mcpp 2026.9.26.2 (#702, squash c109fdd6), in the form SPEC-007 (docs/specs/build-plugins.md, draft 0.2) states:

    • mcpp::runtime_search_dir(dir) (wire mcpp:runtime-search-dir=, protocol 12) is the build-program form of [runtime] runtime_search_dirs.
      • It joins LinkIntent::runtimeSearchDirs, so the existing readers see it: RUNPATH or rpath on ELF and Mach-O, mcpp run's loader path, mcpp pack's closure, and runtime validation.
      • A dependency's declaration reaches the consumer's executable.
      • The legacy [runtime] library_dirs gains no directive.
    • A passing check (or prepare) makes every stamp newer than every input. The engine creates a missing stamp and touches an existing one on success.
    • The new prepare role covers construction whose file names are unknown when the build program runs, such as installing a vcpkg or CMake prefix or unpacking an SDK.
      • The command populates the directory declared with a.output_dir(dir), and the engine writes the stamps.
      • The edge fails when that directory holds no file after success.
      • Compile edges of the declaring package and every link edge wait for it, and progress lines say PREPARE.
      • A build program whose rerun input lies inside a prepare directory is warned.
    • Roles are spelled with constants: mcpp::roles::{source, check, object, artifact, prepare}. An unknown role string is refused with the list; it used to be read as source.
    • On Windows, the link of a program whose plan has runtime search directories is followed by mcpp place-dlls. It places the DLLs the program imports from those directories beside it, so a program started by hand finds them.

    Readings:

    • e2e 780 fails on 2026.9.26.1 and passes on 2026.9.26.2.
    • 779, 790 to 793 pass on Linux; 794 passes on the Windows CI shards; 796 and 797 pass in the mingw-cross and wine job.
    • In the xlings sandbox, the published binary passes 779, 780 and 790 to 793. Against 2026.9.26.1 the same scripts fail.
    • mcpp-plugins' deps and rules-qt work, written against SPEC-007, needs its CI pin moved from "2026.9.27.1" to the released 2026.9.26.2.
  2. added a commit that references this issue on Sep 26, 2026
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