Skip to content

Commit 30c2b1c

Browse files
authored
improve dynamic linking (#139)
1 parent bdabfd9 commit 30c2b1c

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

build.rs

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -242,18 +242,31 @@ fn generate_bindings(ffmpeg_include_dir: &Path, headers: &[PathBuf]) -> Bindings
242242
.expect("Binding generation failed.")
243243
}
244244

245-
fn static_linking_with_libs_dir(library_names: &[&str], ffmpeg_libs_dir: &Path) {
246-
println!("cargo:rustc-link-search=native={}", ffmpeg_libs_dir);
245+
fn linking_with_libs_dir(library_names: &[&str], ffmpeg_libs_dir: &Path, mode: FfmpegLinkMode) {
246+
println!("cargo:rustc-link-search=native={ffmpeg_libs_dir}");
247247
for library_name in library_names {
248-
println!("cargo:rustc-link-lib=static={}", library_name);
248+
println!(
249+
"cargo:rustc-link-lib={}={library_name}",
250+
match mode {
251+
FfmpegLinkMode::Dynamic => "dylib",
252+
FfmpegLinkMode::Static => "static",
253+
}
254+
);
249255
}
250256
}
251257

258+
#[derive(Clone, Copy)]
259+
enum FfmpegLinkMode {
260+
Static,
261+
Dynamic,
262+
}
263+
252264
#[allow(dead_code)]
253265
pub struct EnvVars {
254266
docs_rs: Option<String>,
255267
out_dir: Option<PathBuf>,
256268
ffmpeg_include_dir: Option<PathBuf>,
269+
ffmpeg_link_mode: Option<FfmpegLinkMode>,
257270
ffmpeg_dll_path: Option<PathBuf>,
258271
ffmpeg_pkg_config_path: Option<PathBuf>,
259272
ffmpeg_libs_dir: Option<PathBuf>,
@@ -269,6 +282,7 @@ impl EnvVars {
269282
println!("cargo:rerun-if-env-changed=FFMPEG_PKG_CONFIG_PATH");
270283
println!("cargo:rerun-if-env-changed=FFMPEG_LIBS_DIR");
271284
println!("cargo:rerun-if-env-changed=FFMPEG_BINDING_PATH");
285+
println!("cargo:rerun-if-env-changed=FFMPEG_LINK_MODE");
272286
Self {
273287
docs_rs: env::var("DOCS_RS").ok(),
274288
out_dir: env::var("OUT_DIR").ok().map(remove_verbatim),
@@ -277,6 +291,12 @@ impl EnvVars {
277291
ffmpeg_pkg_config_path: env::var("FFMPEG_PKG_CONFIG_PATH").ok().map(remove_verbatim),
278292
ffmpeg_libs_dir: env::var("FFMPEG_LIBS_DIR").ok().map(remove_verbatim),
279293
ffmpeg_binding_path: env::var("FFMPEG_BINDING_PATH").ok().map(remove_verbatim),
294+
ffmpeg_link_mode: match env::var("FFMPEG_LINK_MODE").ok().as_deref() {
295+
Some("static") => Some(FfmpegLinkMode::Static),
296+
Some("dynamic") => Some(FfmpegLinkMode::Dynamic),
297+
Some(r) => panic!("invalid FFMPEG_LINK_MODE value {r}, expected [static,dynamic]"),
298+
None => None,
299+
},
280300
}
281301
}
282302
}
@@ -359,8 +379,18 @@ mod vcpkg_linking {
359379
}
360380
}
361381

362-
fn dynamic_linking(env_vars: &EnvVars) {
382+
fn dynamic_linking(mut env_vars: EnvVars) {
363383
let ffmpeg_dll_path = env_vars.ffmpeg_dll_path.as_ref().unwrap();
384+
if ffmpeg_dll_path.is_dir() {
385+
if env_vars.ffmpeg_libs_dir.is_none() {
386+
env_vars.ffmpeg_libs_dir = Some(ffmpeg_dll_path.clone());
387+
}
388+
if env_vars.ffmpeg_link_mode.is_none() {
389+
env_vars.ffmpeg_link_mode = Some(FfmpegLinkMode::Dynamic);
390+
}
391+
392+
return linking(env_vars);
393+
}
364394

365395
let output_binding_path = &env_vars.out_dir.as_ref().unwrap().join("binding.rs");
366396

@@ -396,12 +426,12 @@ fn dynamic_linking(env_vars: &EnvVars) {
396426
}
397427
}
398428

399-
fn static_linking(env_vars: &EnvVars) {
429+
fn linking(env_vars: EnvVars) {
400430
let output_binding_path = &env_vars.out_dir.as_ref().unwrap().join("binding.rs");
401431

402432
#[cfg(not(target_os = "windows"))]
403433
{
404-
fn static_linking_with_pkg_config_and_bindgen(
434+
fn linking_with_pkg_config_and_bindgen(
405435
env_vars: &EnvVars,
406436
output_binding_path: &Path,
407437
) -> Result<(), pkg_config::Error> {
@@ -430,10 +460,14 @@ fn static_linking(env_vars: &EnvVars) {
430460
);
431461
}
432462
env::set_var("PKG_CONFIG_PATH", ffmpeg_pkg_config_path);
433-
static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path)
463+
linking_with_pkg_config_and_bindgen(&env_vars, output_binding_path)
434464
.expect("Static linking with pkg-config failed.");
435465
} else if let Some(ffmpeg_libs_dir) = env_vars.ffmpeg_libs_dir.as_ref() {
436-
static_linking_with_libs_dir(&*LIBS, ffmpeg_libs_dir);
466+
linking_with_libs_dir(
467+
&*LIBS,
468+
ffmpeg_libs_dir,
469+
env_vars.ffmpeg_link_mode.unwrap_or(FfmpegLinkMode::Static),
470+
);
437471
if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() {
438472
use_prebuilt_binding(ffmpeg_binding_path, output_binding_path);
439473
} else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() {
@@ -460,7 +494,7 @@ Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installe
460494
#[cfg(feature = "link_system_ffmpeg")]
461495
if !success {
462496
if let Err(e) =
463-
static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path)
497+
linking_with_pkg_config_and_bindgen(&env_vars, output_binding_path)
464498
{
465499
error.push('\n');
466500
error.push_str(&format!("Link system FFmpeg failed: {:?}", e));
@@ -471,9 +505,10 @@ Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installe
471505
}
472506
#[cfg(feature = "link_vcpkg_ffmpeg")]
473507
if !success {
474-
if let Err(e) =
475-
vcpkg_linking::linking_with_vcpkg_and_bindgen(env_vars, output_binding_path)
476-
{
508+
if let Err(e) = vcpkg_linking::linking_with_vcpkg_and_bindgen(
509+
&env_vars,
510+
output_binding_path,
511+
) {
477512
error.push('\n');
478513
error.push_str(&format!("Link vcpkg FFmpeg failed: {:?}", e));
479514
} else {
@@ -490,7 +525,11 @@ Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installe
490525
#[cfg(target_os = "windows")]
491526
{
492527
if let Some(ffmpeg_libs_dir) = env_vars.ffmpeg_libs_dir.as_ref() {
493-
static_linking_with_libs_dir(&*LIBS, ffmpeg_libs_dir);
528+
linking_with_libs_dir(
529+
&*LIBS,
530+
ffmpeg_libs_dir,
531+
env_vars.ffmpeg_link_mode.unwrap_or(FfmpegLinkMode::Static),
532+
);
494533
if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() {
495534
use_prebuilt_binding(ffmpeg_binding_path, output_binding_path);
496535
} else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() {
@@ -502,7 +541,7 @@ Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installe
502541
}
503542
} else {
504543
#[cfg(feature = "link_vcpkg_ffmpeg")]
505-
vcpkg_linking::linking_with_vcpkg_and_bindgen(env_vars, output_binding_path)
544+
vcpkg_linking::linking_with_vcpkg_and_bindgen(&env_vars, output_binding_path)
506545
.expect("Linking FFmpeg with vcpkg failed.");
507546
#[cfg(not(feature = "link_vcpkg_ffmpeg"))]
508547
panic!(
@@ -516,7 +555,7 @@ Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg provided by vcpkg.
516555
}
517556
}
518557

519-
fn docs_rs_linking(env_vars: &EnvVars) {
558+
fn docs_rs_linking(env_vars: EnvVars) {
520559
// If it's a documentation generation from docs.rs, just copy the bindings
521560
// generated locally to `OUT_DIR`. We do this because the building
522561
// environment of docs.rs doesn't have an network connection, so we cannot
@@ -531,11 +570,11 @@ fn docs_rs_linking(env_vars: &EnvVars) {
531570
fn main() {
532571
let env_vars = EnvVars::init();
533572
if env_vars.docs_rs.is_some() {
534-
docs_rs_linking(&env_vars);
573+
docs_rs_linking(env_vars);
535574
} else if env_vars.ffmpeg_dll_path.is_some() {
536-
dynamic_linking(&env_vars);
575+
dynamic_linking(env_vars);
537576
} else {
538577
// fallback to static linking
539-
static_linking(&env_vars);
578+
linking(env_vars);
540579
}
541580
}

0 commit comments

Comments
 (0)