• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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