Skip to content

Conversation

@pproenca
Copy link
Owner

Summary

  • Add CI workflow with lint job and multi-platform build/test matrix
  • Add @pproenca/webcodecs-ffmpeg-* as optionalDependencies for zero-config FFmpeg
  • Update FFmpeg path resolution to check npm packages before system fallback

Changes

CI Workflow (.github/workflows/ci.yml)

  • Lint job: Runs on ubuntu-24.04, checks C++, TypeScript, types, and markdown
  • Build matrix:
    • Linux glibc: Rocky Linux 8 container with Node 20/22
    • Linux musl: Alpine 3.20 container with Node 20/22
    • macOS ARM64: macos-14 runner with Node 20/22
    • macOS x64: macos-13 runner with Node 20/22
  • Uses --omit=optional to test system FFmpeg fallback path

Optional FFmpeg Dependencies

  • Added @pproenca/webcodecs-ffmpeg-darwin-arm64, -darwin-x64, -linux-x64 to optionalDependencies
  • Updated gyp/ffmpeg-paths-lib.ts with new resolution order:
    1. FFMPEG_ROOT env var (explicit override)
    2. @pproenca/webcodecs-ffmpeg npm package (if installed)
    3. ./ffmpeg-install directory (local development)
    4. System pkg-config (fallback)

Test Plan

  • Verify lint job passes on ubuntu-24.04
  • Verify Linux glibc build passes on Rocky Linux 8
  • Verify Linux musl build passes on Alpine 3.20
  • Verify macOS ARM64 build passes on macos-14
  • Verify macOS x64 build passes on macos-13
  • Verify all Node.js versions (20, 22) work

- Add CI workflow with lint job (C++, TypeScript, types, markdown)
- Add build jobs for Linux glibc (Rocky 8), Linux musl (Alpine 3.20)
- Add build jobs for macOS ARM64 (macos-14), macOS x64 (macos-13)
- Test on Node.js 20 and 22 (matching engines field)
- Use system FFmpeg via package managers for CI validation

- Add @pproenca/webcodecs-ffmpeg-* as optionalDependencies
- Update gyp/ffmpeg-paths-lib.ts to resolve FFmpeg from npm package
- Resolution order: FFMPEG_ROOT > npm package > ./ffmpeg-install > system

The CI uses --omit=optional to validate the system FFmpeg fallback works.
Developers get FFmpeg automatically on npm install, or can opt-out to use
system FFmpeg with npm install --omit=optional.
The project doesn't commit package-lock.json, so npm ci fails.
Use npm install with --omit=optional to skip FFmpeg optionalDeps.
- Install cpplint via pip (npm package doesn't support Linux)
- Enable EPEL and PowerTools repos before FFmpeg install
- Try RPMFusion as fallback if ffmpeg-devel not in EPEL
- Add npm run build:ts step before lint:types (tsd needs dist/index.d.ts)
- Use Python 3.9 on Rocky Linux 8 (node-gyp requires Python 3.8+)
- Use RPMFusion for FFmpeg on Rocky 8 (EPEL doesn't have ffmpeg-devel)
Linux glibc (Rocky 8):
- Install gcc-toolset-12 for C++20 support (Rocky 8 default GCC 8.x lacks -std=c++20)
- Source toolset enable script before build

Linux musl (Alpine 3.20):
- Install all FFmpeg transitive dependencies required by pkg-config
- Alpine's FFmpeg is compiled with many optional features, all need their dev packages
Rocky Linux 9:
- Switch from Rocky 8 to Rocky 9 (glibc 2.34 instead of 2.28)
- Rocky 8's RPMFusion only has FFmpeg 4.x, project requires 5.0+
- Rocky 9 RPMFusion has FFmpeg 6+ with C++20 support out of box

Alpine 3.20:
- Use pkgconf instead of pkgconfig (correct Alpine package name)
- Simplify to just ffmpeg-dev (pulls in all core dependencies)
- Add pkg-config verification step to catch errors early
AVFrame::duration was added in FFmpeg 5.1 (libavutil 57.28.100).
For FFmpeg 5.0, use the deprecated pkt_duration field instead.

Added AV_FRAME_DURATION and AV_FRAME_SET_DURATION macros in common.h
that select the correct field based on FFmpeg version.
- Add Linux FFmpeg fallback paths (/usr/include, /usr/local/include, /usr/lib, /usr/local/lib)
- Add RPATH for macOS (@loader_path/../lib) and Linux ($ORIGIN/../lib)
- Add MacPorts support (/opt/local/include, /opt/local/lib)
- Add dynamic linking fallback when static fails on Linux
- Add explicit error logging with [node-webcodecs] prefix
- Add pkg-config output validation (empty check)
- Add isPkgConfigAvailable() helper function
- Add -Wpedantic and -Wshadow compiler warnings
- Add Debug/Release configurations block
- Add parallel compilation (-j max) to build scripts
- Add node-gyp caching to CI workflow
- Implement rpath mode in ffmpeg-paths.js

Closes: harden-native-build-config
Alpine's ffmpeg-dev only provides shared libraries. The --static flag
caused pkg-config to output flags for non-existent static libraries,
which then failed at link time.

Dynamic linking works correctly for CI testing with system FFmpeg.
Static linking is only needed for distribution builds with bundled FFmpeg.
- Add musl libc detection in ffmpeg-paths-lib.ts
- On musl systems, try @pproenca/webcodecs-ffmpeg-linux-x64-musl first
- Update CI to install musl FFmpeg package instead of system ffmpeg-dev
- Remove system pkg-config fallback for Alpine (use npm package only)

This enables proper static linking on Alpine Linux using the
pre-built FFmpeg package with musl libc support.
npm will auto-install @pproenca/webcodecs-ffmpeg-linux-x64-musl on
Alpine/musl systems via the libc field in the package's package.json.

Simplified CI to use regular npm install instead of explicit package install.
- Add @pproenca/webcodecs-ffmpeg-dev for cross-platform headers
- Add tryResolveIncludeFromDevPackage() for header resolution
- Add tryResolveLinkFlagsFromNpmPackage() for static link flags
- Update resolution order: npm packages take precedence
- Bump FFmpeg packages to ^0.1.4 with ./link-flags export
- Update unit test for new resolution priority

This enables fully static builds from npm packages without
requiring system FFmpeg or pkg-config with hardcoded paths.
FFmpeg linking requires system compression libraries (-lz, -lbz2)
which were missing from the Alpine container package installation.
Add -fno-lto to Linux cflags_cc and ldflags to prevent LTO conflicts
with musl's fortified libc functions. The FFmpeg static libraries are
compiled with LTO, which causes link failures on Alpine due to
vsnprintf being marked always_inline in fortify headers.
- Remove ffmpeg-devel from dnf install (not needed with npm packages)
- Remove --omit=optional to install @pproenca/webcodecs-ffmpeg-* packages

The platform packages contain static FFmpeg libs and link-flags.js,
enabling fully static builds without system FFmpeg.
Expand CI from 4 builds to 10 builds matching @pproenca/webcodecs-ffmpeg:
- 5 platforms: darwin-arm64, darwin-x64, linux-x64-glibc, linux-arm64, linux-x64-musl
- 2 variants: free (LGPL), non-free (GPL)

Changes:
- Refactor to unified matrix strategy (replaces 4 separate jobs)
- Add linux-arm64 support via QEMU emulation
- Add variant-aware FFmpeg package installation
- macOS free variant uses npm packages, non-free uses Homebrew
- Linux builds explicitly install correct FFmpeg package per variant
- Update ffmpeg-prebuilds to 0.1.6
- Add linux-arm64 to optionalDependencies
- Simplify to Node.js 20 only
- Update @pproenca/webcodecs-ffmpeg packages to ^0.1.7 (fixes LTO issue)
- Add zlib-devel bzip2-devel to Rocky Linux builds
Prevents stale cache from causing "Access token expired" warnings.
The npm FFmpeg packages include -latomic in link flags, which requires
the libatomic library to be installed for linking. This was missing
from the Rocky Linux CI containers.
@pproenca pproenca merged commit 773cacd into master Jan 12, 2026
1 of 11 checks passed
@pproenca pproenca deleted the feat/ci-workflow branch January 12, 2026 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants