Skip to content

fix(ci): restaurer les builds macOS et Linux sur main - #220

Merged
EtienneLescot merged 9 commits into
mainfrom
fix/restore-cross-platform-builds
Aug 1, 2026
Merged

fix(ci): restaurer les builds macOS et Linux sur main#220
EtienneLescot merged 9 commits into
mainfrom
fix/restore-cross-platform-builds

Conversation

@EtienneLescot

@EtienneLescotEtienneLescot commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

main porte la désactivation Windows-only de la 1.8.0 sans aucune des réparations qui la rendent inutile. Concrètement : une version coupée depuis main aujourd'hui sortirait Windows-only, en silence — les jobs macOS et Linux sont skipped, donc verts, et la release se publie avec un seul artefact.

C'est exactement le mode d'échec contre lequel le commentaire de 610b93e9 mettait en garde :

# RELEASE-BRANCH-ONLY: 1.8.0 ships Windows-only. Do NOT let this if: false reach main when promoting, or every later release becomes Windows-only too.

L'avertissement est arrivé trop tard : le commit était déjà sur main.

Ce que la PR contient

Six commits cherry-pickés de release/v1.8.0, sans le bump 1.8.0-rc.5 qui n'a rien à faire ici. Les quatre fichiers modifiés sont identiques octet pour octet à la branche qui vient de produire une rc.5 verte sur les trois plateformes.

e8c4bb0drevert du Windows-only : macOS et Linux réactivés, remis dans le needs de publish-release
2883617eLinux : RUNPATH $ORIGIN pour whisper-stt · macOS : --disable-xlib/libxcb/sdl2/lzma sur ffmpeg
9e9de681Linux : provisionnement du SDK ffmpeg partagé
ab696f10macOS : chaque arch compilée nativement, x64 sur runner Intel
ca13518fLinux : verbatimSymlinks pour ne pas casser les liens du SDK
9fb7d0c9Linux : mode --sdk-only, la copie runtime reste windows-only

Les cinq pannes réparées

Rallumer les deux jobs n'a pas révélé un problème mais cinq, empilés, invisibles depuis le 27 juillet :

  1. whisper-stt ne démarrait pas sur Linux. Le script supposait que « le loader cherche toujours dans le répertoire du binaire » — vrai sur Windows, faux sur Linux. Le correctif existait et avait été annulé trois fois en supposant qu'il arriverait par une autre branche.
  2. ffmpeg happait le libX11 de Homebrew du runner macOS, produisant un dylib introuvable sur la machine d'un utilisateur.
  3. macOS x64 n'avait jamais cross-compilé : tout se calait sur process.arch, donc le job x64 produisait de l'arm64 dans le mauvais répertoire. v1.7.0 livrait un DMG x64 parce qu'elle n'avait ni compositeur ni ffmpeg vendorisé à construire.
  4. Le SDK ffmpeg Linux n'était provisionné nulle part.
  5. cpSync déréférençait les symlinks du SDK vers un /tmp supprimé juste après : en-têtes trouvés, link en échec.

Vérification

Preuve principale : v1.8.0-rc.5 est publiée avec les six artefacts (AppImage, deb, pacman, DMG arm64, DMG x64, exe) depuis ces mêmes changements.

Sur cette branche : tsc propre, types de test à 0, 1396 tests verts, biome et docs OK, et aucune condition if: false réelle ne subsiste.

À noter

main affiche 1.8.0-rc.4 dans package.json, hérité de la fusion de #219. Cette PR n'y touche pas — c'est promote.yml qui doit réconcilier les versions.

Quand promote ouvrira sa PR release/v1.8.0-sync → main, ces commits y seront déjà sous d'autres SHAs. Git écarte en général les patchs identiques ; sinon ce sera un conflit sur des fichiers connus.

Summary by CodeRabbit

  • New Features

    • Added Linux build support and expanded macOS builds for both Intel and Apple silicon.
    • Added shared FFmpeg support for Linux, macOS, and Windows distributions.
  • Bug Fixes

    • Improved packaged application reliability by ensuring native components locate bundled libraries correctly.
    • Reduced platform-specific build dependencies for more consistent release artifacts.
  • Chores

    • Release publishing now verifies successful builds across Windows, macOS, and Linux before completion.
    • Linux builds now automatically prepare the required FFmpeg SDK.

This reverts commit 610b93e sur la branche release : 1.8.0 ne sort plus
Windows-only, on veut les trois plateformes dès la rc.5.
Les quatre hunks reviennent ensemble, ils ne se séparent pas : réactiver
build-macos et build-linux sans les remettre dans le `needs` de
publish-release ne suffirait pas — un job absent du needs ne bloque plus
la publication, mais ses artefacts ne sont pas attendus non plus. Et le
`continue-on-error` du téléchargement Linux doit sauter avec, sinon un
artefact manquant passerait en silence au lieu d'échouer.
Ce que ça réintroduit, sciemment : un échec macOS ou Linux bloque de
nouveau toute la release. C'était la raison d'être du commit d'origine.
Le compromis est assumé — une release amputée d'une plateforme sans que
rien ne rougisse est un pire défaut qu'une release qui échoue bruyamment.
Sur un tag RC, signature et notarisation sont de toute façon sautées
(`!contains(github.ref_name, '-')`), donc le job macOS ne dépend pas des
secrets Apple pour aboutir.
À noter : `main` porte toujours les mêmes `if: false`. L'avertissement du
commit d'origine — « ne laisse pas ça atteindre main » — s'est déjà
réalisé, et reste à traiter séparément.
…: false`
Les jobs macOS et Linux étaient désactivés depuis le 27/07 (610b93e). Les
réactiver a révélé deux pannes réelles, distinctes, que personne ne pouvait
voir tant que les jobs étaient sautés.
LINUX — whisper-stt-server ne démarre pas
Le staging copie bien libwhisper.so.1 à côté du binaire, puis le smoke-test
échoue en exit 127 : « cannot open shared object file ». Le commentaire de
stage-whisper-stt.sh affirme que « le loader cherche toujours dans le
répertoire du binaire » — vrai sur Windows, faux sur Linux, où ld.so ignore
le cwd et PATH et n'a que RPATH/RUNPATH.
Le correctif existe déjà (aacd65d1) : un RUNPATH `$ORIGIN` dans le CMakeLists.
Il avait été annulé trois fois, à chaque fois pour la même raison procédurale
— « poussé sur la mauvaise branche, il arrivera par feat/linux-compositor-port ».
Il n'est jamais arrivé. Repris ici par cherry-pick.
Attention : rebâtir les artefacts whisper-stt est nécessaire. stage-whisper-stt.sh
télécharge le dernier artefact publié par build-whisper-stt.yml, pas une
compilation locale — sans nouvelle exécution de ce workflow, le staging
continuera de récupérer le binaire non relogeable.
MACOS — ffmpeg happe le libX11 de Homebrew
`libavformat.62.dylib still references build-machine paths after rewriting:
/opt/homebrew/opt/libx11/lib/libX11.6.dylib`. Le contrôle de
build-macos-compositor-addon.mjs fait son travail : un tel dylib est
introuvable sur la machine d'un utilisateur.
La cause est que le configure d'ffmpeg auto-détecte ces bibliothèques dans le
préfixe Homebrew du runner. On les désactive explicitement plutôt que de les
laisser au hasard de ce qui est installé, ce qui rend l'arbre vendorisé
dépendant du tarball et du SDK, et de rien d'autre. Aucune n'est utilisée :
xlib/libxcb sont de la capture X11, sdl2 ne sert qu'à ffplay, et lzma ne touche
que des décodeurs qu'on n'embarque pas.
lzma et sdl2 sont désactivés avec, bien qu'ils n'aient pas encore échoué :
chaque itération coûte un build macOS complet, et ce sont les seuls autres
candidats plausibles à une fuite Homebrew.
`npm run build:linux` échouait dans cargo : « vendored ffmpeg headers are
missing at crates/thirdparty/ffmpeg-linux64-lgpl-shared ». Le helper
pipewire-capture lie ffmpeg, et rien ne fournissait cet arbre.
fetch-ffmpeg.mjs vendorisait déjà la variante « shared », mais uniquement pour
Windows, et de trois façons cumulées : SHARED_PINNED n'avait pas d'entrée Linux,
la fonction cherchait `ffmpeg.exe` et collectait des `.dll`, et main() la gardait
derrière un `if (process.platform === "win32")`. Le commentaire assumait
« compositor addon is Windows-only » — vrai quand il a été écrit, faux depuis que
le helper Linux lie ffmpeg lui aussi.
Quatre points, tous nécessaires :
- entrée SHARED_PINNED linux-x64, même tag BtbN et même commit source
(n8.1.2-32-gcfa62de001) que les entrées Windows, sha256 épinglé ;
- détection des bibliothèques partagées par plateforme (`.dll` / `.so[.N]*`)
au lieu de `.dll` en dur ;
- destination du SDK sur Linux alignée sur le défaut de build.rs plutôt que sur
crates/.cargo/config.toml, qui épingle le chemin Windows ;
- garde win32 retirée de main() — fetchSharedDlls sort déjà d'elle-même quand
aucun pin n'existe pour la plateforme, donc la garde était redondante ET
excluante.
Deux détails que seul un essai réel fait apparaître, et qui auraient coûté
chacun un cycle de CI :
La vérification de licence lançait `ffmpeg -L` sur le binaire du build *shared*,
qui est lié dynamiquement : sans LD_LIBRARY_PATH il ne démarre pas, n'imprime
rien, et assertLgpl lisait ce silence comme « unrecognised licence » puis
refusait de vendoriser. Le lib/ voisin lui est maintenant passé.
Et la copie doit préserver les chaînes de symlinks (libavformat.so ->
.so.62 -> .so.62.12.102) : copyFileSync les déréférencerait en trois fichiers
identiques de 24 Mo.
`fetch:ffmpeg` passe en tête de `build:linux`, avant build:native:linux qui en a
besoin — même ordre que `build:win`.
Vérifié en exécutant le script sur une machine Linux : 21 bibliothèques
vendorisées, SDK déposé, en-têtes et libs de link exactement là où build.rs les
cherche.
Le job x64 tournait sur macos-latest, qui est Apple Silicon. Tout ce que le
chemin macOS de la 1.8.0 a ajouté se cale sur l'arch de l'HÔTE — configure
ffmpeg en `--arch=${process.arch}`, installation dans `darwin-${process.arch}`,
cargo sans `--target` — donc le job x64 produisait de l'arm64 dans
darwin-arm64/, et l'empaquetage échouait sur « Refusing to package an incomplete
macOS payload — looked in darwin-x64 ».
v1.7.0 livrait bien un DMG x64 : elle n'avait ni addon compositeur ni ffmpeg
vendorisé à construire. Les deux sont arrivés avec la 1.8.0, et le `if: false`
a empêché quiconque de le voir.
Un runner Intel pour x64 règle ça sans faire passer une arch cible à travers le
configure d'ffmpeg, cargo et les chemins de sortie — quatre modifications à
l'aveugle sur une branche de release, dont aucune n'est testable sans Mac.
Le vendoring déposait bien les en-têtes — build.rs passait son assert — puis le
link échouait sur `unable to find library -lavcodec` et ses quatre voisines.
fs.cpSync RÉSOUT les liens symboliques par défaut : lib/libavcodec.so ->
libavcodec.so.62.28.102 devenait un lien ABSOLU vers le répertoire temporaire
d'extraction, que la fonction appelante supprime juste après. Les cinq liens de
développement que le linker cherche étaient donc pendants.
verbatimSymlinks les préserve tels quels. Sans effet sur Windows, qui n'a pas
de liens dans cette archive.
Vérifié en re-vendorisant depuis zéro sur Linux, et en testant la RÉSOLVABILITÉ
des cinq liens (-e) et non leur simple présence : un `ls` réussit sur un lien
mort, ce qui est précisément ce qui m'avait fait valider la version cassée.
Deux collisions dans electron/native/bin/linux-x64/, introduites en branchant
fetch:ffmpeg sur build:linux.
La première a cassé le build : le CLI statique est vendorisé sous le nom
`ffmpeg` (un FICHIER), alors que build-linux-pipewire-helper.mjs y crée un
RÉPERTOIRE `ffmpeg/` — le nom contre lequel le RUNPATH $ORIGIN/ffmpeg du
helper est compilé. D'où `EEXIST: mkdir .../linux-x64/ffmpeg`.
La seconde n'avait pas encore frappé et aurait été pire à diagnostiquer : les
copies runtime des .so partaient elles aussi dans ce répertoire, NON renommées,
sous les mêmes noms que les copies à symboles renommés (osff_*) qu'y place
build-linux-compositor-addon.mjs pour que l'addon ne se lie pas au ffmpeg de
Chromium. L'une aurait écrasé l'autre, et l'addon serait mort au chargement.
Ce répertoire appartient donc aux deux scripts natifs ; fetch-ffmpeg n'a rien à
y faire sur Linux. La copie runtime est restreinte à Windows, où le loader
cherche bien les DLL à côté de l'exécutable, et `--sdk-only` (nouveau script
fetch:ffmpeg:sdk) saute le CLI statique. Le SDK, lui, reste nécessaire :
pipewire-capture et l'addon compositeur linkent contre lui.
Le CLI n'est pas une perte : assertLgpl note que plus rien dans l'app ne lance
ffmpeg, et v1.7.0 livrait AppImage/deb/pacman sans.
Vérifié depuis un état vierge sur Linux : les cinq bibliothèques que build.rs
demande sont résolvables, les en-têtes sont en place, et le chemin
linux-x64/ffmpeg est libre pour le mkdir du helper.
@coderabbitai

coderabbitaiBot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b6e6232-dc13-46f9-a71d-425cc06679b6

📥 Commits

Reviewing files that changed from the base of the PR and between 88871aa and 441d3d8.

📒 Files selected for processing (2)
  • .github/workflows/build.yml
  • scripts/fetch-ffmpeg.mjs
💤 Files with no reviewable changes (1)
  • .github/workflows/build.yml

📝 Walkthrough

Walkthrough

The change adds Linux shared FFmpeg provisioning, executable-relative RPATHs, and macOS FFmpeg feature exclusions. It enables Linux and macOS CI builds and requires Windows, macOS, and Linux artifacts before release publication.

Changes

Cross-platform FFmpeg builds

Layer / File(s)Summary
Shared FFmpeg configuration
scripts/fetch-ffmpeg.mjs, scripts/fetch-ffmpeg-macos.mjs
Shared FFmpeg assets now include a pinned Linux archive. License and build checks accept platform environments. macOS configuration disables X11, libxcb, SDL2, and LZMA.
FFmpeg SDK and runtime provisioning
scripts/fetch-ffmpeg.mjs
Provisioning supports Linux shared libraries, SDK symlinks, platform-specific library discovery, Linux validation, and --sdk-only mode.
Linux native build integration
package.json, electron/native/whisper-stt/CMakeLists.txt
The Linux build fetches the FFmpeg SDK before native compilation. Non-Apple Unix builds use $ORIGIN and $ORIGIN/bin install RPATHs.
Build and release workflow
.github/workflows/build.yml
Linux and macOS builds are enabled. Release publication waits for all three platform builds, and missing required artifacts fail the workflow.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
participant BuildScript
participant FetchFFmpeg
participant FFmpegSDK
participant NativeBuild
BuildScript->>FetchFFmpeg: invoke --sdk-only
FetchFFmpeg->>FFmpegSDK: download and extract shared SDK
FetchFFmpeg->>FetchFFmpeg: discover and validate platform libraries
FetchFFmpeg-->>NativeBuild: provide Linux SDK and shared libraries
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly and concisely describes restoring macOS and Linux builds on main.
Description check✅ PassedThe description provides a detailed summary, affected platforms, fixes, and testing results, but omits the template checklists.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/restore-cross-platform-builds

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/fetch-ffmpeg.mjs (1)

159-182: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Encoder check and version banner bypass the shared-build environment.

assertLgpl accepts extraEnv and applies it to the -L, -buildconf, and -version probes at lines 171, 181-182. The -encoders check (line 193) and the closing -version call (line 205) still call run() without opts.

The function's own comment states a shared ffmpeg binary "cannot resolve its own libav*.so without being told where they are, and a binary that fails to start prints nothing." fetchSharedDlls calls assertLgpl(exe, sharedEnv) for non-Windows builds, where sharedEnv carries LD_LIBRARY_PATH. Without that same env on the -encoders call, the shared Linux ffmpeg fails to start, encoders is empty, and the loop that flags libx264/libx265 finds no problems — the "belt and braces" GPL-encoder check silently no-ops for every shared Linux verification instead of catching a misconfigured build.

🔒 Proposed fix to propagate opts to the remaining checks
 // Belt and braces: whatever the flags claim, the binary must not actually
// expose a GPL encoder.
-	const encoders = run(exePath, ["-hide_banner", "-encoders"]).stdout ?? "";+	const encoders = run(exePath, ["-hide_banner", "-encoders"], opts).stdout ?? "";
for (const lib of ["libx264", "libx265"]) {
if (new RegExp(`\\s${lib}\\s`).test(encoders)) problems.push(`exposes the ${lib} encoder`);
}
@@
-	const ver = run(exePath, ["-hide_banner", "-version"]).stdout ?? "";+	const ver = run(exePath, ["-hide_banner", "-version"], opts).stdout ?? "";
return ver.split("\n")[0]?.trim() ?? "";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/fetch-ffmpeg.mjs` around lines 159 - 182, Update the remaining probe
calls in assertLgpl to pass the existing opts environment: specifically use opts
for the -encoders check and the final -version banner call. Keep the current
shared-build environment propagation and GPL encoder/version validation behavior
unchanged.
🧹 Nitpick comments (1)
.github/workflows/build.yml (1)

92-104: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Pin the ARM64 runner to an explicit label.

runs-on pins x64 to macos-15-intel, but it uses macos-latest for arm64. The native build derives its output from the host architecture. A moving runner label can change the build environment and break this release path.

Use macos-15 or another explicit ARM64 label. GitHub currently lists macos-latest for macOS 15 ARM64, but documents -latest labels as moving. (github.com)

Suggested change
- runs-on: ${{ matrix.arch == 'x64' && 'macos-15-intel' || 'macos-latest' }}+ runs-on: ${{ matrix.arch == 'x64' && 'macos-15-intel' || 'macos-15' }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/build.yml around lines 92 - 104, Update the ARM64 branch
of the runs-on expression in the build matrix to use an explicit ARM64 macOS
label such as macos-15 instead of the moving macos-latest label, while
preserving the existing macos-15-intel selection for x64.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/build.yml:
- Around line 347-350: Update the release workflow around publish-release and
the macOS artifact download steps so manual releases always build and require
both x64 and arm64 macOS artifacts. Remove continue-on-error from both macOS
downloads, validate that both expected artifacts exist before invoking gh
release, and prevent publication when either architecture is missing.
In `@scripts/fetch-ffmpeg.mjs`:
- Around line 390-405: Update the vendored-library detection in the fetch flow
around alreadyVendored so Linux also evaluates whether the shared FFmpeg
libraries are present, while preserving the existing Windows-specific
directory-entry logic where applicable. Ensure the skip condition uses
alreadyVendored, sdkPresent, and the absence of --force so already-complete
vendoring avoids re-downloads on all supported platforms.
---
Outside diff comments:
In `@scripts/fetch-ffmpeg.mjs`:
- Around line 159-182: Update the remaining probe calls in assertLgpl to pass
the existing opts environment: specifically use opts for the -encoders check and
the final -version banner call. Keep the current shared-build environment
propagation and GPL encoder/version validation behavior unchanged.
---
Nitpick comments:
In @.github/workflows/build.yml:
- Around line 92-104: Update the ARM64 branch of the runs-on expression in the
build matrix to use an explicit ARM64 macOS label such as macos-15 instead of
the moving macos-latest label, while preserving the existing macos-15-intel
selection for x64.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3fe0f929-7edc-488f-b22e-31b6acece8eb

📥 Commits

Reviewing files that changed from the base of the PR and between f6f74c6 and 88871aa.

📒 Files selected for processing (5)
  • .github/workflows/build.yml
  • electron/native/whisper-stt/CMakeLists.txt
  • package.json
  • scripts/fetch-ffmpeg-macos.mjs
  • scripts/fetch-ffmpeg.mjs

Comment thread.github/workflows/build.yml
Comment on lines +390 to 405
const alreadyVendored =
process.platform === "win32" &&
fs
.readdirSync(binDir, { withFileTypes: true })
.some((e) => e.isFile() && isSharedLib(e.name) && /^(lib)?av/i.test(e.name));
// The build-time SDK comes out of this same archive, so a tree that has the
// DLLs but not the SDK must still re-download — otherwise we skip here and
// the compositor build fails afterwards on the missing FFMPEG_DIR.
const sdkDest = ffmpegSdkDest();
const sdkPresent = sdkDest == null || fs.existsSync(sdkDest);
if (alreadyVendored && sdkPresent && !process.argv.includes("--force")) {
console.log(`\nShared ffmpeg DLLs already present in ${binDir}. Use --force to re-vendor.`);
console.log(
`\nShared ffmpeg libraries already present in ${binDir}. Use --force to re-vendor.`,
);
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Linux always re-downloads the shared SDK, even when already vendored.

alreadyVendored is gated by process.platform === "win32" &&, so it is always false on Linux. The skip condition on line 400 requires alreadyVendored && sdkPresent && !force, so on Linux the skip never triggers, regardless of sdkPresent. The adjacent comment states re-download should be "driven by --force" once vendoring is in place, which indicates the skip was meant to work on all platforms, not just Windows.

Since the Linux native build script now runs this fetch step before every native compile, this means every native Linux build re-downloads and re-extracts the shared ffmpeg archive from the network, even when crates/thirdparty/ffmpeg-linux64-lgpl-shared is already present and current. This adds unnecessary network I/O and a new failure mode (network flakiness) to every build.

♻️ Proposed fix to make the skip check platform-aware
-	const alreadyVendored =- process.platform === "win32" &&- fs- .readdirSync(binDir, { withFileTypes: true })- .some((e) => e.isFile() && isSharedLib(e.name) && /^(lib)?av/i.test(e.name));
// The build-time SDK comes out of this same archive, so a tree that has the
// DLLs but not the SDK must still re-download — otherwise we skip here and
// the compositor build fails afterwards on the missing FFMPEG_DIR.
const sdkDest = ffmpegSdkDest();
const sdkPresent = sdkDest == null || fs.existsSync(sdkDest);
+	// Windows vendors runtime DLLs into binDir; Linux vendors only the SDK, so the+	// SDK's presence alone tells us whether there is anything left to fetch.+	const alreadyVendored =+ process.platform === "win32"+ ? fs+ .readdirSync(binDir, { withFileTypes: true })+ .some((e) => e.isFile() && isSharedLib(e.name) && /^(lib)?av/i.test(e.name))+ : sdkPresent;
if (alreadyVendored && sdkPresent && !process.argv.includes("--force")) {
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constalreadyVendored=
process.platform==="win32"&&
fs
.readdirSync(binDir,{withFileTypes: true})
.some((e)=>e.isFile()&&isSharedLib(e.name)&&/^(lib)?av/i.test(e.name));
// The build-time SDK comes out of this same archive, so a tree that has the
// DLLs but not the SDK must still re-download — otherwise we skip here and
// the compositor build fails afterwards on the missing FFMPEG_DIR.
constsdkDest=ffmpegSdkDest();
constsdkPresent=sdkDest==null||fs.existsSync(sdkDest);
if(alreadyVendored&&sdkPresent&&!process.argv.includes("--force")){
console.log(`\nShared ffmpeg DLLs already present in ${binDir}. Use --force to re-vendor.`);
console.log(
`\nShared ffmpeg libraries already present in ${binDir}. Use --force to re-vendor.`,
);
return;
}
// The build-time SDK comes out of this same archive, so a tree that has the
// DLLs but not the SDK must still re-download — otherwise we skip here and
// the compositor build fails afterwards on the missing FFMPEG_DIR.
constsdkDest=ffmpegSdkDest();
constsdkPresent=sdkDest==null||fs.existsSync(sdkDest);
// Windows vendors runtime DLLs into binDir; Linux vendors only the SDK, so the
// SDK's presence alone tells us whether there is anything left to fetch.
constalreadyVendored=
process.platform==="win32"
? fs
.readdirSync(binDir,{withFileTypes: true})
.some((e)=>e.isFile()&&isSharedLib(e.name)&&/^(lib)?av/i.test(e.name))
: sdkPresent;
if(alreadyVendored&&sdkPresent&&!process.argv.includes("--force")){
console.log(
`\nShared ffmpeg libraries already present in ${binDir}. Use --force to re-vendor.`,
);
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/fetch-ffmpeg.mjs` around lines 390 - 405, Update the vendored-library
detection in the fetch flow around alreadyVendored so Linux also evaluates
whether the shared FFmpeg libraries are present, while preserving the existing
Windows-specific directory-entry logic where applicable. Ensure the skip
condition uses alreadyVendored, sdkPresent, and the absence of --force so
already-complete vendoring avoids re-downloads on all supported platforms.

Deux trouvailles de la revue CodeRabbit sur #220, vérifiées avant correction.
assertLgpl propageait l'environnement partagé à -L et -buildconf mais pas au
contrôle -encoders ni à la bannière -version finale. Sur un build SHARED Linux,
ffmpeg ne résout pas ses propres libav*.so sans LD_LIBRARY_PATH : il n'imprime
rien, et le contrôle ceinture-bretelles qui cherche libx264/libx265 opérait donc
sur une chaîne vide. Il ne rejetait rien, jamais. Mesuré : 0 octet sans
l'environnement, 13 397 octets et 229 encodeurs avec.
C'est un garde-fou de conformité LGPL. Passer à vide y est pire qu'échouer.
Les téléchargements macOS d'artefacts portaient continue-on-error: true, alors
qu'un workflow_dispatch peut cibler une seule arch tout en fournissant un
release_tag. Le contrôle final ne rejette qu'un répertoire entièrement vide, si
bien qu'une release pouvait se publier avec un seul DMG sur les deux, sans que
rien ne rougisse. C'est le mode d'échec silencieux que cette PR entend supprimer,
appliqué à macOS au lieu de Windows. Le revert avait déjà retiré le même drapeau
côté Linux ; les deux macOS le suivent.
Un dispatch délibérément mono-arch échouera désormais à la publication plutôt
que de livrer une release incomplète. C'est le comportement voulu : l'opérateur
le verra et tranchera.
@EtienneLescot
EtienneLescot merged commit 3f0ec8a into mainAug 1, 2026
13 of 14 checks passed
@EtienneLescot
EtienneLescot deleted the fix/restore-cross-platform-builds branch August 1, 2026 10:35
Sign up for freeto 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.

1 participant

@EtienneLescot