1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Build rust library and bindings for dav1d.
16 
17 use std::env;
18 use std::path::Path;
19 use std::path::PathBuf;
20 
21 extern crate pkg_config;
22 
main()23 fn main() {
24     println!("cargo:rerun-if-changed=build.rs");
25 
26     let build_target = std::env::var("TARGET").unwrap();
27     let build_dir = if build_target.contains("android") {
28         if build_target.contains("x86_64") {
29             "build.android/x86_64"
30         } else if build_target.contains("x86") {
31             "build.android/x86"
32         } else if build_target.contains("aarch64") {
33             "build.android/aarch64"
34         } else if build_target.contains("arm") {
35             "build.android/arm"
36         } else {
37             panic!("Unknown target_arch for android. Must be one of x86, x86_64, arm, aarch64.");
38         }
39     } else {
40         "build"
41     };
42 
43     let project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
44     // Prefer locally built dav1d if available.
45     let abs_library_dir = PathBuf::from(&project_root).join("dav1d");
46     let abs_object_dir = PathBuf::from(&abs_library_dir).join(build_dir).join("src");
47     let library_file = PathBuf::from(&abs_object_dir).join("libdav1d.a");
48     let mut include_paths: Vec<String> = Vec::new();
49     if Path::new(&library_file).exists() {
50         println!("cargo:rustc-link-search={}", abs_object_dir.display());
51         println!("cargo:rustc-link-lib=static=dav1d");
52         let version_dir = PathBuf::from(&abs_library_dir)
53             .join(build_dir)
54             .join("include")
55             .join("dav1d");
56         include_paths.push(format!("-I{}", version_dir.display()));
57         let include_dir = PathBuf::from(&abs_library_dir).join("include");
58         include_paths.push(format!("-I{}", include_dir.display()));
59     } else {
60         let library = pkg_config::Config::new().probe("dav1d");
61         if library.is_err() {
62             println!(
63                 "dav1d could not be found with pkg-config. Install the system library or run dav1d.cmd"
64             );
65         }
66         let library = library.unwrap();
67         for lib in &library.libs {
68             println!("cargo:rustc-link-lib={lib}");
69         }
70         for link_path in &library.link_paths {
71             println!("cargo:rustc-link-search={}", link_path.display());
72         }
73         for include_path in &library.include_paths {
74             include_paths.push(format!("-I{}", include_path.display()));
75         }
76     }
77 
78     // Generate bindings.
79     let header_file = PathBuf::from(&project_root).join("wrapper.h");
80     let outdir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
81     let outfile = PathBuf::from(&outdir).join("dav1d_bindgen.rs");
82     let mut bindings = bindgen::Builder::default()
83         .header(header_file.into_os_string().into_string().unwrap())
84         .clang_args(&include_paths)
85         .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
86         .layout_tests(false)
87         .generate_comments(false);
88     let allowlist_items = &[
89         "dav1d_close",
90         "dav1d_data_unref",
91         "dav1d_data_wrap",
92         "dav1d_default_settings",
93         "dav1d_error",
94         "dav1d_get_picture",
95         "dav1d_open",
96         "dav1d_picture_unref",
97         "dav1d_send_data",
98     ];
99     for allowlist_item in allowlist_items {
100         bindings = bindings.allowlist_item(allowlist_item);
101     }
102     let bindings = bindings
103         .generate()
104         .unwrap_or_else(|_| panic!("Unable to generate bindings for dav1d."));
105     bindings
106         .write_to_file(outfile.as_path())
107         .unwrap_or_else(|_| panic!("Couldn't write bindings for dav1d"));
108 }
109