Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/alert.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ on:
- moq-relay
- Nightly
- release-brew
- Release C++
- Release Dart
- Release Dart FFI
- Release Go
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/cpp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: C++

# Builds and tests the moq C++ package (cpp/moq) with clang, outside Nix. `just
# check` already runs `just cpp check` with the dev shell's gcc; the dev shell
# has no clang++, and adding one would change which compiler every other recipe
# gets as `cc`. MSVC runs in nightly.yml, for the reason the Windows Rust check
# does: those runners are throttled too hard to gate every pull request.
#
# Outside Nix the generator comes from `cargo install` at the tag flake.nix
# pins; see the comment there for every other place that names it.

permissions:
contents: read

on:
pull_request:
# `closed` is here only so merging/closing a PR cancels its in-flight run
# via the concurrency group below; the job itself is skipped on close.
types: [opened, synchronize, reopened, closed]
paths:
- "cpp/moq/**"
- "cpp/justfile"
- "rs/moq-ffi/**"
- "rs/libmoq/native-libs/**"
- "doc/lib/cpp/**"
- "doc/lib/samples.sh"
- "Cargo.lock"
- ".github/workflows/cpp.yml"

concurrency:
group: cpp-${{ github.ref }}
cancel-in-progress: true

jobs:
clang:
name: C++ (clang)
if: github.event.action != 'closed'
runs-on: ubuntu-24.04
timeout-minutes: 60

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable

# Pinned: `--locked` fixes just's own dependencies, not which version of
# just cargo selects.
- name: Install just
run: cargo install --locked just@1.52.0

- name: Install uniffi-bindgen-cpp
run: cargo install uniffi-bindgen-cpp --locked --git https://github.com/kixelated/uniffi-bindgen-cpp --tag v0.11.0-kixelated.2+v0.32.2

- name: Check
run: just cpp check
env:
CXX: clang++
1 change: 1 addition & 0 deletions .github/workflows/interop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ on:
- "package.json"
# The Go client builds against the modules this script stages.
- "go/scripts/**"
- "cpp/moq/**"
- ".github/workflows/interop.yml"

concurrency:
Expand Down
42 changes: 42 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ jobs:
permissions:
contents: write

release-cpp:
name: Release C++
uses: ./.github/workflows/release-cpp.yml
permissions:
contents: write

release-moq-relay:
name: moq-relay
uses: ./.github/workflows/moq-relay.yml
Expand Down Expand Up @@ -309,6 +315,42 @@ jobs:
shell: bash
run: just rs windows

# The moq C++ package (cpp/moq) under MSVC, with exceptions and RTTI off. cpp.yml covers clang on pull requests and `just check` covers gcc; this
# is the Windows half, nightly for the same runner cost as `windows`.
cpp-windows:
name: C++ (MSVC)
runs-on: windows-latest
timeout-minutes: 60

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable

# aws-lc-rs assembles its x86_64 crypto with NASM on Windows.
- name: Install NASM
shell: pwsh
run: |
choco install nasm -y --no-progress
"C:\Program Files\NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Install just
shell: bash
run: cargo install --locked just@1.52.0

# The tag flake.nix pins; see the comment there.
- name: Install uniffi-bindgen-cpp
shell: bash
run: cargo install uniffi-bindgen-cpp --locked --git https://github.com/kixelated/uniffi-bindgen-cpp --tag v0.11.0-kixelated.2+v0.32.2

- name: Check
shell: bash
run: just cpp check

# `just rs macos` is the only thing that compiles moq-video's VideoToolbox
# encode/decode and its ScreenCaptureKit / AVFoundation capture, plus
# moq-audio's ScreenCaptureKit system audio and its TCC permission pre-check.
Expand Down
111 changes: 111 additions & 0 deletions .github/workflows/release-cpp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Release C++

# Builds the moq C++ package (cpp/moq) for every target and publishes one archive per
# target to a cpp-v<version> GitHub release. The vcpkg and Conan packages fetch these.

on:
push:
tags:
- "cpp-v*"
# Dry-run: build everything, publish nothing. Nightly calls every release
# workflow this way so a broken build surfaces before the tag is cut.
workflow_call:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: Build (${{ matrix.target }})
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-pc-windows-msvc
os: windows-latest

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable

# aws-lc-rs assembles its x86_64 crypto with NASM on Windows.
- name: Install NASM
if: runner.os == 'Windows'
shell: pwsh
run: |
choco install nasm -y --no-progress
"C:\Program Files\NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

# The tag flake.nix pins; see the comment there.
- name: Install uniffi-bindgen-cpp
shell: bash
run: cargo install uniffi-bindgen-cpp --locked --git https://github.com/kixelated/uniffi-bindgen-cpp --tag v0.11.0-kixelated.2+v0.32.2

# The package version lives in cpp/moq/VERSION; a tag that disagrees is a mistake.
- name: Check version
if: github.ref_type == 'tag'
shell: bash
env:
TAG: ${{ github.ref_name }}
run: |
version=$(tr -d '[:space:]' < cpp/moq/VERSION)
if [[ "$TAG" != "cpp-v$version" ]]; then
echo "::error::tag $TAG does not match cpp/moq/VERSION ($version)"
exit 1
fi

- name: Build and package
shell: bash
env:
TARGET: ${{ matrix.target }}
run: ./cpp/moq/build.sh --target "$TARGET" --output dist

- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: moq-cpp-${{ matrix.target }}
path: dist/*

release:
name: Release
needs: build
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Find previous tag
id: prev_tag
run: .github/scripts/release.sh prev-tag cpp

- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: artifacts
merge-multiple: true

- name: Create or update release
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.ref_name }}
RELEASE_PREV_TAG: ${{ steps.prev_tag.outputs.tag }}
run: RELEASE_TITLE="moq C++ v${RELEASE_TAG#cpp-v}" .github/scripts/release.sh create artifacts
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ These diff the branch against its base and only run the affected packages.

| Change in | Also update |
|---|---|
| `rs/moq-ffi` | `rs/libmoq`, `{py,swift,kt,dart}/`, `go/wrapper/moq/*.go` (the `go/ffi` and `dart/moq_ffi` bindings regenerate automatically, but a new method needs a hand-written wrapper too, like `py/moq-rs` or `dart/moq`), `doc/lib/{py,swift,kt,go,dart,c}` |
| `rs/moq-ffi` | `rs/libmoq`, `{py,swift,kt,dart}/`, `go/wrapper/moq/*.go` (the `go/ffi` and `dart/moq_ffi` bindings regenerate automatically, but a new method needs a hand-written wrapper too, like `py/moq-rs` or `dart/moq`), `cpp/moq`, `doc/lib/{py,swift,kt,go,dart,c,cpp}` |
| `rs/moq-net` wire/API | `js/net`, `doc/concept`, `drafts/draft-lcurley-moq-lite.md` (if the wire spec changes) |
| `rs/hang` catalog/container | `js/hang`, `doc/concept`, `drafts/draft-lcurley-moq-hang.md` (if the format spec changes) |
| `rs/moq-token` | `js/token` |
Expand Down
79 changes: 79 additions & 0 deletions cpp/justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env just --justfile
#
# The moq C++ package over rs/moq-ffi. Invoked from the repo root as `just cpp <recipe>` via
# the `mod cpp` import. The OBS plugin has its own module, `just obs`.

set working-directory := '.'

default:
just check

# Takes an optional newline-separated list of changed files and skips when none
# are in scope; `just cpp check` (no FILES) always runs. CXX picks the compiler
# on Unix; Windows uses MSVC.

# Build and install cpp/moq, then build the probe against the installed package at C++17 and
# C++23 through CMake, and at C++17 through pkg-config, and run each. Also compiles the doc samples.
check $FILES="":
#!/usr/bin/env bash
set -euo pipefail
if [[ -n "$FILES" ]] && ! grep -qE '^(cpp/moq/|cpp/justfile$|rs/moq-ffi/|rs/libmoq/native-libs/|doc/lib/cpp/|doc/lib/samples\.sh$)' <<< "$FILES"; then
echo "cpp: no C++ package changes; skipping."
exit 0
fi
if ! command -v uniffi-bindgen-cpp >/dev/null 2>&1; then
echo "cpp check: uniffi-bindgen-cpp not on PATH, skipping" >&2
echo " install: cargo install uniffi-bindgen-cpp --locked --git https://github.com/kixelated/uniffi-bindgen-cpp --tag v0.11.0-kixelated.2+v0.32.2" >&2
exit 0
fi

# Single-config generators build Debug. Visual Studio ignores CMAKE_BUILD_TYPE and gets
# --config Release, since the Rust staticlib links the release CRT (/MD) either way.
build=moq/build
prefix="$PWD/$build/prefix"
cmake -S moq -B "$build/package" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_LIBDIR=lib
cmake --build "$build/package" --config Release
rm -rf "$prefix"
cmake --install "$build/package" --config Release --prefix "$prefix"

# Every generated moq::MoqFoo needs its moq::Foo alias in the wrapper.
missing=$(comm -23 \
<(sed -nE 's/^(struct|enum class) Moq([A-Za-z0-9]+);$/\2/p' "$prefix/include/moq/ffi/moq.hpp" | sort -u) \
<(sed -nE 's/^using ([A-Za-z0-9]+) = Moq\1;$/\1/p' moq/include/moq/moq.hpp | sort -u))
if [[ -n "$missing" ]]; then
echo "cpp check: cpp/moq/include/moq/moq.hpp lacks an alias for:" $missing >&2
exit 1
fi

run() {
if [[ -x "$1/probe" ]]; then "$1/probe"; else "$1/Release/probe.exe"; fi
}
for std in 17 23; do
cmake -S moq/test -B "$build/test-$std" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD="$std" -DCMAKE_PREFIX_PATH="$prefix"
cmake --build "$build/test-$std" --config Release
run "$build/test-$std"
done

# The samples in doc/lib/cpp compile against the installed headers.
bash ../doc/lib/samples.sh cpp ../doc/lib/cpp/index.md >"$build/doc-samples.cpp"
if [[ "$(uname -s)" != MINGW* && "$(uname -s)" != MSYS* ]]; then
"${CXX:-c++}" -std=c++17 -fsyntax-only -Wall -Werror -include moq/test/doc-samples.hpp \
-I"$prefix/include" "$build/doc-samples.cpp"
fi

if command -v pkg-config >/dev/null 2>&1; then
export PKG_CONFIG_PATH="$prefix/lib/pkgconfig"
mkdir -p "$build/pkg-config"
# shellcheck disable=SC2046 # pkg-config output is a flag list.
"${CXX:-c++}" -std=c++17 -o "$build/pkg-config/probe" moq/test/probe.cpp \
$(pkg-config --variable=sources moq-cpp) $(pkg-config --cflags --libs moq-cpp)
run "$build/pkg-config"
fi

# Build the release tarball for the host into cpp/moq/dist.
package:
moq/build.sh --output moq/dist

# Remove the package builds.
clean:
rm -rf moq/build moq/dist
2 changes: 2 additions & 0 deletions cpp/moq/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# `just cpp check` builds, installs, and tests here.
/build/
Loading
Loading