crosvm/rutabaga_gfx/build.rs
Gurchetan Singh 0a41752942 rutabaga_gfx: gfxstream_unstable --> fence_passing_option1
Realistically, this has nothing to do with gfxstream
per se.  It's just one of the options discussed on
on how to do fence passing, which gfxstream may or
not leverage.

Rename the option for clarity.

BUG=328083772
TEST=CI

Change-Id: I1292f329a1935ca512ec22b0993958bbb06180e4
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/6012806
Reviewed-by: Frederick Mayle <fmayle@google.com>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
2024-11-12 23:47:15 +00:00

311 lines
9.9 KiB
Rust

// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::env;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use anyhow::anyhow;
use anyhow::bail;
use anyhow::Context;
use anyhow::Result;
fn is_native_build() -> bool {
env::var("HOST").unwrap() == env::var("TARGET").unwrap()
}
fn use_system_minigbm() -> bool {
println!("cargo:rerun-if-env-changed=CROSVM_BUILD_VARIANT");
println!("cargo:rerun-if-env-changed=CROSVM_USE_SYSTEM_MINIGBM");
env::var("CROSVM_BUILD_VARIANT").unwrap_or_default() == "chromeos"
|| env::var("CROSVM_USE_SYSTEM_MINIGBM").unwrap_or_else(|_| "0".to_string()) != "0"
}
fn use_system_virglrenderer() -> bool {
println!("cargo:rerun-if-env-changed=CROSVM_BUILD_VARIANT");
println!("cargo:rerun-if-env-changed=CROSVM_USE_SYSTEM_VIRGLRENDERER");
env::var("CROSVM_BUILD_VARIANT").unwrap_or_default() == "chromeos"
|| env::var("CROSVM_USE_SYSTEM_VIRGLRENDERER").unwrap_or_else(|_| "0".to_string()) != "0"
}
/// Returns the target triplet prefix for gcc commands. No prefix is required
/// for native builds.
fn get_cross_compile_prefix() -> String {
if is_native_build() {
return String::from("");
}
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
format!("{}-{}-{}-", arch, os, env)
}
/// For cross-compilation with meson, we need to pick a cross-file, which
/// live in /usr/local/share/meson/cross.
fn get_meson_cross_args() -> Vec<String> {
if is_native_build() {
Vec::new()
} else {
vec![
"--cross-file".to_string(),
env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
]
}
}
fn env_prepend_pkg_config_path(new_path: &Path) -> Result<()> {
const KEY: &str = "PKG_CONFIG_PATH";
let new_path_string = new_path
.to_str()
.ok_or(anyhow!("failed to convert path to string"))?;
if let Ok(original_value) = env::var(KEY) {
env::set_var(KEY, format!("{}:{}", new_path_string, original_value));
} else {
env::set_var(KEY, new_path);
};
Ok(())
}
/// Builds from pinned commit as static library and probes the generated pkgconfig file to emit
/// cargo linking metadata
fn build_and_probe_minigbm(out_dir: &Path) -> Result<()> {
const SOURCE_DIR: &str = "../third_party/minigbm";
let pkgconfig_file = out_dir.join("gbm.pc");
println!("cargo:rerun-if-changed={}", SOURCE_DIR);
if !Path::new(SOURCE_DIR).join(".git").exists() {
bail!(
"{} source does not exist, did you forget to \
`git submodule update --init`?",
SOURCE_DIR
);
}
// build static library
let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
let status = Command::new("make")
.env("MAKEFLAGS", make_flags)
.env("VERBOSE", "1")
.env("CROSS_COMPILE", get_cross_compile_prefix())
.env("PKG_CONFIG", "pkg-config")
.arg(format!("OUT={}", out_dir.display()))
.arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
.current_dir(SOURCE_DIR)
.status()?;
if !status.success() {
bail!("make failed with status: {}", status);
}
// copy headers to build output
let src_dir = Path::new(SOURCE_DIR);
fs::copy(src_dir.join("gbm.h"), out_dir.join("gbm.h"))?;
fs::copy(
src_dir.join("minigbm_helpers.h"),
out_dir.join("minigbm_helpers.h"),
)?;
// minigbm will be linked using the name gbm, make sure it can be found.
fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
// write out a custom pkgconfig
let mut conf = File::create(pkgconfig_file)?;
let contents = format!(
r#"prefix={install_dir}
includedir=${{prefix}}
libdir=${{prefix}}
Name: libgbm
Description: A small gbm implementation
Version: 18.0.0
Cflags: -I${{includedir}}
Libs: -L${{libdir}} -lgbm
Requires.private: libdrm >= 2.4.50
"#,
install_dir = out_dir.display()
);
conf.write_all(contents.as_bytes())?;
// let pkg_config crate configure the cargo link metadata according to the custom pkgconfig
// above
env_prepend_pkg_config_path(out_dir)?;
let mut config = pkg_config::Config::new();
config.statik(true).probe("gbm")?;
Ok(())
}
fn minigbm() -> Result<()> {
if use_system_minigbm() {
pkg_config::probe_library("gbm").context("pkgconfig failed to find gbm")?;
} else {
// Otherwise build from source and emit cargo build metadata
let out_dir = PathBuf::from(env::var("OUT_DIR")?).join("minigbm");
build_and_probe_minigbm(&out_dir).context("failed building minigbm")?;
};
Ok(())
}
/// Builds from pinned commit as static library and probes the generated pkgconfig file to emit
/// cargo linking metadata
fn build_and_probe_virglrenderer(out_dir: &Path) -> Result<()> {
const SOURCE_DIR: &str = "../third_party/virglrenderer";
let install_prefix = out_dir.join("installed");
println!("cargo:rerun-if-changed={}", SOURCE_DIR);
if !Path::new(SOURCE_DIR).join(".git").exists() {
bail!(
"{} source does not exist, did you forget to \
`git submodule update --init`?",
SOURCE_DIR
);
}
let mut platforms = vec!["egl"];
if env::var("CARGO_FEATURE_X").is_ok() {
platforms.push("glx");
}
// Ensures minigbm is available and that it's pkgconfig is locatable
minigbm()?;
let mut setup = Command::new("meson");
setup
.arg("setup")
.current_dir(SOURCE_DIR)
.arg("--prefix")
.arg(install_prefix.as_os_str())
.arg("--libdir")
.arg("lib")
.args(get_meson_cross_args())
.arg(format!("-Dplatforms={}", platforms.join(",")))
.arg("-Ddefault_library=static")
.arg(out_dir.as_os_str());
let setup_status = setup.status()?;
if !setup_status.success() {
bail!("meson setup failed with status: {}", setup_status);
}
let mut compile = Command::new("meson");
compile
.arg("compile")
.arg("src/virglrenderer")
.current_dir(out_dir);
let compile_status = compile.status()?;
if !compile_status.success() {
bail!("meson compile failed with status: {}", compile_status);
}
let mut install = Command::new("meson");
install.arg("install").current_dir(out_dir);
let install_status = install.status()?;
if !install_status.success() {
bail!("meson install failed with status: {}", install_status);
}
let pkg_config_path = install_prefix.join("lib/pkgconfig");
assert!(pkg_config_path.join("virglrenderer.pc").exists());
// let pkg_config crate configure the cargo link metadata according to the generated pkgconfig
env_prepend_pkg_config_path(pkg_config_path.as_path())?;
let mut config = pkg_config::Config::new();
config.statik(true).probe("virglrenderer")?;
Ok(())
}
fn virglrenderer() -> Result<()> {
if use_system_virglrenderer() && !use_system_minigbm() {
bail!("Must use system minigbm if using system virglrenderer (try setting CROSVM_USE_SYSTEM_MINIGBM=1)");
}
// Use virglrenderer package from pkgconfig on ChromeOS builds
if use_system_virglrenderer() {
let lib = pkg_config::Config::new()
.atleast_version("1.0.0")
.probe("virglrenderer")
.context("pkgconfig failed to find virglrenderer")?;
if lib.defines.contains_key("VIRGL_RENDERER_UNSTABLE_APIS") {
println!("cargo:rustc-cfg=virgl_renderer_unstable");
}
} else {
// Otherwise build from source.
let out_dir = PathBuf::from(env::var("OUT_DIR")?).join("virglrenderer");
build_and_probe_virglrenderer(&out_dir)?;
}
Ok(())
}
fn gfxstream() -> Result<()> {
if let Ok(gfxstream_path) = env::var("GFXSTREAM_PATH") {
println!("cargo:rustc-link-lib=gfxstream_backend");
println!("cargo:rustc-link-search={}", gfxstream_path);
Ok(())
} else {
let gfxstream_lib = pkg_config::Config::new().probe("gfxstream_backend")?;
if gfxstream_lib.defines.contains_key("GFXSTREAM_UNSTABLE") {
println!("cargo:rustc-cfg=gfxstream_unstable");
}
pkg_config::Config::new().probe("aemu_base")?;
pkg_config::Config::new().probe("aemu_host_common")?;
pkg_config::Config::new().probe("aemu_logging")?;
pkg_config::Config::new().probe("aemu_snapshot")?;
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
if target_os.contains("linux") {
pkg_config::Config::new().probe("libdrm")?;
}
// Need to link against libc++ or libstdc++. Apple is clang-only, while by default other
// Unix platforms use libstdc++.
if target_os.contains("macos") {
println!("cargo:rustc-link-lib=dylib=c++");
} else if target_os.contains("linux") || target_os.contains("nto") {
println!("cargo:rustc-link-lib=dylib=stdc++");
}
Ok(())
}
}
fn main() -> Result<()> {
println!("cargo:rustc-check-cfg=cfg(gfxstream_unstable)");
println!("cargo:rustc-check-cfg=cfg(virgl_renderer_unstable)");
let mut use_fence_passing_option1 = true;
// Skip installing dependencies when generating documents.
if env::var("CARGO_DOC").is_ok() {
return Ok(());
}
if env::var("CARGO_FEATURE_MINIGBM").is_ok() {
minigbm()?;
}
if env::var("CARGO_FEATURE_VIRGL_RENDERER").is_ok() {
virglrenderer()?;
use_fence_passing_option1 = false;
}
if env::var("CARGO_FEATURE_GFXSTREAM").is_ok()
&& env::var("CARGO_FEATURE_GFXSTREAM_STUB").is_err()
{
gfxstream()?;
}
if use_fence_passing_option1 {
println!("cargo:rustc-cfg=fence_passing_option1");
}
Ok(())
}