22# moq-interop Makefile
33# =============================================================================
44#
5- # A single command builds the moq-interop test suite anywhere Docker
6- # is available — no local C++ toolchain required.
5+ # Builds and runs the moq-interop test suite entirely inside Docker —
6+ # no local C++ toolchain required.
77#
88# Targets
9- # build Build (or rebuild) the moq-interop Docker image.
10- # tests Run the interop tests against RELAY_URL.
11- # conformance Run moxygen moqtest conformance tests against CONFORMANCE_URL.
9+ # build Build the moq-interop Docker image (skip if already present).
10+ # build-force Unconditionally rebuild the image.
11+ # tests Run the interop test binary against a live relay.
12+ # conformance Run moxygen's conformance_test.sh against a relay.
1213# shell Open an interactive shell inside the container.
1314# clean Remove the local Docker image.
1415# push Tag and push the image to REGISTRY/IMAGE:TAG.
1516# help Print this help text.
1617#
18+ # Build overview
19+ # The Dockerfile uses a two-stage build:
20+ # builder — Ubuntu 22.04 + GCC 11; compiles moxygen and all Meta OSS
21+ # dependencies (folly, fizz, wangle, mvfst, proxygen) via
22+ # getdeps.py into a deterministic scratch directory
23+ # (/var/cache/getdeps inside the container), then compiles
24+ # the interop_tests binary.
25+ # runtime — Minimal Ubuntu 22.04; contains only the statically-linked
26+ # interop_tests binary and optional conformance tooling.
27+ #
28+ # The getdeps compile (folly/fizz/wangle/mvfst/proxygen/moxygen) takes
29+ # 30–60 minutes on a cold build. BuildKit caches the result in a
30+ # persistent cache volume (id=moq-interop-getdeps-v2) so subsequent
31+ # builds only recompile what changed in the interop tests source.
32+ #
1733# Common variables (override on the command line)
1834# IMAGE Local image name (default: moq-interop)
1935# TAG Image tag (default: latest)
20- # REGISTRY Registry prefix (default: empty)
36+ # REGISTRY Registry prefix for 'push' (default: empty)
2137# RELAY_URL Relay URL used by 'tests' (default: https://localhost:4433/moq)
22- # TESTS_ARGS Extra flags for interop_tests (default: empty)
38+ # TESTS_ARGS Extra flags passed to interop_tests (default: empty)
2339# WITH_CONFORMANCE Include conformance tooling (0/1) (default: 1)
2440# CONFORMANCE_URL Relay URL used by 'conformance' (default: http://localhost:9999)
2541# CONFORMANCE_ARGS Extra args for conformance_test.sh (default: empty)
42+ # DOCKER_BUILD_FLAGS Extra flags passed to docker build (default: empty)
43+ #
44+ # localhost rewriting
45+ # localhost and 127.0.0.1 in RELAY_URL and CONFORMANCE_URL are
46+ # automatically rewritten to host.docker.internal so the container can
47+ # reach services running on the host. On Linux the --add-host flag is
48+ # added automatically; on macOS Docker Desktop provides the alias natively.
2649#
2750# Examples
2851# make build
52+ # make build-force DOCKER_BUILD_FLAGS="--progress=plain"
53+ # make build WITH_CONFORMANCE=0
2954# make tests RELAY_URL=https://relay.example.com:4433/moq
30- # make tests RELAY_URL=https://localhost:9668/moq-relay # localhost auto-rewritten
55+ # make tests RELAY_URL=https://localhost:9668/moq-relay
3156# make tests TESTS_ARGS="--categories=Publisher,Subscriber"
57+ # make tests TESTS_ARGS="--tests=PublishTest"
3258# make conformance CONFORMANCE_URL=http://relay.example.com:9999
33- # make conformance CONFORMANCE_ARGS="16" # restrict to MoQT version 16
34- # make build WITH_CONFORMANCE=0 # omit conformance tooling
35- # make push REGISTRY=ghcr.io/myorg TAG=v1.2.3
36- # make build DOCKER_BUILD_FLAGS="--progress=plain" # verbose build log
59+ # make conformance CONFORMANCE_ARGS="16"
60+ # make push REGISTRY=ghcr.io/myorg TAG=v1.2.3
3761# =============================================================================
3862
3963# ── Image coordinates ────────────────────────────────────────────────────────────────────────────
@@ -52,25 +76,30 @@ RELAY_URL ?= https://localhost:4433/moq
5276TESTS_ARGS ?=
5377
5478# Rewrite localhost / 127.0.0.1 → host.docker.internal so the container can
55- # reach a relay running on the host machine . On macOS Docker Desktop
56- # host.docker.internal is provided automatically; the --add-host flag below
57- # makes it work on Linux as well .
79+ # reach a relay running on the host. Docker Desktop on macOS provides the
80+ # alias automatically; on Linux the --add-host=host.docker.internal:host-gateway
81+ # flag (added on the docker run line) creates it .
5882RELAY_URL_DOCKER := $(subst 127.0.0.1,host.docker.internal,$(subst localhost,host.docker.internal,$(RELAY_URL ) ) )
5983
6084# ── Conformance test parameters ───────────────────────────────────────────────────────
61- # WITH_CONFORMANCE=1 (default) stages moqtest_client + conformance_test.sh in
62- # the image. Set to 0 to build a smaller image without conformance tooling.
85+ # WITH_CONFORMANCE=1 (default) builds and stages moqtest_client and
86+ # conformance_test.sh inside the image, enabling the 'conformance' target.
87+ # Set to 0 (make build WITH_CONFORMANCE=0) for a smaller image that only
88+ # contains interop_tests.
6389WITH_CONFORMANCE ?= 1
6490CONFORMANCE_URL ?= http://localhost:9999
6591CONFORMANCE_ARGS ?=
6692
6793CONFORMANCE_URL_DOCKER := $(subst 127.0.0.1,host.docker.internal,$(subst localhost,host.docker.internal,$(CONFORMANCE_URL ) ) )
6894
6995# ── Build parameters ────────────────────────────────────────────────────────────────────────────
70- # Auto-detect CPU count from the host so getdeps can parallelise its build.
96+ # CPU count forwarded to getdeps and ninja via the NPROC build-arg .
7197NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)
7298
73- # Pass --progress=plain here to get verbose (non-TTY) Docker build output.
99+ # Extra flags forwarded verbatim to docker build.
100+ # Useful values:
101+ # --progress=plain verbose, non-TTY output (good for CI / log files)
102+ # --no-cache force a completely clean rebuild
74103DOCKER_BUILD_FLAGS ?=
75104
76105# ── Paths ─────────────────────────────────────────────────────────────────────────────────────
@@ -79,21 +108,42 @@ BUILD_CTX := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
79108DOCKERFILE := $(BUILD_CTX ) /docker/Dockerfile
80109
81110DOCKER := docker
82- # BuildKit is required for --mount=type=cache in the Dockerfile.
83- # It is the default builder since Docker 23.x; this export ensures it is
84- # active on any Docker version that supports it.
111+ # BuildKit is required for --mount=type=cache in the Dockerfile, which
112+ # persists the getdeps build tree (folly/fizz/wangle/mvfst/proxygen/moxygen)
113+ # across builds in a named cache volume (id=moq-interop-getdeps-v2).
114+ # BuildKit is the default backend since Docker 23.x; this export ensures it
115+ # is active on older Docker versions as well.
85116export DOCKER_BUILDKIT := 1
86117
87118# ── Phony declarations ────────────────────────────────────────────────────────────────────────
88- .PHONY : all build tests conformance shell clean push help
119+ .PHONY : all build build-force tests conformance shell clean push help
89120
90121all : tests
91122
92123# ── build ─────────────────────────────────────────────────────────────────────────────
93- # The build context is moq-interop/ (this directory). .dockerignore in the
94- # same directory excludes heavy artefacts (.scratch/, build/ dirs, etc.) so
95- # only source files are transferred to the Docker daemon .
124+ # Builds the image only if it does not already exist locally.
125+ # Skips the build entirely when the image is already present — use
126+ # 'make build-force' to rebuild, or 'make clean && make build' to start fresh .
96127build :
128+ @if [ -z " $$ ($( DOCKER) images -q $( IMAGE_REF) 2>/dev/null)" ]; then \
129+ echo " ==> Image $( IMAGE_REF) not found — building..." ; \
130+ $(DOCKER ) build \
131+ $(DOCKER_BUILD_FLAGS ) \
132+ --build-arg NPROC=$(NPROC ) \
133+ --build-arg WITH_CONFORMANCE=$(WITH_CONFORMANCE ) \
134+ -t $(IMAGE_REF ) \
135+ -f $(DOCKERFILE ) \
136+ $(BUILD_CTX ) ; \
137+ else \
138+ echo " ==> Image $( IMAGE_REF) already exists — skipping build. Use 'make build-force' to rebuild." ; \
139+ fi
140+
141+ # ── build-force ───────────────────────────────────────────────────────────────────────
142+ # Unconditionally rebuilds the Docker image. Docker layer caches and the
143+ # BuildKit getdeps volume are still reused when available, so only layers
144+ # that changed since the last build are recompiled. Pass
145+ # DOCKER_BUILD_FLAGS=--no-cache to force a completely clean rebuild.
146+ build-force :
97147 $(DOCKER ) build \
98148 $(DOCKER_BUILD_FLAGS ) \
99149 --build-arg NPROC=$(NPROC ) \
@@ -104,35 +154,49 @@ build:
104154
105155
106156# ── tests ─────────────────────────────────────────────────────────────────────────────
107- # Runs the interop tests against a relay at RELAY_URL.
108- # localhost/127.0.0.1 are automatically rewritten to host.docker.internal so
109- # the container can reach a relay running on the host machine.
110- # The relay must already be running before invoking this target.
157+ # Runs interop_tests inside the container against a relay at RELAY_URL.
158+ # The relay must be running before invoking this target.
159+ # localhost/127.0.0.1 in RELAY_URL are automatically rewritten to
160+ # host.docker.internal so the container can reach the host relay.
161+ # Use TESTS_ARGS to pass additional flags to interop_tests, e.g.:
162+ # make tests TESTS_ARGS="--tests=PublishTest"
163+ # make tests TESTS_ARGS="--categories=Publisher,Subscriber"
164+ # make tests TESTS_ARGS="--list"
111165tests : build
112166 $(DOCKER ) run --rm \
113167 --name moq-interop-tests \
114168 --add-host=host.docker.internal:host-gateway \
115169 $(IMAGE_REF ) --relay=$(RELAY_URL_DOCKER ) $(TESTS_ARGS )
116170
117171# ── interactive shell ───────────────────────────────────────────────────────────────
172+ # Opens a bash shell in the runtime container. Useful for ad-hoc inspection
173+ # or running interop_tests with custom arguments.
118174shell : build
119175 $(DOCKER ) run --rm -it \
120176 --name moq-interop-shell \
121177 --add-host=host.docker.internal:host-gateway \
122- $(IMAGE_REF ) /bin/bash
178+ --entrypoint /bin/bash \
179+ $(IMAGE_REF )
123180
124181# ── clean ─────────────────────────────────────────────────────────────────────────────────────
182+ # Removes the local Docker image. Does NOT prune the BuildKit cache volume
183+ # (moq-interop-getdeps-v2); to wipe that too run:
184+ # docker buildx prune --filter type=exec.cachemount --force
125185clean :
126186 $(DOCKER ) rmi -f $(IMAGE_REF ) 2> /dev/null || true
127187
128188# ── push ──────────────────────────────────────────────────────────────────────────────────────
189+ # Pushes the image to REGISTRY/IMAGE:TAG. REGISTRY must be set.
190+ # Example: make push REGISTRY=ghcr.io/myorg TAG=v1.2.3
129191push : build
130192 $(DOCKER ) push $(IMAGE_REF )
131193
132194# ── conformance ───────────────────────────────────────────────────────────────────────────────
133- # Runs moxygen's conformance_test.sh against CONFORMANCE_URL.
134- # The image must have been built with WITH_CONFORMANCE=1 (the default).
135- # The relay/server must already be running before invoking this target.
195+ # Runs moxygen's conformance_test.sh inside the container against CONFORMANCE_URL.
196+ # Requires the image to have been built with WITH_CONFORMANCE=1 (the default).
197+ # The relay must be running before invoking this target.
198+ # CONFORMANCE_ARGS is passed verbatim to conformance_test.sh — for example,
199+ # pass "16" to restrict testing to MoQT draft-16.
136200conformance : build
137201 @if [ " $( WITH_CONFORMANCE) " = " 0" ]; then \
138202 echo " Error: image built without conformance tooling (WITH_CONFORMANCE=0)." >&2 ; \
@@ -148,9 +212,10 @@ conformance: build
148212# ── help ──────────────────────────────────────────────────────────────────────────────────────
149213help :
150214 @printf ' \nmoq-interop — available make targets\n\n'
151- @printf ' %-14s %s\n' build ' Build (or rebuild) the Docker image'
152- @printf ' %-14s %s\n' tests ' Run the interop tests against RELAY_URL'
153- @printf ' %-14s %s\n' conformance ' Run moxygen moqtest conformance tests against CONFORMANCE_URL'
215+ @printf ' %-14s %s\n' build ' Build image only if it does not already exist locally'
216+ @printf ' %-14s %s\n' build-force ' Unconditionally rebuild the Docker image'
217+ @printf ' %-14s %s\n' tests ' Run the interop tests (auto-builds if image absent)'
218+ @printf ' %-14s %s\n' conformance ' Run moxygen conformance tests against CONFORMANCE_URL'
154219 @printf ' %-14s %s\n' shell ' Open an interactive shell in the container'
155220 @printf ' %-14s %s\n' clean ' Remove the local Docker image'
156221 @printf ' %-14s %s\n' push ' Push the image to REGISTRY/IMAGE:TAG'
@@ -169,12 +234,14 @@ help:
169234 @printf ' %-28s %s\n' NPROC ' $(NPROC)'
170235 @printf ' \nExamples\n\n'
171236 @printf ' make build\n'
237+ @printf ' make build-force DOCKER_BUILD_FLAGS="--progress=plain"\n'
238+ @printf ' make build WITH_CONFORMANCE=0\n'
172239 @printf ' make tests RELAY_URL=https://relay.example.com:4433/moq\n'
173240 @printf ' make tests RELAY_URL=https://localhost:9668/moq-relay\n'
174241 @printf ' make tests TESTS_ARGS="--categories=Publisher,Subscriber"\n'
242+ @printf ' make tests TESTS_ARGS="--tests=PublishTest"\n'
243+ @printf ' make tests TESTS_ARGS="--list"\n'
175244 @printf ' make conformance CONFORMANCE_URL=http://relay.example.com:9999\n'
176245 @printf ' make conformance CONFORMANCE_ARGS="16"\n'
177- @printf ' make build WITH_CONFORMANCE=0\n'
178- @printf ' make push REGISTRY=ghcr.io/myorg TAG=v1.2.3\n'
179- @printf ' make build DOCKER_BUILD_FLAGS="--progress=plain"\n'
246+ @printf ' make push REGISTRY=ghcr.io/myorg TAG=v1.2.3\n'
180247 @printf ' \n'
0 commit comments