mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
fix(desktop): build with compatible PipeWire headers (#2043)
This commit is contained in:
1 parent
23493b4ac2
commit
fc3065ebe4
1 file changed
+239
-19
+239
-19
@@ -33,6 +33,9 @@ const PUBLIC_DL_BASE: &str = "https://api.fluxer.app/dl";
|
|||||||
const PNPM_VERSION: &str = "10.29.3";
|
const PNPM_VERSION: &str = "10.29.3";
|
||||||
const RUST_TOOLCHAIN: &str = "1.93.0";
|
const RUST_TOOLCHAIN: &str = "1.93.0";
|
||||||
const DEFAULT_DESKTOP_VARIANT: &str = "default";
|
const DEFAULT_DESKTOP_VARIANT: &str = "default";
|
||||||
|
const LINUX_PIPEWIRE_VERSION: &str = "0.3.65";
|
||||||
|
const LINUX_PIPEWIRE_SOURCE_SHA256: &str =
|
||||||
|
"bb76f938136d0ce8c35bffa99e002dc2dbaeab5e14c6c34154e7f750013d1d6b";
|
||||||
const LINUX_LIBFIDO2_VERSION: &str = "1.16.0";
|
const LINUX_LIBFIDO2_VERSION: &str = "1.16.0";
|
||||||
const LINUX_LIBFIDO2_SOURCE_SHA256: &str =
|
const LINUX_LIBFIDO2_SOURCE_SHA256: &str =
|
||||||
"8c2b6fb279b5b42e9ac92ade71832e485852647b53607c43baaafbbcecea04e4";
|
"8c2b6fb279b5b42e9ac92ade71832e485852647b53607c43baaafbbcecea04e4";
|
||||||
@@ -812,6 +815,8 @@ DPkg::Lock::Timeout "120";
|
|||||||
"build-essential",
|
"build-essential",
|
||||||
"binutils",
|
"binutils",
|
||||||
"cmake",
|
"cmake",
|
||||||
|
"meson",
|
||||||
|
"ninja-build",
|
||||||
"nasm",
|
"nasm",
|
||||||
"rpm",
|
"rpm",
|
||||||
"desktop-file-utils",
|
"desktop-file-utils",
|
||||||
@@ -836,10 +841,217 @@ DPkg::Lock::Timeout "120";
|
|||||||
"clang",
|
"clang",
|
||||||
"libpulse-dev",
|
"libpulse-dev",
|
||||||
])?;
|
])?;
|
||||||
|
install_linux_pipewire_headers().await?;
|
||||||
install_linux_libfido2().await?;
|
install_linux_libfido2().await?;
|
||||||
run_command(CommandSpec::new("sudo").args(["gem", "install", "--no-document", "fpm"]))
|
run_command(CommandSpec::new("sudo").args(["gem", "install", "--no-document", "fpm"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn install_linux_pipewire_headers() -> Result<()> {
|
||||||
|
let temp = TempDir::new().context("Failed to create PipeWire header build directory")?;
|
||||||
|
let archive_name = format!("pipewire-{LINUX_PIPEWIRE_VERSION}.tar.gz");
|
||||||
|
let archive_path = temp.path().join(&archive_name);
|
||||||
|
let source_dir = temp.path().join("source");
|
||||||
|
let build_dir = temp.path().join("build");
|
||||||
|
let staging_dir = temp.path().join("stage");
|
||||||
|
let source_url = format!(
|
||||||
|
"https://gitlab.freedesktop.org/pipewire/pipewire/-/archive/{LINUX_PIPEWIRE_VERSION}/{archive_name}"
|
||||||
|
);
|
||||||
|
let multiarch = linux_multiarch()?;
|
||||||
|
let install_library_dir = Path::new("/usr/local/lib").join(&multiarch);
|
||||||
|
let install_pkgconfig_dir = install_library_dir.join("pkgconfig");
|
||||||
|
let libdir_arg = format!("--libdir=lib/{multiarch}");
|
||||||
|
let system_pipewire_library = fs::canonicalize(linux_loader_path("libpipewire-0.3.so.0")?)
|
||||||
|
.context("Failed to resolve the system PipeWire library")?;
|
||||||
|
ensure!(
|
||||||
|
!system_pipewire_library.starts_with("/usr/local"),
|
||||||
|
"Expected the system PipeWire runtime, got {}",
|
||||||
|
system_pipewire_library.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
download_file(&source_url, &archive_path).await?;
|
||||||
|
let archive_sha256 = sha256_file(&archive_path)?;
|
||||||
|
ensure!(
|
||||||
|
archive_sha256 == LINUX_PIPEWIRE_SOURCE_SHA256,
|
||||||
|
"PipeWire source checksum mismatch: expected {}, got {}",
|
||||||
|
LINUX_PIPEWIRE_SOURCE_SHA256,
|
||||||
|
archive_sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::create_dir_all(&source_dir)
|
||||||
|
.with_context(|| format!("Failed to create {}", source_dir.display()))?;
|
||||||
|
run_command(CommandSpec::new("tar").args([
|
||||||
|
"-xzf",
|
||||||
|
archive_path.to_string_lossy().as_ref(),
|
||||||
|
"-C",
|
||||||
|
source_dir.to_string_lossy().as_ref(),
|
||||||
|
"--strip-components=1",
|
||||||
|
]))?;
|
||||||
|
run_command(CommandSpec::new("meson").args([
|
||||||
|
"setup",
|
||||||
|
build_dir.to_string_lossy().as_ref(),
|
||||||
|
source_dir.to_string_lossy().as_ref(),
|
||||||
|
"--buildtype=release",
|
||||||
|
"--default-library=shared",
|
||||||
|
"--prefix=/usr/local",
|
||||||
|
&libdir_arg,
|
||||||
|
"--auto-features=disabled",
|
||||||
|
"-Dexamples=disabled",
|
||||||
|
"-Dtests=disabled",
|
||||||
|
"-Dinstalled_tests=disabled",
|
||||||
|
"-Ddocs=disabled",
|
||||||
|
"-Dman=disabled",
|
||||||
|
"-Dspa-plugins=enabled",
|
||||||
|
"-Dpipewire-alsa=disabled",
|
||||||
|
"-Dpipewire-jack=disabled",
|
||||||
|
"-Dpipewire-v4l2=disabled",
|
||||||
|
"-Dsystemd=disabled",
|
||||||
|
"-Ddbus=disabled",
|
||||||
|
"-Dflatpak=disabled",
|
||||||
|
"-Dsession-managers=[]",
|
||||||
|
"-Dlegacy-rtkit=false",
|
||||||
|
]))?;
|
||||||
|
run_command(CommandSpec::new("meson").args([
|
||||||
|
"compile",
|
||||||
|
"-C",
|
||||||
|
build_dir.to_string_lossy().as_ref(),
|
||||||
|
]))?;
|
||||||
|
run_command(
|
||||||
|
CommandSpec::new("meson")
|
||||||
|
.args([
|
||||||
|
"install",
|
||||||
|
"-C",
|
||||||
|
build_dir.to_string_lossy().as_ref(),
|
||||||
|
"--no-rebuild",
|
||||||
|
])
|
||||||
|
.env("DESTDIR", staging_dir.as_os_str()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let staged_prefix = staging_dir.join("usr/local");
|
||||||
|
let staged_pipewire_headers = staged_prefix.join("include/pipewire-0.3");
|
||||||
|
let staged_spa_headers = staged_prefix.join("include/spa-0.2");
|
||||||
|
let staged_pkgconfig_dir = staged_prefix.join(format!("lib/{multiarch}/pkgconfig"));
|
||||||
|
let install_include_dir = Path::new("/usr/local/include");
|
||||||
|
let install_pipewire_headers = install_include_dir.join("pipewire-0.3");
|
||||||
|
let install_spa_headers = install_include_dir.join("spa-0.2");
|
||||||
|
ensure!(
|
||||||
|
!install_pipewire_headers.exists() && !install_spa_headers.exists(),
|
||||||
|
"PipeWire header overlay already exists under {}",
|
||||||
|
install_include_dir.display()
|
||||||
|
);
|
||||||
|
run_command(CommandSpec::new("sudo").args([
|
||||||
|
"install",
|
||||||
|
"-d",
|
||||||
|
install_include_dir.to_string_lossy().as_ref(),
|
||||||
|
install_pkgconfig_dir.to_string_lossy().as_ref(),
|
||||||
|
]))?;
|
||||||
|
run_command(CommandSpec::new("sudo").args([
|
||||||
|
"cp",
|
||||||
|
"-a",
|
||||||
|
staged_pipewire_headers.to_string_lossy().as_ref(),
|
||||||
|
staged_spa_headers.to_string_lossy().as_ref(),
|
||||||
|
install_include_dir.to_string_lossy().as_ref(),
|
||||||
|
]))?;
|
||||||
|
for pkgconfig_name in ["libpipewire-0.3.pc", "libspa-0.2.pc"] {
|
||||||
|
run_command(
|
||||||
|
CommandSpec::new("sudo").args([
|
||||||
|
"install",
|
||||||
|
"-m",
|
||||||
|
"0644",
|
||||||
|
staged_pkgconfig_dir
|
||||||
|
.join(pkgconfig_name)
|
||||||
|
.to_string_lossy()
|
||||||
|
.as_ref(),
|
||||||
|
install_pkgconfig_dir
|
||||||
|
.join(pkgconfig_name)
|
||||||
|
.to_string_lossy()
|
||||||
|
.as_ref(),
|
||||||
|
]),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let installed_version =
|
||||||
|
output_text(CommandSpec::new("pkg-config").args(["--modversion", "libpipewire-0.3"]))?;
|
||||||
|
ensure!(
|
||||||
|
installed_version == LINUX_PIPEWIRE_VERSION,
|
||||||
|
"Expected PipeWire headers {}, got {}",
|
||||||
|
LINUX_PIPEWIRE_VERSION,
|
||||||
|
installed_version
|
||||||
|
);
|
||||||
|
for (package, expected_include_flag) in [
|
||||||
|
("libpipewire-0.3", "-I/usr/local/include/pipewire-0.3"),
|
||||||
|
("libspa-0.2", "-I/usr/local/include/spa-0.2"),
|
||||||
|
] {
|
||||||
|
let pkgconfig_dir =
|
||||||
|
output_text(CommandSpec::new("pkg-config").args(["--variable=pcfiledir", package]))?;
|
||||||
|
ensure!(
|
||||||
|
Path::new(&pkgconfig_dir) == install_pkgconfig_dir,
|
||||||
|
"Expected {package} metadata in {}, got {}",
|
||||||
|
install_pkgconfig_dir.display(),
|
||||||
|
pkgconfig_dir
|
||||||
|
);
|
||||||
|
let include_dir =
|
||||||
|
output_text(CommandSpec::new("pkg-config").args(["--variable=includedir", package]))?;
|
||||||
|
ensure!(
|
||||||
|
Path::new(&include_dir) == install_include_dir,
|
||||||
|
"Expected {package} headers in {}, got {}",
|
||||||
|
install_include_dir.display(),
|
||||||
|
include_dir
|
||||||
|
);
|
||||||
|
let include_flags =
|
||||||
|
output_text(CommandSpec::new("pkg-config").args(["--cflags-only-I", package]))?;
|
||||||
|
ensure!(
|
||||||
|
include_flags
|
||||||
|
.split_whitespace()
|
||||||
|
.any(|flag| flag == expected_include_flag),
|
||||||
|
"Expected {package} include flag {expected_include_flag}, got {include_flags}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ensure!(
|
||||||
|
install_pipewire_headers
|
||||||
|
.join("pipewire/pipewire.h")
|
||||||
|
.is_file()
|
||||||
|
&& install_spa_headers.join("spa/buffer/meta.h").is_file()
|
||||||
|
&& install_spa_headers.join("spa/param/video/raw.h").is_file(),
|
||||||
|
"PipeWire {} header overlay is incomplete",
|
||||||
|
LINUX_PIPEWIRE_VERSION
|
||||||
|
);
|
||||||
|
let mut local_pipewire_library = None;
|
||||||
|
for entry in fs::read_dir(&install_library_dir)
|
||||||
|
.with_context(|| format!("Failed to read {}", install_library_dir.display()))?
|
||||||
|
{
|
||||||
|
let entry = entry
|
||||||
|
.with_context(|| format!("Failed to inspect {}", install_library_dir.display()))?;
|
||||||
|
if entry
|
||||||
|
.file_name()
|
||||||
|
.to_string_lossy()
|
||||||
|
.starts_with("libpipewire-0.3.")
|
||||||
|
{
|
||||||
|
local_pipewire_library = Some(entry.path());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(path) = local_pipewire_library {
|
||||||
|
bail!(
|
||||||
|
"PipeWire header overlay found unexpected library {}",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let loaded_pipewire_library = fs::canonicalize(linux_loader_path("libpipewire-0.3.so.0")?)
|
||||||
|
.context("Failed to resolve the selected PipeWire library")?;
|
||||||
|
ensure!(
|
||||||
|
loaded_pipewire_library == system_pipewire_library,
|
||||||
|
"PipeWire header overlay changed the runtime from {} to {}",
|
||||||
|
system_pipewire_library.display(),
|
||||||
|
loaded_pipewire_library.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Installed PipeWire {LINUX_PIPEWIRE_VERSION} headers for {}.",
|
||||||
|
system_pipewire_library.display()
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn install_linux_libfido2() -> Result<()> {
|
async fn install_linux_libfido2() -> Result<()> {
|
||||||
let temp = TempDir::new().context("Failed to create libfido2 build directory")?;
|
let temp = TempDir::new().context("Failed to create libfido2 build directory")?;
|
||||||
let archive_name = format!("libfido2-{LINUX_LIBFIDO2_VERSION}.tar.gz");
|
let archive_name = format!("libfido2-{LINUX_LIBFIDO2_VERSION}.tar.gz");
|
||||||
@@ -847,16 +1059,8 @@ async fn install_linux_libfido2() -> Result<()> {
|
|||||||
let source_dir = temp.path().join("source");
|
let source_dir = temp.path().join("source");
|
||||||
let build_dir = temp.path().join("build");
|
let build_dir = temp.path().join("build");
|
||||||
let source_url = format!("https://developers.yubico.com/libfido2/Releases/{archive_name}");
|
let source_url = format!("https://developers.yubico.com/libfido2/Releases/{archive_name}");
|
||||||
let multiarch = output_text(CommandSpec::new("gcc").arg("-print-multiarch"))?;
|
let multiarch = linux_multiarch()?;
|
||||||
let multiarch = multiarch.trim();
|
let install_library_dir = Path::new("/usr/local/lib").join(&multiarch);
|
||||||
ensure!(
|
|
||||||
!multiarch.is_empty()
|
|
||||||
&& multiarch
|
|
||||||
.bytes()
|
|
||||||
.all(|byte| { byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_' }),
|
|
||||||
"gcc returned invalid multiarch tuple: {multiarch:?}"
|
|
||||||
);
|
|
||||||
let install_library_dir = Path::new("/usr/local/lib").join(multiarch);
|
|
||||||
let install_library_arg = format!("-DCMAKE_INSTALL_LIBDIR=lib/{multiarch}");
|
let install_library_arg = format!("-DCMAKE_INSTALL_LIBDIR=lib/{multiarch}");
|
||||||
|
|
||||||
download_file(&source_url, &archive_path).await?;
|
download_file(&source_url, &archive_path).await?;
|
||||||
@@ -945,15 +1149,7 @@ async fn install_linux_libfido2() -> Result<()> {
|
|||||||
);
|
);
|
||||||
let installed_library = fs::canonicalize(&installed_soname)
|
let installed_library = fs::canonicalize(&installed_soname)
|
||||||
.with_context(|| format!("Failed to resolve {}", installed_soname.display()))?;
|
.with_context(|| format!("Failed to resolve {}", installed_soname.display()))?;
|
||||||
let loader_cache = output_text(CommandSpec::new("ldconfig").arg("-p"))?;
|
let loader_path = linux_loader_path("libfido2.so.1")?;
|
||||||
let loader_path = loader_cache
|
|
||||||
.lines()
|
|
||||||
.find_map(|line| {
|
|
||||||
let (library, path) = line.trim().split_once("=>")?;
|
|
||||||
(library.split_whitespace().next() == Some("libfido2.so.1"))
|
|
||||||
.then(|| PathBuf::from(path.trim()))
|
|
||||||
})
|
|
||||||
.context("ldconfig did not resolve libfido2.so.1")?;
|
|
||||||
let loaded_library = fs::canonicalize(&loader_path)
|
let loaded_library = fs::canonicalize(&loader_path)
|
||||||
.with_context(|| format!("Failed to resolve {}", loader_path.display()))?;
|
.with_context(|| format!("Failed to resolve {}", loader_path.display()))?;
|
||||||
ensure!(
|
ensure!(
|
||||||
@@ -967,6 +1163,30 @@ async fn install_linux_libfido2() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn linux_multiarch() -> Result<String> {
|
||||||
|
let multiarch = output_text(CommandSpec::new("gcc").arg("-print-multiarch"))?;
|
||||||
|
ensure!(
|
||||||
|
!multiarch.is_empty()
|
||||||
|
&& multiarch
|
||||||
|
.bytes()
|
||||||
|
.all(|byte| byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_'),
|
||||||
|
"gcc returned invalid multiarch tuple: {multiarch:?}"
|
||||||
|
);
|
||||||
|
Ok(multiarch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linux_loader_path(library_name: &str) -> Result<PathBuf> {
|
||||||
|
let loader_cache = output_text(CommandSpec::new("ldconfig").arg("-p"))?;
|
||||||
|
loader_cache
|
||||||
|
.lines()
|
||||||
|
.find_map(|line| {
|
||||||
|
let (library, path) = line.trim().split_once("=>")?;
|
||||||
|
(library.split_whitespace().next() == Some(library_name))
|
||||||
|
.then(|| PathBuf::from(path.trim()))
|
||||||
|
})
|
||||||
|
.with_context(|| format!("ldconfig did not resolve {library_name}"))
|
||||||
|
}
|
||||||
|
|
||||||
fn rewrite_ubuntu_ports_sources() -> Result<()> {
|
fn rewrite_ubuntu_ports_sources() -> Result<()> {
|
||||||
let apt = Path::new("/etc/apt");
|
let apt = Path::new("/etc/apt");
|
||||||
if !apt.exists() {
|
if !apt.exists() {
|
||||||
|
|||||||
Reference in new issue
Block a user