1 // Copyright 2021 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use anyhow::Result;
6
7 #[cfg(feature = "virgl_renderer")]
8 use anyhow::bail;
9 #[cfg(feature = "virgl_renderer")]
10 use std::env;
11 #[cfg(feature = "virgl_renderer")]
12 use std::fs;
13 #[cfg(feature = "virgl_renderer")]
14 use std::path::Path;
15 #[cfg(feature = "virgl_renderer")]
16 use std::path::PathBuf;
17 #[cfg(feature = "virgl_renderer")]
18 use std::process::Command;
19
20 #[cfg(feature = "virgl_renderer")]
21 const MINIGBM_SRC: &str = "../../minigbm";
22 #[cfg(feature = "virgl_renderer")]
23 const VIRGLRENDERER_SRC: &str = "../../virglrenderer";
24
25 #[cfg(feature = "virgl_renderer")]
is_native_build() -> bool26 fn is_native_build() -> bool {
27 env::var("HOST").unwrap() == env::var("TARGET").unwrap()
28 }
29
30 /// Returns the target triplet prefix for gcc commands. No prefix is required
31 /// for native builds.
32 #[cfg(feature = "virgl_renderer")]
get_cross_compile_prefix() -> String33 fn get_cross_compile_prefix() -> String {
34 if is_native_build() {
35 return String::from("");
36 }
37
38 let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
39 let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
40 let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
41 return format!("{}-{}-{}-", arch, os, env);
42 }
43
44 /// For cross-compilation with meson, we need to pick a cross-file, which
45 /// live in /usr/local/share/meson/cross.
46 #[cfg(feature = "virgl_renderer")]
get_meson_cross_args() -> Vec<String>47 fn get_meson_cross_args() -> Vec<String> {
48 if is_native_build() {
49 Vec::new()
50 } else {
51 vec![
52 "--cross-file".to_string(),
53 env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
54 ]
55 }
56 }
57
58 #[cfg(feature = "virgl_renderer")]
build_minigbm(out_dir: &Path) -> Result<()>59 fn build_minigbm(out_dir: &Path) -> Result<()> {
60 let lib_path = out_dir.join("libgbm.a");
61 if lib_path.exists() {
62 return Ok(());
63 }
64
65 if !Path::new(MINIGBM_SRC).join(".git").exists() {
66 bail!(
67 "{} source does not exist, did you forget to \
68 `git submodule update --init`?",
69 MINIGBM_SRC
70 );
71 }
72
73 let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
74 let status = Command::new("make")
75 .env("MAKEFLAGS", make_flags)
76 .env("CROSS_COMPILE", get_cross_compile_prefix())
77 .arg(format!("OUT={}", out_dir.display()))
78 .arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
79 .current_dir(MINIGBM_SRC)
80 .status()?;
81 if !status.success() {
82 bail!("make failed with status: {}", status);
83 }
84
85 // minigbm will be linked using the name gbm, make sure it can be found.
86 fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
87 Ok(())
88 }
89
90 #[cfg(feature = "virgl_renderer")]
build_virglrenderer(out_dir: &Path) -> Result<()>91 fn build_virglrenderer(out_dir: &Path) -> Result<()> {
92 let lib_path = out_dir.join("src/libvirglrenderer.a");
93 if lib_path.exists() {
94 return Ok(());
95 }
96
97 if !Path::new(VIRGLRENDERER_SRC).join(".git").exists() {
98 bail!(
99 "{} source does not exist, did you forget to \
100 `git submodule update --init`?",
101 VIRGLRENDERER_SRC
102 );
103 }
104
105 let platforms = [
106 "egl",
107 #[cfg(feature = "x")]
108 "glx",
109 ];
110
111 let minigbm_src_abs = PathBuf::from(MINIGBM_SRC).canonicalize()?;
112 let status = Command::new("meson")
113 .env("PKG_CONFIG_PATH", &minigbm_src_abs)
114 .arg("setup")
115 .arg(format!("-Dplatforms={}", platforms.join(",")))
116 .arg("-Ddefault_library=static")
117 .args(get_meson_cross_args())
118 .arg(out_dir.as_os_str())
119 .current_dir(VIRGLRENDERER_SRC)
120 .status()?;
121 if !status.success() {
122 bail!("meson setup failed with status: {}", status);
123 }
124
125 // Add local minigbm paths to make sure virglrenderer can build against it.
126 let mut cmd = Command::new("meson");
127 cmd.env("CPATH", &minigbm_src_abs)
128 .arg("compile")
129 .arg("src/virglrenderer")
130 .current_dir(out_dir);
131
132 let status = cmd.status()?;
133 if !status.success() {
134 bail!("meson compile failed with status: {}", status);
135 }
136 Ok(())
137 }
138
139 #[cfg(feature = "virgl_renderer")]
virglrenderer() -> Result<()>140 fn virglrenderer() -> Result<()> {
141 // System provided runtime dependencies.
142 pkg_config::Config::new().probe("epoxy")?;
143 pkg_config::Config::new().probe("libdrm")?;
144
145 // Use virglrenderer package from the standard system location if available.
146 if pkg_config::Config::new().probe("virglrenderer").is_ok() {
147 return Ok(());
148 }
149
150 // Otherwise build from source.
151 let out_dir = PathBuf::from(env::var("OUT_DIR")?);
152 let minigbm_out = out_dir.join("minigbm");
153 let virglrenderer_out = out_dir.join("virglrenderer");
154 build_minigbm(&minigbm_out)?;
155 build_virglrenderer(&virglrenderer_out)?;
156
157 println!(
158 "cargo:rustc-link-search={}/src",
159 virglrenderer_out.display()
160 );
161 println!("cargo:rustc-link-search={}", minigbm_out.display());
162 println!("cargo:rustc-link-lib=static=virglrenderer");
163 println!("cargo:rustc-link-lib=static=gbm");
164 Ok(())
165 }
166
main() -> Result<()>167 fn main() -> Result<()> {
168 #[cfg(feature = "virgl_renderer")]
169 virglrenderer()?;
170
171 Ok(())
172 }
173