feat: 一条依赖 + 一行 build.mcpp —— codegen 工具链由本包交给用户 (#3) #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| env: | |
| # Keep in step with the mcpp-index CI pin: this package's dependencies are | |
| # index packages, and they are validated against that same mcpp. | |
| # 2026.8.6.2 is the FLOOR, not a routine pin. Four things the codegen in | |
| # templates/ and examples/ is built on do not exist before it: | |
| # 2026.8.5.1 `tools = [...]` host tools; `mcpp:action=` build-graph nodes | |
| # 2026.8.5.2 a `host-module = true` rule package may use `import std;` and | |
| # `import mcpp;` — rules/ needs both, and before .5.2 it failed | |
| # with `module 'std' not found` / `module 'mcpp' not found` | |
| # 2026.8.6.2 `reexport = true`, which is what lets THIS package hand its | |
| # user the whole codegen toolchain — one dependency, not four — | |
| # and `rerun_if_changed_glob`, without which generate_all() | |
| # would not re-run when a .proto is ADDED (no declared file's | |
| # hash changes), silently never generating it | |
| MCPP_VERSION: "2026.8.6.2" | |
| jobs: | |
| build: | |
| name: ${{ matrix.name }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 120 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { name: "linux x86_64", os: ubuntu-latest, suffix: linux-x86_64, ext: tar.gz, mcpp: bin/mcpp } | |
| - { name: "macos arm64", os: macos-latest, suffix: macosx-arm64, ext: tar.gz, mcpp: bin/mcpp } | |
| # No windows leg: compat.openssl has no windows xpm entry yet, so | |
| # dependency resolution fails there before anything is compiled | |
| # ("E_NOT_FOUND: package 'compat:openssl@3.5.1' not found"). gRPC's | |
| # secure build cannot drop TLS, so this package is linux + macOS | |
| # until that package gains windows support. Re-add this line then — | |
| # the windows flags in mcpp.toml are already in place. | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download pinned mcpp | |
| shell: bash | |
| run: | | |
| base="https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}" | |
| archive="mcpp-${MCPP_VERSION}-${{ matrix.suffix }}.${{ matrix.ext }}" | |
| curl -L -fsS -o "$archive" "$base/$archive" | |
| if [ "${{ matrix.ext }}" = "zip" ]; then unzip -q "$archive"; else tar -xzf "$archive"; fi | |
| root="$PWD/mcpp-${MCPP_VERSION}-${{ matrix.suffix }}" | |
| if [ "${{ runner.os }}" = "Windows" ]; then | |
| echo "MCPP=$(cygpath -m "$root/${{ matrix.mcpp }}")" >> "$GITHUB_ENV" | |
| echo "MCPP_VENDORED_XLINGS=$(cygpath -m "$root/registry/bin/xlings")" >> "$GITHUB_ENV" | |
| else | |
| echo "MCPP=$root/${{ matrix.mcpp }}" >> "$GITHUB_ENV" | |
| echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV" | |
| fi | |
| # The dependencies are published index packages, and the snapshot the | |
| # mcpp release vendored is older than whatever landed since. | |
| - name: Refresh the published package index | |
| shell: bash | |
| env: | |
| MCPP_INDEX_MIRROR: GLOBAL | |
| run: | | |
| "$MCPP" index update | |
| # mcpp#344: object-path disambiguation keys on basename collisions across | |
| # the whole build dir, while the package cache key covers only the | |
| # dependency — one entry can hold two layouts. This graph has several | |
| # colliding basenames (abseil/protobuf `parser.cc`, abseil/gRPC | |
| # `status.cc`, `time.cc`), so the package cache is bypassed exactly as | |
| # mcpp-index's own CI does. Drop this once the pin reaches 2026.8.3.4. | |
| - name: Build the library and run the module test | |
| shell: bash | |
| env: | |
| MCPP_INDEX_MIRROR: GLOBAL | |
| MCPP_BUILD_CACHE: local | |
| run: | | |
| "$MCPP" --version | |
| "$MCPP" test | |
| # The long form: codegen spelled out by hand in build.mcpp. | |
| - name: helloworld example — a real RPC over loopback | |
| shell: bash | |
| working-directory: examples/helloworld | |
| env: | |
| MCPP_INDEX_MIRROR: GLOBAL | |
| MCPP_BUILD_CACHE: local | |
| run: | | |
| "$MCPP" run | |
| # The short form: the same program, with codegen from the `grpcgen` rule | |
| # package and a three-line build.mcpp. This example IS templates/greeter | |
| # instantiated, so building it is how the template gets tested — a broken | |
| # template would otherwise only be discovered by a user running | |
| # `mcpp new`. | |
| - name: greeter example — the template, via the rule package | |
| shell: bash | |
| working-directory: examples/greeter | |
| env: | |
| MCPP_INDEX_MIRROR: GLOBAL | |
| MCPP_BUILD_CACHE: local | |
| run: | | |
| "$MCPP" run | |
| package-versions-match: | |
| name: all three packages share one version | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # The plugin generates code that calls gRPC internals, so a plugin built | |
| # from a different release than the runtime being linked is exactly the | |
| # mismatch this whole design exists to make impossible. The rule package | |
| # names both of the others by version in what it tells users to write. | |
| # All three ship as separate index entries from ONE tag, so nothing but a | |
| # check keeps them equal. | |
| - name: versions must match | |
| shell: bash | |
| run: | | |
| lib=$(awk -F'"' '/^version/{print $2; exit}' mcpp.toml) | |
| plug=$(awk -F'"' '/^version/{print $2; exit}' plugin/mcpp.toml) | |
| rule=$(awk -F'"' '/^version/{print $2; exit}' rules/mcpp.toml) | |
| echo "grpc=$lib grpc-plugin=$plug grpcgen=$rule" | |
| rc=0 | |
| [ "$lib" = "$plug" ] || { echo "FAIL: grpc-plugin ($plug) != grpc ($lib)"; rc=1; } | |
| [ "$lib" = "$rule" ] || { echo "FAIL: grpcgen ($rule) != grpc ($lib)"; rc=1; } | |
| exit $rc | |
| template-matches-example: | |
| name: templates/greeter == examples/greeter | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # examples/greeter is the template instantiated; CI builds it, which is | |
| # the only thing that tests the template at all. That only holds while | |
| # the two do not drift, and build.mcpp is the file that matters — it is | |
| # pure code with no substitutions, so it must be byte-identical. | |
| - name: build.mcpp must be identical | |
| shell: bash | |
| run: | | |
| if ! diff -u templates/greeter/build.mcpp.in examples/greeter/build.mcpp; then | |
| echo "FAIL: the template and its example have drifted apart." | |
| echo " cp templates/greeter/build.mcpp.in examples/greeter/build.mcpp" | |
| exit 1 | |
| fi | |
| echo "template and example agree" | |
| manifest-matches-upstream: | |
| name: source list == upstream CMakeLists | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch the pinned gRPC tag | |
| run: | | |
| git clone -q --depth 1 -b v1.83.0 https://github.com/grpc/grpc.git /tmp/grpc | |
| # Proves mcpp.toml's source arrays are upstream's own list, not a | |
| # hand-curated one that has drifted. | |
| - name: tools/gen_sources.py --check | |
| run: python3 tools/gen_sources.py --grpc /tmp/grpc --check |