fix(windows): vendor audiopus_sys + patch libopus for clang-cl SIMD
Some checks failed
Mirror to GitHub / mirror (push) Failing after 35s
Build Release Binaries / build-amd64 (push) Has been cancelled

cargo-xwin drives the Windows MSVC cross-compile via clang-cl, under
which CMake sets MSVC=1 — causing libopus 1.3.1's `if(NOT MSVC)` guards
to skip the per-file `-msse4.1` / `-mssse3` COMPILE_FLAGS that its x86
SIMD source files need. Clang-cl (unlike real cl.exe) still honors
Clang's target-feature system, so those files then fail to compile
with "always_inline function '_mm_cvtepi16_epi32' requires target
feature 'sse4.1'" errors across silk/NSQ_sse4_1.c, NSQ_del_dec_sse4_1.c,
and VQ_WMat_EC_sse4_1.c.

Earlier attempts to fix this downstream (cargo-xwin toolchain file,
override.cmake CMAKE_C_COMPILE_OBJECT <FLAGS> replace, CFLAGS env vars)
all failed because cargo-xwin rewrites override.cmake from scratch on
every `cargo xwin build` invocation and cmake-rs's -DCMAKE_C_FLAGS=
assembly happens before toolchain FORCE sets propagate.

Fixing it upstream at the source: vendor audiopus_sys 0.2.2 into
vendor/audiopus_sys, patch its bundled opus/CMakeLists.txt to introduce
an MSVC_CL var (true only when CMAKE_C_COMPILER_ID == "MSVC", i.e. real
cl.exe), and flip the eight `if(NOT MSVC)` SIMD guards to
`if(NOT MSVC_CL)`. Clang-cl then gets the GCC-style per-file flags and
the SSE4.1 sources build cleanly. Also flip the `if(MSVC)` global /arch
block at line 445 to `if(MSVC_CL)` so only cl.exe applies /arch:AVX and
clang-cl relies purely on per-file flags (no global/per-file mixing).

Wire via [patch.crates-io] in the workspace root Cargo.toml; the patch
is resolved relative to the workspace root as `vendor/audiopus_sys`.

Upstream context: xiph/opus#256, xiph/opus PR #257 (both stale).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-10 14:12:59 +04:00
parent 53f57eea07
commit 0683dde5d3
423 changed files with 103000 additions and 2 deletions

149
vendor/audiopus_sys/build.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
#![deny(rust_2018_idioms)]
#[cfg(feature = "generate_binding")]
use std::path::PathBuf;
use std::{env, fmt::Display, path::Path};
/// Outputs the library-file's prefix as word usable for actual arguments on
/// commands or paths.
const fn rustc_linking_word(is_static_link: bool) -> &'static str {
if is_static_link {
"static"
} else {
"dylib"
}
}
/// Generates a new binding at `src/lib.rs` using `src/wrapper.h`.
#[cfg(feature = "generate_binding")]
fn generate_binding() {
const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_upper_case_globals)]\n\
#![allow(non_camel_case_types)]\n\
#![allow(non_snake_case)]\n";
let bindings = bindgen::Builder::default()
.header("src/wrapper.h")
.raw_line(ALLOW_UNCONVENTIONALS)
.generate()
.expect("Unable to generate binding");
let binding_target_path = PathBuf::new().join("src").join("lib.rs");
bindings
.write_to_file(binding_target_path)
.expect("Could not write binding to the file at `src/lib.rs`");
println!("cargo:info=Successfully generated binding.");
}
fn build_opus(is_static: bool) {
let opus_path = Path::new("opus");
println!(
"cargo:info=Opus source path used: {:?}.",
opus_path
.canonicalize()
.expect("Could not canonicalise to absolute path")
);
println!("cargo:info=Building Opus via CMake.");
let opus_build_dir = cmake::build(opus_path);
link_opus(is_static, opus_build_dir.display())
}
fn link_opus(is_static: bool, opus_build_dir: impl Display) {
let is_static_text = rustc_linking_word(is_static);
println!(
"cargo:info=Linking Opus as {} lib: {}",
is_static_text, opus_build_dir
);
println!("cargo:rustc-link-lib={}=opus", is_static_text);
println!("cargo:rustc-link-search=native={}/lib", opus_build_dir);
}
#[cfg(any(unix, target_env = "gnu"))]
fn find_via_pkg_config(is_static: bool) -> bool {
pkg_config::Config::new()
.statik(is_static)
.probe("opus")
.is_ok()
}
/// Based on the OS or target environment we are building for,
/// this function will return an expected default library linking method.
///
/// If we build for Windows, MacOS, or Linux with musl, we will link statically.
/// However, if you build for Linux without musl, we will link dynamically.
///
/// **Info**:
/// This is a helper-function and may not be called if
/// if the `static`-feature is enabled, the environment variable
/// `LIBOPUS_STATIC` or `OPUS_STATIC` is set.
fn default_library_linking() -> bool {
#[cfg(any(windows, target_os = "macos", target_env = "musl"))]
{
true
}
#[cfg(any(target_os = "freebsd", all(unix, target_env = "gnu")))]
{
false
}
}
fn find_installed_opus() -> Option<String> {
if let Ok(lib_directory) = env::var("LIBOPUS_LIB_DIR") {
Some(lib_directory)
} else if let Ok(lib_directory) = env::var("OPUS_LIB_DIR") {
Some(lib_directory)
} else {
None
}
}
fn is_static_build() -> bool {
if cfg!(feature = "static") && cfg!(feature = "dynamic") {
default_library_linking()
} else if cfg!(feature = "static")
|| env::var("LIBOPUS_STATIC").is_ok()
|| env::var("OPUS_STATIC").is_ok()
{
println!("cargo:info=Static feature or environment variable found.");
true
} else if cfg!(feature = "dynamic") {
println!("cargo:info=Dynamic feature enabled.");
false
} else {
println!("cargo:info=No feature or environment variable found, linking by default.");
default_library_linking()
}
}
fn main() {
#[cfg(feature = "generate_binding")]
generate_binding();
let is_static = is_static_build();
#[cfg(any(unix, target_env = "gnu"))]
{
if std::env::var("LIBOPUS_NO_PKG").is_ok() || std::env::var("OPUS_NO_PKG").is_ok() {
println!("cargo:info=Bypassed `pkg-config`.");
} else if find_via_pkg_config(is_static) {
println!("cargo:info=Found `Opus` via `pkg_config`.");
return;
} else {
println!("cargo:info=`pkg_config` could not find `Opus`.");
}
}
if let Some(installed_opus) = find_installed_opus() {
link_opus(is_static, installed_opus);
} else {
build_opus(is_static);
}
}