Skip to content
Merged
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
64 changes: 64 additions & 0 deletions crates/compositor/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ fn main() {
.derive_default(true)
.layout_tests(false);

// Linux uniquement : cf. `freestanding_header_args()`. Sur macOS le sysroot arrive
// par `xcrun` juste en dessous, sur Windows par MSVC — dans les deux cas clang a
// déjà ses en-têtes builtin et injecter ceux de gcc n'aurait aucun sens.
if target_os == "linux" {
for arg in freestanding_header_args() {
builder = builder.clang_arg(arg);
}
}

// Sur macOS le bindgen doit viser aarch64-apple-darwin pour que les layouts
// générés (long=8, etc.) matchent la cible. Sans ce flag, bindgen utilise
// le défaut du host (probablement x86_64), et les structs ffmpeg sont mal
Expand Down Expand Up @@ -162,6 +171,61 @@ fn main() {
}
}

/// Flags `-I` supplémentaires pour que clang trouve les en-têtes « freestanding » qu'il
/// embarque normalement lui-même (`stddef.h`, `limits.h`, `stdint.h`).
///
/// Ubuntu scinde libclang : `libclang.so.1` vient du paquet runtime, le répertoire
/// d'en-têtes builtin de `libclang-N-dev`. Avec seulement le premier — le cas courant —
/// parser n'importe quel header réel échoue sur
/// `/usr/include/stdio.h: 'stddef.h' file not found`, parce que la copie de la glibc fait
/// un `#include_next` de celle du compilateur et qu'il n'y en a aucune. Celles de gcc
/// sont interchangeables pour cet usage : on y pointe clang plutôt que d'imposer une
/// seconde toolchain à chaque contributeur.
///
/// Jumeau de `freestanding_header_args()` dans
/// electron/native/pipewire-capture/build.rs, et comme lui ça vit DANS build.rs plutôt
/// que dans scripts/build-linux-compositor-addon.mjs : tant que seul le script posait
/// `BINDGEN_EXTRA_CLANG_ARGS`, un `cargo check -p openscreen-compositor` nu échouait sur
/// une Ubuntu de série — y compris en x86_64.
fn freestanding_header_args() -> Vec<String> {
if let Ok(extra) = env::var("BINDGEN_EXTRA_CLANG_ARGS") {
// Déjà configuré par l'appelant ; bindgen le lit de lui-même.
if !extra.trim().is_empty() {
return Vec::new();
}
}
// Le triplet vendeur n'est PAS codé en dur : c'est `x86_64-linux-gnu` sur Debian/
// Ubuntu amd64, `aarch64-linux-gnu` sur arm64 et `x86_64-pc-linux-gnu` sur Arch.
// Matcher sur le préfixe d'architecture de la CIBLE couvre les trois, et sur une
// machine où un cross-gcc est installé refuse quand même les en-têtes de l'AUTRE
// architecture, dont les largeurs de types seraient fausses.
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_else(|_| env::consts::ARCH.to_string());
let prefix = format!("{arch}-");
let Ok(vendors) = std::fs::read_dir("/usr/lib/gcc") else {
return Vec::new();
};
// Les DEUX en-têtes sont exigés : l'échec observé porte tantôt sur `stddef.h`
// (compositor) tantôt sur `limits.h` (pipewire-capture), et un répertoire qui n'a
// que l'un des deux ne réglerait qu'une moitié du problème tout en ayant l'air
// d'un candidat valable.
let mut dirs: Vec<PathBuf> = vendors
.filter_map(|entry| entry.ok())
.filter(|entry| entry.file_name().to_string_lossy().starts_with(&prefix))
.filter_map(|vendor| std::fs::read_dir(vendor.path()).ok())
.flatten()
.filter_map(|entry| entry.ok())
.map(|entry| entry.path().join("include"))
.filter(|dir| dir.join("limits.h").is_file() && dir.join("stddef.h").is_file())
.collect();
// gcc le plus récent d'abord, pour une machine qui en a plusieurs.
dirs.sort();
dirs.reverse();
dirs.into_iter()
.take(1)
.map(|dir| format!("-I{}", dir.display()))
.collect()
}

/// Ajoute `#[link_name = "<prefix><nom>"]` devant chaque `pub fn` ffmpeg de `ffi.rs`.
///
/// Seul le SYMBOLE importé change ; l'identifiant Rust reste `avformat_open_input`, donc
Expand Down
9 changes: 6 additions & 3 deletions electron/native/pipewire-capture/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,12 @@ fn build_pipewire_shim(root: &Path) {
/// `/usr/include/limits.h: 'limits.h' file not found`, because glibc's copy
/// `#include_next`s the compiler's and there is none. gcc's copies are
/// interchangeable for this purpose, so point clang at those instead of making
/// every contributor install a second toolchain. Mirrors `bindgenClangArgs()` in
/// scripts/build-linux-compositor-addon.mjs, but lives here so that a bare
/// `cargo build` in this directory works too.
/// every contributor install a second toolchain.
///
/// Twin of `freestanding_header_args()` in crates/compositor/build.rs. Both live in
/// build.rs rather than in the npm build scripts so that a bare `cargo build` works
/// too — scripts/build-linux-compositor-addon.mjs used to carry a copy of this, and
/// `cargo check -p openscreen-compositor` stayed broken for as long as it did.
fn freestanding_header_args() -> Vec<String> {
if let Ok(extra) = std::env::var("BINDGEN_EXTRA_CLANG_ARGS") {
// Already configured by the caller; bindgen picks that up on its own.
Expand Down
42 changes: 9 additions & 33 deletions scripts/build-linux-compositor-addon.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -118,38 +118,15 @@ function resolveLibclangDir() {
return found;
}

/**
* On distributions that ship only `libclang.so.1` (no -dev package) clang also
* cannot find its own `stddef.h`. Point it at gcc's copy in that case rather
* than making the caller discover it.
*
* Kept behaviourally identical to `freestanding_header_args()` in
* electron/native/pipewire-capture/build.rs, which is the authority — that one
* runs for a bare `cargo build` too. Two properties matter and both were once
* wrong here: `limits.h` must be required alongside `stddef.h` (the failure
* being fixed is `'limits.h' file not found` — glibc's copy `#include_next`s
* the compiler's), and the newest gcc must be picked deterministically rather
* than whatever `readdirSync` happened to return first.
*/
function bindgenClangArgs() {
if (process.env.BINDGEN_EXTRA_CLANG_ARGS) {
return process.env.BINDGEN_EXTRA_CLANG_ARGS;
}
const gccIncludeRoot = `/usr/lib/gcc/${MULTIARCH}`;
if (!fs.existsSync(gccIncludeRoot)) {
return "";
}
const usable = fs
.readdirSync(gccIncludeRoot)
.map((version) => path.join(gccIncludeRoot, version, "include"))
.filter(
(dir) =>
fs.existsSync(path.join(dir, "limits.h")) && fs.existsSync(path.join(dir, "stddef.h")),
)
.sort()
.reverse();
return usable.length > 0 ? `-I${usable[0]}` : "";
}
// No BINDGEN_EXTRA_CLANG_ARGS is set below, on purpose. On distributions shipping only
// `libclang.so.1` (no -dev package) clang cannot find its own `stddef.h`, and this
// script used to paper over that by pointing bindgen at gcc's copies. That only ever
// covered the build that goes through here: `cargo check -p openscreen-compositor` on a
// stock Ubuntu still died on `'stddef.h' file not found`, x86_64 included. The fallback
// now lives in crates/compositor/build.rs (`freestanding_header_args()`), which covers
// both entry points — and, being the only claimant, cannot lose to a worse guess made
// here. Setting the variable again would suppress it, since build.rs defers to a
// caller-supplied value.

/**
* Prefix applied to every ffmpeg dynamic symbol. Anything unique works; this one is
Expand Down Expand Up @@ -302,7 +279,6 @@ await run("cargo", ["build", "-p", "compositor-view-napi", "--release"], {
FFMPEG_DIR: stagedFfmpegDir,
OPENSCREEN_FFMPEG_SYMBOL_PREFIX: SYMBOL_PREFIX,
LIBCLANG_PATH: resolveLibclangDir(),
BINDGEN_EXTRA_CLANG_ARGS: bindgenClangArgs(),
// `$ORIGIN` is resolved by the dynamic linker against the directory the
// .node itself lives in, so the ffmpeg copies below are found wherever the
// app is installed. Single-quoted on purpose: the shell must not expand it.
Expand Down
Loading