mirror of
https://github.com/esp-rs/espup.git
synced 2025-10-02 07:10:36 +00:00
228 lines
7.9 KiB
Rust
228 lines
7.9 KiB
Rust
//! GCC Toolchain source and installation tools
|
|
|
|
use crate::{
|
|
emoji,
|
|
error::Error,
|
|
targets::Target,
|
|
toolchain::{
|
|
gcc::{get_toolchain_name, get_ulp_toolchain_name},
|
|
get_home_dir,
|
|
},
|
|
};
|
|
use embuild::{espidf, espidf::EspIdfRemote, git};
|
|
use log::{debug, info};
|
|
use miette::Result;
|
|
use std::{
|
|
collections::hash_map::DefaultHasher,
|
|
collections::HashSet,
|
|
env,
|
|
fs::remove_dir_all,
|
|
hash::{Hash, Hasher},
|
|
path::PathBuf,
|
|
};
|
|
use strum::{Display, EnumIter, EnumString, IntoStaticStr};
|
|
|
|
pub const DEFAULT_GIT_REPOSITORY: &str = "https://github.com/espressif/esp-idf";
|
|
|
|
const DEFAULT_CMAKE_GENERATOR: Generator = {
|
|
// No Ninja builds for linux=aarch64 from Espressif yet
|
|
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
|
{
|
|
Generator::UnixMakefiles
|
|
}
|
|
|
|
#[cfg(not(all(target_os = "linux", target_arch = "aarch64")))]
|
|
{
|
|
Generator::Ninja
|
|
}
|
|
};
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, EnumString, Display, EnumIter, IntoStaticStr)]
|
|
pub enum Generator {
|
|
Ninja,
|
|
NinjaMultiConfig,
|
|
UnixMakefiles,
|
|
BorlandMakefiles,
|
|
MSYSMakefiles,
|
|
MinGWMakefiles,
|
|
NMakeMakefiles,
|
|
NMakeMakefilesJOM,
|
|
WatcomWMake,
|
|
}
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct EspIdfRepo {
|
|
/// The repository containing GCC sources.
|
|
pub repository_url: String,
|
|
/// ESP-IDF Version.
|
|
pub version: String,
|
|
/// Minify ESP-IDF?.
|
|
pub minified: bool,
|
|
/// Installation directory.
|
|
pub install_path: PathBuf,
|
|
/// ESP targets.
|
|
pub targets: HashSet<Target>,
|
|
}
|
|
|
|
impl EspIdfRepo {
|
|
/// Installs esp-idf.
|
|
pub fn install(self) -> Result<Vec<String>, Error> {
|
|
let cmake_generator = DEFAULT_CMAKE_GENERATOR;
|
|
let mut exports: Vec<String> = Vec::new();
|
|
|
|
// A closure to specify which tools `idf-tools.py` should install.
|
|
let make_tools = move |repo: &git::Repository,
|
|
version: &anyhow::Result<espidf::EspIdfVersion>|
|
|
-> anyhow::Result<Vec<espidf::Tools>> {
|
|
let version_str = match version {
|
|
Ok(v) => format!("v{v}"),
|
|
Err(_) => "(unknown version)".to_string(),
|
|
};
|
|
info!(
|
|
"{} Using esp-idf {} at '{}'",
|
|
emoji::INFO,
|
|
version_str,
|
|
repo.worktree().display()
|
|
);
|
|
|
|
let mut tools = vec![];
|
|
let mut subtools = Vec::new();
|
|
for target in self.targets {
|
|
let gcc_toolchain_name = get_toolchain_name(&target);
|
|
subtools.push(gcc_toolchain_name);
|
|
|
|
let ulp_toolchain_name = get_ulp_toolchain_name(target, version.as_ref().ok());
|
|
if !cfg!(target_os = "linux") || !cfg!(target_arch = "aarch64") {
|
|
if let Some(ulp_toolchain_name) = ulp_toolchain_name {
|
|
subtools.push(ulp_toolchain_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use custom cmake for esp-idf<4.4, because we need at least cmake-3.20
|
|
match version.as_ref().map(|v| (v.major, v.minor, v.patch)) {
|
|
Ok((major, minor, _)) if major >= 4 && minor >= 4 => {
|
|
subtools.push("cmake".to_string())
|
|
}
|
|
_ => {
|
|
tools
|
|
.push(espidf::Tools::cmake().map_err(|_| Error::FailedToInstantiateCmake)?);
|
|
}
|
|
}
|
|
#[cfg(windows)]
|
|
subtools.push("openocd-esp32".to_string());
|
|
#[cfg(windows)]
|
|
subtools.push("idf-exe".to_string());
|
|
#[cfg(windows)]
|
|
subtools.push("ccache".to_string());
|
|
#[cfg(windows)]
|
|
subtools.push("dfu-util".to_string());
|
|
|
|
if cmake_generator == Generator::Ninja {
|
|
subtools.push("ninja".to_string())
|
|
}
|
|
|
|
tools.push(espidf::Tools::new(subtools));
|
|
|
|
Ok(tools)
|
|
};
|
|
|
|
let install =
|
|
|esp_idf_origin: espidf::EspIdfOrigin| -> anyhow::Result<espidf::EspIdf, Error> {
|
|
espidf::Installer::new(esp_idf_origin)
|
|
.install_dir(Some(self.install_path.clone()))
|
|
.with_tools(make_tools)
|
|
.install()
|
|
.map_err(|_| Error::FailedToCreateEspIdfInstallClosure)
|
|
};
|
|
|
|
let repo = espidf::EspIdfRemote {
|
|
git_ref: espidf::parse_esp_idf_git_ref(&self.version),
|
|
repo_url: Some("https://github.com/espressif/esp-idf".to_string()),
|
|
};
|
|
|
|
let espidf_origin = espidf::EspIdfOrigin::Managed(repo.clone());
|
|
#[cfg(unix)]
|
|
let espidf = install(espidf_origin).map_err(|_| Error::FailedToInstallEspIdf)?;
|
|
#[cfg(windows)]
|
|
install(espidf_origin)?;
|
|
let espidf_dir = get_install_path(repo);
|
|
#[cfg(windows)]
|
|
exports.push(format!("$Env:IDF_PATH=\"{}\"", espidf_dir.display()));
|
|
#[cfg(unix)]
|
|
exports.push(format!("export IDF_PATH={}", espidf_dir.display()));
|
|
#[cfg(windows)]
|
|
exports.push(espidf_dir.join("export.ps1").display().to_string());
|
|
#[cfg(unix)]
|
|
exports.push(format!("export PATH={:?}", espidf.exported_path));
|
|
if self.minified {
|
|
info!("{} Minifying ESP-IDF", emoji::INFO);
|
|
remove_dir_all(espidf_dir.join("docs"))?;
|
|
remove_dir_all(espidf_dir.join("examples"))?;
|
|
remove_dir_all(espidf_dir.join("tools").join("esp_app_trace"))?;
|
|
remove_dir_all(espidf_dir.join("tools").join("test_idf_size"))?;
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
exports.push(format!("$Env:IDF_TOOLS_PATH=\"{}\"", get_tools_path()));
|
|
#[cfg(unix)]
|
|
exports.push(format!("export IDF_TOOLS_PATH=\"{}\"", get_tools_path()));
|
|
|
|
Ok(exports)
|
|
}
|
|
|
|
/// Create a new instance with the proper arguments.
|
|
pub fn new(version: &str, minified: bool, targets: &HashSet<Target>) -> EspIdfRepo {
|
|
let install_path = PathBuf::from(get_tools_path());
|
|
debug!(
|
|
"{} ESP-IDF install path: '{}'",
|
|
emoji::DEBUG,
|
|
install_path.display()
|
|
);
|
|
Self {
|
|
repository_url: DEFAULT_GIT_REPOSITORY.to_string(),
|
|
version: version.to_string(),
|
|
minified,
|
|
install_path,
|
|
targets: targets.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Gets the esp-idf installation path.
|
|
pub fn get_install_path(repo: EspIdfRemote) -> PathBuf {
|
|
let mut hasher = DefaultHasher::new();
|
|
repo.repo_url.as_ref().unwrap().hash(&mut hasher);
|
|
let repo_url_hash = format!("{:x}", hasher.finish());
|
|
let repo_dir = match repo.git_ref {
|
|
git::Ref::Branch(n) | git::Ref::Tag(n) | git::Ref::Commit(n) => n,
|
|
};
|
|
// Replace all directory separators with a dash `-`, so that we don't create
|
|
// subfolders for tag or branch names that contain such characters.
|
|
let repo_dir = repo_dir.replace(['/', '\\'], "-");
|
|
|
|
let mut install_path = PathBuf::from(get_tools_path());
|
|
install_path = install_path.join(PathBuf::from(format!("esp-idf-{}", repo_url_hash)));
|
|
install_path = install_path.join(PathBuf::from(repo_dir));
|
|
install_path
|
|
}
|
|
|
|
/// Gets path where esp-idf tools where be downloaded and installed. If environment
|
|
/// variable IDF_TOOLS_PATH is not set. Uses HOME/.espressif on Linux and macOS,
|
|
/// and %USER_PROFILE%\.espressif on Windows.
|
|
pub fn get_tools_path() -> String {
|
|
env::var("IDF_TOOLS_PATH").unwrap_or_else(|_e| get_home_dir() + "/.espressif")
|
|
}
|
|
|
|
/// Gets the espressif tools directory path. Tools directory is where the tools
|
|
/// are extracted.
|
|
pub fn get_tool_path(tool_name: &str) -> String {
|
|
format!("{}/tools/{}", get_tools_path(), tool_name)
|
|
}
|
|
|
|
/// Gets the Espressif dist directory path. Dist directory is where the archives
|
|
/// of the tools are downloaded.
|
|
pub fn get_dist_path(tool_name: &str) -> String {
|
|
let tools_path = get_tools_path();
|
|
format!("{}/dist/{}", tools_path, tool_name)
|
|
}
|