blob: 345dddb00bd19e872f82f9ec924a9839d953a2f0 [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use alchemist::{
analyze::source::PackageDistSource, ebuild::PackageDetails, repository::RepositorySet,
};
use anyhow::Result;
use itertools::Itertools;
use serde::Serialize;
pub static AUTOGENERATE_NOTICE: &str = "# AUTO-GENERATED FILE. DO NOT EDIT.\n\n";
/// Packages that are used to bootstrap the target's SYSROOT.
///
/// These packages are considered implicit built-time dependencies for all
/// packages built for the target.
///
/// TODO: Create a virtual package containing this list instead of hard coding
/// it into alchemist.
pub static PRIMORDIAL_PACKAGES: &[&str] = &[
"sys-kernel/linux-headers",
// We currently have glibc in package.provided for !amd64-host boards.
// When cross-compiling we use the toolchain's glibc package and manually
// install it into the SYSROOT.
"sys-libs/glibc",
"sys-libs/libcxx",
"sys-libs/llvm-libunwind",
"virtual/os-headers",
];
/// The packages we install to create a cross-compiler toolchain layer.
///
/// When cross-compiling a sysroot we need to ensure the cross-compiler
/// toolchain is implicitly provided. Portage will use the target's CHOST
/// variable to derive the compiler paths.
///
/// e.g.,
/// CHOST=aarch64-cros-linux-gnu
/// CC="${CHOST}-clang"
///
/// This unfortunately means that it's not possible for individual packages to
/// declare an explicit dependency on the specific cross-compiler tools they
/// depend on.
///
/// i.e., The following is not possible because the CHOST variable is profile
/// dependent.
/// BDEPEND="cross-${CHOST}/go"
///
/// For packages we maintain, we can add explicit BDEPENDs on the
/// cross-compilers since we only support a handful of architectures:
///
/// BDEPEND="!cros_host? (
/// arm? ( cross-armv7a-cros-linux-gnueabihf/go )
/// arm64? ( cross-aarch64-cros-linux-gnu/go )
/// amd64? ( cross-x86_64-cros-linux-gnu/go )
/// )"
///
/// Ideally we can prune this list as much as possible.
///
/// Questions:
/// * Why is LLVM not listed here? The sys-devel/llvm ebuild generates compilers
/// for all the different architectures we support.
/// * Why is the compiler-rt library not listed as a PRIMORDIAL_PACKAGES list
/// instead? The compiler-rt is a host package that provides helper objects
/// for the `llvm` cross-compilers. We don't want it installed into the
/// target's sysroot.
///
/// Packages that don't have a category specified will default to
/// `cross-$CHOST`.
pub static TOOLCHAIN_PACKAGE_NAMES: &[&str] = &[
"binutils",
// compiler-rt is only required for non-x86 toolchains. It's handled
// as a special case in the generator code.
"compiler-rt",
// The crossdev package provides /usr/share/config.site which includes
// a bunch of autoconf overrides that are used when cross compiling.
"sys-devel/crossdev",
];
fn file_name_to_name(file_name: &str) -> String {
let escaped_file_name: String = file_name
.chars()
.map(|c| {
if c.is_ascii_alphanumeric() || c == '-' || c == '.' {
c.to_string()
} else {
format!("_{:x}_", c as u32)
}
})
.join("");
format!("dist_{}", escaped_file_name)
}
pub fn repository_set_to_target_path(repo_set: &RepositorySet) -> String {
format!("//internal/overlays:{}", repo_set.name())
}
pub fn package_details_to_target_path(details: &PackageDetails, prefix: &str) -> String {
format!(
"//internal/packages/{}/{}/{}:{}",
prefix,
details.as_basic_data().repo_name,
details.as_basic_data().package_name,
details.as_basic_data().version
)
}
#[derive(Serialize)]
pub struct DistFileEntry {
pub name: String,
pub filename: String,
pub integrity: String,
pub urls: Vec<String>,
}
impl DistFileEntry {
pub fn try_new(source: &PackageDistSource) -> Result<Self> {
Ok(Self {
name: file_name_to_name(&source.filename),
filename: source.filename.clone(),
integrity: source.compute_integrity()?,
urls: source.urls.iter().map(|url| url.to_string()).collect(),
})
}
}
/// Escapes a string so that it is safe to be embedded in a Starlark literal
/// string quoted with double-quotes (`"`).
///
/// Use this function with [`Tera::set_escape_fn`] to generate Starlark files.
pub fn escape_starlark_string(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('\"', "\\\"")
.replace('\n', "\\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_escape_starlark_string() -> Result<()> {
assert_eq!("", escape_starlark_string(""));
assert_eq!("123", escape_starlark_string("123"));
assert_eq!("abc", escape_starlark_string("abc"));
assert_eq!(r#"\"foo\""#, escape_starlark_string(r#""foo""#));
assert_eq!(r#"foo\\bar"#, escape_starlark_string(r#"foo\bar"#));
Ok(())
}
}