Avoid using "static" functions in build script (#40)

* Move fetch & early return into fn build

* Pass ffmpeg_version as parameter

* Pass source_dir as parameter

* Create rustc_link_extralibs

* Use local variable instead of search()

* Pass OUT_DIR to the build function

* Return install_dir from build function

* Parametrize ffmpeg_major_version

* Remove duplicate import
This commit is contained in:
FreezyLemon 2024-04-28 01:58:42 +02:00 committed by GitHub
parent 22fda65cda
commit 159e6f924d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -6,7 +6,7 @@ use std::env;
use std::fmt::Write as FmtWrite; use std::fmt::Write as FmtWrite;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Write}; use std::io::{self, BufRead, BufReader, Write};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::str; use std::str;
@ -424,38 +424,23 @@ fn ffmpeg_version() -> String {
.replace("ffmpeg-", "") .replace("ffmpeg-", "")
} }
fn ffmpeg_major_version() -> u32 { fn get_major_version(version_string: &str) -> u32 {
ffmpeg_version().split('.').next().unwrap().parse().unwrap() version_string.split('.').next().unwrap().parse().unwrap()
} }
fn output() -> PathBuf { fn output() -> PathBuf {
PathBuf::from(env::var("OUT_DIR").unwrap()) PathBuf::from(env::var("OUT_DIR").unwrap())
} }
fn source() -> PathBuf { fn fetch(source_dir: &Path, ffmpeg_version: &str) -> io::Result<()> {
output().join(format!("ffmpeg-{}", ffmpeg_version())) let _ = std::fs::remove_dir_all(source_dir);
}
fn search() -> PathBuf {
let mut absolute = env::current_dir().unwrap();
absolute.push(&output());
absolute.push("dist");
absolute
}
fn fetch() -> io::Result<()> {
let output_base_path = output();
let clone_dest_dir = format!("ffmpeg-{}", ffmpeg_version());
let _ = std::fs::remove_dir_all(output_base_path.join(&clone_dest_dir));
let status = Command::new("git") let status = Command::new("git")
.current_dir(&output_base_path)
.arg("clone") .arg("clone")
.arg("--depth=1") .arg("--depth=1")
.arg("-b") .arg("-b")
.arg(format!("n{}", ffmpeg_version())) .arg(format!("n{ffmpeg_version}"))
.arg("https://github.com/FFmpeg/FFmpeg") .arg("https://github.com/FFmpeg/FFmpeg")
.arg(&clone_dest_dir) .arg(source_dir)
.status()?; .status()?;
if status.success() { if status.success() {
@ -520,8 +505,15 @@ static EXTERNAL_BUILD_LIBS: &[(&str, &str)] = &[
("SSH", "libssh"), ("SSH", "libssh"),
]; ];
fn build() -> io::Result<()> { fn build(out_dir: &Path, ffmpeg_version: &str) -> io::Result<PathBuf> {
let source_dir = source(); let source_dir = out_dir.join(format!("ffmpeg-{ffmpeg_version}"));
let install_dir = out_dir.join("dist");
if install_dir.join("lib").join("libavutil.a").exists() {
rustc_link_extralibs(&source_dir);
return Ok(install_dir);
}
fetch(&source_dir, ffmpeg_version)?;
// Command's path is not relative to command's current_dir // Command's path is not relative to command's current_dir
let configure_path = source_dir.join("configure"); let configure_path = source_dir.join("configure");
@ -529,7 +521,7 @@ fn build() -> io::Result<()> {
let mut configure = Command::new(&configure_path); let mut configure = Command::new(&configure_path);
configure.current_dir(&source_dir); configure.current_dir(&source_dir);
configure.arg(format!("--prefix={}", search().to_string_lossy())); configure.arg(format!("--prefix={}", install_dir.to_string_lossy()));
if env::var("TARGET").unwrap() != env::var("HOST").unwrap() { if env::var("TARGET").unwrap() != env::var("HOST").unwrap() {
// Rust targets are subtly different than naming scheme for compiler prefixes. // Rust targets are subtly different than naming scheme for compiler prefixes.
@ -582,7 +574,7 @@ fn build() -> io::Result<()> {
// the binary using ffmpeg-sys cannot be redistributed // the binary using ffmpeg-sys cannot be redistributed
configure.switch("BUILD_LICENSE_NONFREE", "nonfree"); configure.switch("BUILD_LICENSE_NONFREE", "nonfree");
let ffmpeg_major_version: u32 = ffmpeg_major_version(); let ffmpeg_major_version: u32 = get_major_version(ffmpeg_version);
// configure building libraries based on features // configure building libraries based on features
for lib in LIBRARIES for lib in LIBRARIES
@ -628,7 +620,7 @@ fn build() -> io::Result<()> {
// run make // run make
if !Command::new("make") if !Command::new("make")
.arg(format!("-j{num_jobs}")) .arg(format!("-j{num_jobs}"))
.current_dir(&source()) .current_dir(&source_dir)
.status()? .status()?
.success() .success()
{ {
@ -637,7 +629,7 @@ fn build() -> io::Result<()> {
// run make install // run make install
if !Command::new("make") if !Command::new("make")
.current_dir(&source()) .current_dir(&source_dir)
.arg("install") .arg("install")
.status()? .status()?
.success() .success()
@ -645,7 +637,28 @@ fn build() -> io::Result<()> {
return Err(io::Error::new(io::ErrorKind::Other, "make install failed")); return Err(io::Error::new(io::ErrorKind::Other, "make install failed"));
} }
Ok(()) rustc_link_extralibs(&source_dir);
Ok(install_dir)
}
fn rustc_link_extralibs(source_dir: &Path) {
let config_mak = source_dir.join("ffbuild").join("config.mak");
let file = File::open(config_mak).unwrap();
let reader = BufReader::new(file);
let extra_libs = reader
.lines()
.find(|line| line.as_ref().unwrap().starts_with("EXTRALIBS"))
.map(|line| line.unwrap())
.unwrap();
let linker_args = extra_libs.split('=').last().unwrap().split(' ');
let include_libs = linker_args
.filter(|v| v.starts_with("-l"))
.map(|flag| &flag[2..]);
for lib in include_libs {
println!("cargo:rustc-link-lib={lib}");
}
} }
#[cfg(not(target_env = "msvc"))] #[cfg(not(target_env = "msvc"))]
@ -670,8 +683,6 @@ fn try_vcpkg(statik: bool) -> Option<Vec<PathBuf>> {
// add well known package manager lib paths us as homebrew (or macports) // add well known package manager lib paths us as homebrew (or macports)
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn add_pkg_config_path() { fn add_pkg_config_path() {
use std::path::Path;
let pc_path = pkg_config::get_variable("pkg-config", "pc_path").unwrap(); let pc_path = pkg_config::get_variable("pkg-config", "pc_path").unwrap();
// append M1 homebrew pkgconfig path // append M1 homebrew pkgconfig path
let brew_pkgconfig = cfg!(target_arch = "aarch64") let brew_pkgconfig = cfg!(target_arch = "aarch64")
@ -919,43 +930,20 @@ fn link_to_libraries(statik: bool) {
} }
fn main() { fn main() {
let out_dir = output();
let statik = cargo_feature_enabled("static"); let statik = cargo_feature_enabled("static");
let ffmpeg_major_version: u32 = ffmpeg_major_version(); let ffmpeg_version = ffmpeg_version();
let ffmpeg_major_version: u32 = get_major_version(&ffmpeg_version);
let include_paths: Vec<PathBuf> = if cargo_feature_enabled("build") { let include_paths: Vec<PathBuf> = if cargo_feature_enabled("build") {
let install_dir = build(&out_dir, &ffmpeg_version).unwrap();
println!( println!(
"cargo:rustc-link-search=native={}", "cargo:rustc-link-search=native={}",
search().join("lib").to_string_lossy() install_dir.join("lib").to_string_lossy()
); );
link_to_libraries(statik); link_to_libraries(statik);
if fs::metadata(search().join("lib").join("libavutil.a")).is_err() {
fs::create_dir_all(output()).expect("failed to create build directory");
fetch().unwrap();
build().unwrap();
}
// Check additional required libraries. vec![install_dir.join("include")]
{
let config_mak = source().join("ffbuild/config.mak");
let file = File::open(config_mak).unwrap();
let reader = BufReader::new(file);
let extra_libs = reader
.lines()
.find(|line| line.as_ref().unwrap().starts_with("EXTRALIBS"))
.map(|line| line.unwrap())
.unwrap();
let linker_args = extra_libs.split('=').last().unwrap().split(' ');
let include_libs = linker_args
.filter(|v| v.starts_with("-l"))
.map(|flag| &flag[2..]);
for lib in include_libs {
println!("cargo:rustc-link-lib={}", lib);
}
}
vec![search().join("include")]
} }
// Use prebuilt library // Use prebuilt library
else if let Ok(ffmpeg_dir) = env::var("FFMPEG_DIR") { else if let Ok(ffmpeg_dir) = env::var("FFMPEG_DIR") {
@ -1111,6 +1099,6 @@ fn main() {
// Write the bindings to the $OUT_DIR/bindings.rs file. // Write the bindings to the $OUT_DIR/bindings.rs file.
bindings bindings
.write_to_file(output().join("bindings.rs")) .write_to_file(out_dir.join("bindings.rs"))
.expect("Couldn't write bindings!"); .expect("Couldn't write bindings!");
} }