1+ .PHONY : help install format format-check lint lint-fix check type-check clean build \
2+ build-rtc download-ffi status doctor
3+
4+ # Colors for output
5+ CYAN := \033[36m
6+ GREEN := \033[32m
7+ YELLOW := \033[33m
8+ RED := \033[31m
9+ RESET := \033[0m
10+ BOLD := \033[1m
11+
12+ # Paths (computed as absolute paths)
13+ MAKEFILE_DIR := $(shell pwd)
14+ PYTHON_RTC := $(MAKEFILE_DIR ) /livekit-rtc
15+ PYTHON_API := $(MAKEFILE_DIR ) /livekit-api
16+ PYTHON_PROTOCOL := $(MAKEFILE_DIR ) /livekit-protocol
17+ RUST_SUBMODULE := $(MAKEFILE_DIR ) /livekit-rtc/rust-sdks
18+
19+ # Platform and architecture auto-detection
20+ ARCH := $(shell uname -m)
21+ OS := $(shell uname -s | tr A-Z a-z)
22+
23+ # Default target
24+ .DEFAULT_GOAL := help
25+
26+ help : # # Show this help message
27+ @echo " $( BOLD) $( CYAN) Available targets:$( RESET) "
28+ @echo " "
29+ @echo " $( BOLD) Development Workflows:$( RESET) "
30+ @grep -E ' ^(build-rtc|download-ffi|status|doctor):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
31+ @echo " "
32+ @echo " $( BOLD) Code Quality:$( RESET) "
33+ @grep -E ' ^(format|format-check|lint|lint-fix|type-check|check):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
34+ @echo " "
35+ @echo " $( BOLD) Other:$( RESET) "
36+ @grep -E ' ^(install|clean|build):.*?## .*$$' $(MAKEFILE_LIST ) | awk ' BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'
37+
38+ install : # # Install all dependencies with dev extras
39+ @echo " $( BOLD) $( CYAN) Installing dependencies...$( RESET) "
40+ @uv sync --all-extras --dev
41+ @echo " $( BOLD) $( GREEN) ✓ Dependencies installed$( RESET) "
42+
43+ format : # # Format code with ruff
44+ @echo " $( BOLD) $( CYAN) Formatting code...$( RESET) "
45+ @uv run ruff format .
46+ @echo " $( BOLD) $( GREEN) ✓ Code formatted$( RESET) "
47+
48+ format-check : # # Check code formatting without making changes
49+ @echo " $( BOLD) $( CYAN) Checking code formatting...$( RESET) "
50+ @if uv run ruff format --check . ; then \
51+ echo " $( BOLD) $( GREEN) ✓ Code formatting is correct$( RESET) " ; \
52+ else \
53+ echo " $( BOLD) $( RED) ✗ Code formatting issues found. Run 'make format' to fix.$( RESET) " ; \
54+ exit 1; \
55+ fi
56+
57+ lint : # # Run ruff linter
58+ @echo " $( BOLD) $( CYAN) Running linter...$( RESET) "
59+ @if uv run ruff check . ; then \
60+ echo " $( BOLD) $( GREEN) ✓ No linting issues found$( RESET) " ; \
61+ else \
62+ echo " $( BOLD) $( RED) ✗ Linting issues found$( RESET) " ; \
63+ exit 1; \
64+ fi
65+
66+ lint-fix : # # Run ruff linter and fix issues automatically
67+ @echo " $( BOLD) $( CYAN) Running linter with auto-fix...$( RESET) "
68+ @uv run ruff check --fix .
69+ @echo " $( BOLD) $( GREEN) ✓ Linting complete$( RESET) "
70+
71+ type-check : # # Run mypy type checker
72+ @echo " $( BOLD) $( CYAN) Running type checker...$( RESET) "
73+ @uv pip install pip 2> /dev/null || true
74+ @if uv run mypy --install-types --non-interactive \
75+ -p livekit.rtc \
76+ -p livekit.api \
77+ -p livekit.protocol; then \
78+ echo " $( BOLD) $( GREEN) ✓ Type checking passed$( RESET) " ; \
79+ else \
80+ echo " $( BOLD) $( RED) ✗ Type checking failed$( RESET) " ; \
81+ exit 1; \
82+ fi
83+
84+ check : format-check lint type-check # # Run all checks (format, lint, type-check)
85+ @echo " $( BOLD) $( GREEN) ✓ All checks passed!$( RESET) "
86+
87+ # ============================================
88+ # Development Workflows
89+ # ============================================
90+
91+ download-ffi : # # Download pre-built FFI artifacts for livekit-rtc
92+ @echo " $( BOLD) $( CYAN) 📦 Downloading FFI artifacts...$( RESET) "
93+ @set -e; \
94+ DETECTED_ARCH=" $( ARCH) " ; \
95+ DETECTED_OS=" $( OS) " ; \
96+ if [ " $$ DETECTED_ARCH" = " aarch64" ]; then \
97+ PLATFORM_ARCH=" arm64" ; \
98+ else \
99+ PLATFORM_ARCH=" $$ DETECTED_ARCH" ; \
100+ fi ; \
101+ if [ " $$ DETECTED_OS" = " darwin" ]; then \
102+ PLATFORM_OS=" macos" ; \
103+ else \
104+ PLATFORM_OS=" $$ DETECTED_OS" ; \
105+ fi ; \
106+ echo " $( CYAN) Platform: $$ PLATFORM_OS-$$ PLATFORM_ARCH$( RESET) " ; \
107+ cd $(PYTHON_RTC ) && python rust-sdks/download_ffi.py --platform " $$ PLATFORM_OS" --arch " $$ PLATFORM_ARCH" --output livekit/rtc/resources; \
108+ echo " $( BOLD) $( GREEN) ✅ FFI artifacts downloaded$( RESET) "
109+
110+ build-rtc : # # Build livekit-ffi from local rust-sdks and generate proto
111+ @echo " $( BOLD) $( CYAN) 🦀 Building livekit-ffi from source...$( RESET) "
112+ @set -e; \
113+ if [ ! -d " $( RUST_SUBMODULE) " ]; then \
114+ echo " $( BOLD) $( RED) ✗ Error: rust-sdks submodule not found at $( RUST_SUBMODULE) $( RESET) " ; \
115+ exit 1; \
116+ fi ; \
117+ echo " $( CYAN) 🦀 Building livekit-ffi...$( RESET) " ; \
118+ cd $(RUST_SUBMODULE ) && cargo build --release -p livekit-ffi; \
119+ echo " $( CYAN) 📝 Generating protobuf FFI protocol...$( RESET) " ; \
120+ cd $(PYTHON_RTC ) && ./generate_proto.sh; \
121+ RUST_LIB_DIR=" $$ (cd $( RUST_SUBMODULE) && pwd)/target/release" ; \
122+ if [ " $( OS) " = " darwin" ]; then \
123+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/liblivekit_ffi.dylib" ; \
124+ elif [ " $( OS) " = " linux" ]; then \
125+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/liblivekit_ffi.so" ; \
126+ else \
127+ RUST_LIB_PATH=" $$ RUST_LIB_DIR/livekit_ffi.dll" ; \
128+ fi ; \
129+ echo " $( BOLD) $( GREEN) ✅ Built livekit-ffi from source$( RESET) " ; \
130+ echo " " ; \
131+ echo " $( BOLD) $( YELLOW) 📋 To use the local rust lib, export the following:$( RESET) " ; \
132+ echo " $( BOLD) export LIVEKIT_LIB_PATH=$$ RUST_LIB_PATH$( RESET) "
133+
134+ status : # # Show current development environment status
135+ @echo " $( BOLD) $( CYAN) 📍 Current status:$( RESET) "
136+ @echo " "
137+ @set -e; \
138+ echo " $( BOLD) 📦 Packages:$( RESET) " ; \
139+ for pkg in livekit livekit-api livekit-protocol; do \
140+ SHOW_OUTPUT=$$(uv pip show $$pkg 2>/dev/null || echo "" ) ; \
141+ if [ -z " $$ SHOW_OUTPUT" ]; then \
142+ echo " $$ pkg: NOT INSTALLED" ; \
143+ elif echo " $$ SHOW_OUTPUT" | grep -q " Editable project location:" ; then \
144+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
145+ LOCATION=$$(echo "$$SHOW_OUTPUT" | grep "Editable project location:" | cut -d' ' -f4- ) ; \
146+ echo " $$ pkg: LOCAL (editable) v$$ VERSION" ; \
147+ echo " path: $$ LOCATION" ; \
148+ else \
149+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
150+ echo " $$ pkg: PyPI v$$ VERSION" ; \
151+ fi ; \
152+ done ; \
153+ echo " " ; \
154+ echo " $( BOLD) 🦀 FFI Status:$( RESET) " ; \
155+ if [ -n " $$ LIVEKIT_LIB_PATH" ]; then \
156+ if [ -f " $$ LIVEKIT_LIB_PATH" ]; then \
157+ echo " FFI: CUSTOM (from LIVEKIT_LIB_PATH env var)" ; \
158+ echo " path: $$ LIVEKIT_LIB_PATH" ; \
159+ else \
160+ echo " FFI: CUSTOM (LIVEKIT_LIB_PATH set but file not found)" ; \
161+ echo " path: $$ LIVEKIT_LIB_PATH" ; \
162+ fi ; \
163+ else \
164+ FFI_PATH=" $( PYTHON_RTC) /livekit/rtc/resources" ; \
165+ if [ -d " $$ FFI_PATH" ] && { [ -f " $$ FFI_PATH/liblivekit_ffi.dylib" ] || [ -f " $$ FFI_PATH/liblivekit_ffi.so" ] || [ -f " $$ FFI_PATH/livekit_ffi.dll" ]; }; then \
166+ RUST_SUBMODULE_DIR=" $$ (cd $( RUST_SUBMODULE) 2>/dev/null && pwd || echo " " )" ; \
167+ CARGO_TOML_PATH=" $$ RUST_SUBMODULE_DIR/livekit-ffi/Cargo.toml" ; \
168+ if [ -f " $$ CARGO_TOML_PATH" ]; then \
169+ FFI_VERSION=$$(grep '^version = ' "$$CARGO_TOML_PATH" | head -1 | sed 's/.*"\(.*\ ) " .*/\1/'); \
170+ echo " FFI: PRE-BUILT ARTIFACTS (v$$ FFI_VERSION)" ; \
171+ else \
172+ echo " FFI: PRE-BUILT ARTIFACTS" ; \
173+ fi ; \
174+ else \
175+ echo " FFI: NOT AVAILABLE (run 'make download-ffi')" ; \
176+ fi ; \
177+ fi
178+
179+ doctor : # # Check development environment health
180+ @echo " $( BOLD) $( CYAN) 🏥 Running diagnostics...$( RESET) "
181+ @echo " "
182+ @ISSUES=0; \
183+ echo " $( BOLD) 📦 Required Tools:$( RESET) " ; \
184+ if command -v uv & > /dev/null; then \
185+ UV_VERSION=$$(uv --version 2>&1 | head -1 ) ; \
186+ echo " ✓ uv: $$ UV_VERSION" ; \
187+ else \
188+ echo " ✗ uv: NOT FOUND" ; \
189+ ISSUES=$$((ISSUES + 1 ) ); \
190+ fi ; \
191+ if command -v python & > /dev/null; then \
192+ PYTHON_VERSION=$$(python --version 2>&1 ) ; \
193+ echo " ✓ python: $$ PYTHON_VERSION" ; \
194+ else \
195+ echo " ✗ python: NOT FOUND" ; \
196+ ISSUES=$$((ISSUES + 1 ) ); \
197+ fi ; \
198+ if command -v cargo & > /dev/null; then \
199+ CARGO_VERSION=$$(cargo --version 2>&1 ) ; \
200+ echo " ✓ cargo: $$ CARGO_VERSION" ; \
201+ else \
202+ echo " ⚠ cargo: NOT FOUND (required for 'make build-rtc')" ; \
203+ fi ; \
204+ if command -v git & > /dev/null; then \
205+ GIT_VERSION=$$(git --version 2>&1 ) ; \
206+ echo " ✓ git: $$ GIT_VERSION" ; \
207+ else \
208+ echo " ✗ git: NOT FOUND" ; \
209+ ISSUES=$$((ISSUES + 1 ) ); \
210+ fi ; \
211+ echo " " ; \
212+ echo " $( BOLD) 📂 Repository Structure:$( RESET) " ; \
213+ REPO_ROOT=$$(cd $(MAKEFILE_DIR ) && git rev-parse --show-toplevel 2>/dev/null || echo "" ) ; \
214+ if [ -n " $$ REPO_ROOT" ]; then \
215+ BRANCH=$$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown" ) ; \
216+ COMMIT=$$(git rev-parse --short HEAD 2>/dev/null || echo "unknown" ) ; \
217+ echo " ✓ python-sdks: $$ REPO_ROOT" ; \
218+ echo " Branch: $$ BRANCH @ $$ COMMIT" ; \
219+ fi ; \
220+ if [ -d " $( PYTHON_RTC) " ]; then \
221+ echo " ✓ livekit-rtc: $( PYTHON_RTC) " ; \
222+ else \
223+ echo " ✗ livekit-rtc: NOT FOUND" ; \
224+ ISSUES=$$((ISSUES + 1 ) ); \
225+ fi ; \
226+ if [ -d " $( PYTHON_API) " ]; then \
227+ echo " ✓ livekit-api: $( PYTHON_API) " ; \
228+ else \
229+ echo " ✗ livekit-api: NOT FOUND" ; \
230+ ISSUES=$$((ISSUES + 1 ) ); \
231+ fi ; \
232+ if [ -d " $( PYTHON_PROTOCOL) " ]; then \
233+ echo " ✓ livekit-protocol: $( PYTHON_PROTOCOL) " ; \
234+ else \
235+ echo " ✗ livekit-protocol: NOT FOUND" ; \
236+ ISSUES=$$((ISSUES + 1 ) ); \
237+ fi ; \
238+ if [ -d " $( RUST_SUBMODULE) " ]; then \
239+ echo " ✓ rust-sdks: $( RUST_SUBMODULE) " ; \
240+ if [ -e " $( RUST_SUBMODULE) /.git" ]; then \
241+ RUST_BRANCH=$$(cd $(RUST_SUBMODULE ) && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown" ) ; \
242+ RUST_COMMIT=$$(cd $(RUST_SUBMODULE ) && git rev-parse --short HEAD 2>/dev/null || echo "unknown" ) ; \
243+ echo " Branch: $$ RUST_BRANCH @ $$ RUST_COMMIT" ; \
244+ fi ; \
245+ else \
246+ echo " ⚠ rust-sdks: NOT FOUND (needed for 'make build-rtc')" ; \
247+ fi ; \
248+ echo " " ; \
249+ echo " $( BOLD) 🔍 Current Configuration:$( RESET) " ; \
250+ if [ -d " .venv" ]; then \
251+ echo " ✓ Virtual environment: .venv exists" ; \
252+ else \
253+ echo " ⚠ Virtual environment: .venv not found (run 'make install')" ; \
254+ fi ; \
255+ for pkg in livekit livekit-api livekit-protocol; do \
256+ SHOW_OUTPUT=$$(uv pip show $$pkg 2>/dev/null || echo "" ) ; \
257+ if [ -z " $$ SHOW_OUTPUT" ]; then \
258+ echo " ✗ $$ pkg: NOT INSTALLED" ; \
259+ elif echo " $$ SHOW_OUTPUT" | grep -q " Editable project location:" ; then \
260+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
261+ echo " ✓ $$ pkg: LOCAL (editable) v$$ VERSION" ; \
262+ else \
263+ VERSION=$$(echo "$$SHOW_OUTPUT" | grep "^Version:" | awk '{print $$2}' ) ; \
264+ echo " ✓ $$ pkg: PyPI v$$ VERSION" ; \
265+ fi ; \
266+ done ; \
267+ if [ -n " $$ LIVEKIT_LIB_PATH" ]; then \
268+ if [ -f " $$ LIVEKIT_LIB_PATH" ]; then \
269+ echo " ✓ FFI: Custom build from LIVEKIT_LIB_PATH" ; \
270+ else \
271+ echo " ✗ FFI: LIVEKIT_LIB_PATH set but file not found: $$ LIVEKIT_LIB_PATH" ; \
272+ ISSUES=$$((ISSUES + 1 ) ); \
273+ fi ; \
274+ fi ; \
275+ echo " " ; \
276+ if [ $$ ISSUES -eq 0 ]; then \
277+ echo " $( BOLD) $( GREEN) ✅ All checks passed! Environment is healthy.$( RESET) " ; \
278+ else \
279+ echo " $( BOLD) $( RED) ⚠️ Found $$ ISSUES issue(s). Please fix the errors above.$( RESET) " ; \
280+ exit 1; \
281+ fi
0 commit comments