Skip to content

Commit

Permalink
#41, #36
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmarkov committed Dec 9, 2021
1 parent e8c801b commit 948bd1f
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 72 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ readme = "README.md"
links = "esp_idf"
build = "build/build.rs"

[patch.crates-io]
embuild = { path = "../embuild" }

[features]
default = ["std", "pio"]

Expand Down
96 changes: 73 additions & 23 deletions build/common.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::HashSet;
use std::fmt::Display;
use std::iter::once;
use std::path::{Path, PathBuf};
use std::str::FromStr;
Expand Down Expand Up @@ -174,32 +175,81 @@ pub fn get_sdkconfig_profile(path: &Path, profile: &str, chip: &str) -> Option<P
})
}

pub fn get_install_dir(builder_name: impl AsRef<str>) -> Result<Option<PathBuf>> {
let location = match env::var(ESP_IDF_TOOLS_INSTALL_DIR_VAR) {
Err(env::VarError::NotPresent) => None,
var => Some(var?.to_lowercase()),
};

let dir = match location.as_deref() {
None | Some("workspace") => Some(
workspace_dir()?
.join(TOOLS_WORKSPACE_INSTALL_DIR)
.join(builder_name.as_ref()),
),
Some("global") => None,
Some("out") => Some(cargo::out_dir().join(builder_name.as_ref())),
Some(custom) => {
if let Some(suffix) = custom.strip_prefix("custom:") {
Some(PathBuf::from(suffix).abspath_relative_to(&workspace_dir()?))
} else {
bail!("Invalid installation directory format. Should be one of `global`, `workspace`, `out` or `custom:<dir>`");
}
#[derive(Clone, Debug, PartialEq)]
pub enum InstallLocation {
Global,
Workspace(PathBuf),
Out(PathBuf),
Custom(PathBuf),
FromPath,
}

impl InstallLocation {
pub fn get_env_var_name() -> &'static str {
ESP_IDF_TOOLS_INSTALL_DIR_VAR
}

pub fn get(builder_name: impl AsRef<str>) -> Result<Option<InstallLocation>> {
let location = match env::var(Self::get_env_var_name()) {
Err(env::VarError::NotPresent) => None,
e => Some(e?),
};

Self::parse(location.as_deref(), builder_name)
}

pub fn parse(location: Option<&str>, builder_name: impl AsRef<str>) -> Result<Option<Self>> {
if let Some(location) = location {
let location = match location.to_lowercase().as_str() {
"global" => Self::Global,
"workspace" => Self::new_workspace(builder_name)?,
"out" => Self::Out(cargo::out_dir().join(builder_name.as_ref())),
"frompath" => Self::FromPath,
custom => Self::Custom({
if let Some(suffix) = custom.strip_prefix("custom:") {
PathBuf::from(suffix).abspath_relative_to(&workspace_dir()?)
} else {
bail!("Invalid installation directory format. Should be one of `global`, `workspace`, `out` or `custom:<dir>`");
}
}),
};

Ok(Some(location))
} else {
Ok(None)
}
};
}

Ok(dir)
pub fn path(&self) -> Option<&Path> {
match self {
Self::Global | Self::FromPath => None,
Self::Workspace(ref path) => Some(path.as_ref()),
Self::Out(ref path) => Some(path.as_ref()),
Self::Custom(ref path) => Some(path.as_ref()),
}
}

pub fn new_workspace(builder_name: impl AsRef<str>) -> Result<Self> {
let dir = workspace_dir()?
.join(TOOLS_WORKSPACE_INSTALL_DIR)
.join(builder_name.as_ref());

Ok(Self::Workspace(dir))
}
}

impl Display for InstallLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Global => write!(f, "global"),
Self::Workspace(ref path) => write!(f, "workspace({})", path.display()),
Self::Out(ref path) => write!(f, "out({})", path.display()),
Self::Custom(ref path) => write!(f, "custom({})", path.display()),
Self::FromPath => write!(f, "frompath"),
}
}
}

pub fn workspace_dir() -> Result<PathBuf> {
Ok(cargo::workspace_dir().ok_or_else(|| anyhow!("Cannot fetch crate's workspace dir"))?)
cargo::workspace_dir().ok_or_else(|| anyhow!("Cannot fetch crate's workspace dir"))
}
156 changes: 113 additions & 43 deletions build/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ use std::{env, fs};
use anyhow::*;
use embuild::cmake::file_api::codemodel::Language;
use embuild::cmake::file_api::ObjKind;
use embuild::espidf::InstallOpts;
use embuild::fs::copy_file_if_different;
use embuild::utils::{OsStrExt, PathExt};
use embuild::{bindgen, build, cargo, cmake, espidf, git, kconfig, path_buf};
use strum::{Display, EnumString};

use super::common::{
self, get_install_dir, get_sdkconfig_profile, workspace_dir, EspIdfBuildOutput,
EspIdfComponents, ESP_IDF_GLOB_VAR_PREFIX, ESP_IDF_SDKCONFIG_DEFAULTS_VAR,
self, get_sdkconfig_profile, workspace_dir, EspIdfBuildOutput, EspIdfComponents,
InstallLocation, ESP_IDF_GLOB_VAR_PREFIX, ESP_IDF_SDKCONFIG_DEFAULTS_VAR,
ESP_IDF_SDKCONFIG_VAR, ESP_IDF_TOOLS_INSTALL_DIR_VAR, MASTER_PATCHES, MCU_VAR, STABLE_PATCHES,
};

Expand Down Expand Up @@ -103,52 +102,89 @@ fn build_cargo_first() -> Result<EspIdfBuildOutput> {
let chip_name = chip.to_string();
let profile = common::build_profile();

cargo::track_env_var(espidf::IDF_PATH_VAR);
cargo::track_env_var(ESP_IDF_TOOLS_INSTALL_DIR_VAR);
cargo::track_env_var(ESP_IDF_VERSION_VAR);
cargo::track_env_var(ESP_IDF_REPOSITORY_VAR);
cargo::track_env_var(ESP_IDF_SDKCONFIG_DEFAULTS_VAR);
cargo::track_env_var(ESP_IDF_SDKCONFIG_VAR);
cargo::track_env_var(MCU_VAR);

let cmake_tool = espidf::Tools::cmake()?;
let tools = espidf::Tools::new(
vec!["ninja", chip.gcc_toolchain()]
.into_iter()
.chain(chip.ulp_gcc_toolchain()),
);
let idf_frompath = espidf::EspIdf::detect_from_path()?;

let install_dir = get_install_dir("espressif")?;
let idf = espidf::Installer::new(esp_idf_version()?)
.opts(InstallOpts::empty())
.local_install_dir(install_dir)
.git_url(match env::var(ESP_IDF_REPOSITORY_VAR) {
Err(env::VarError::NotPresent) => None,
git_url => Some(git_url?),
})
.with_tools(tools)
.with_tools(cmake_tool)
.install()
.context("Could not install esp-idf")?;

// Apply patches, only if the patches were not previously applied.
let patch_set = match &idf.esp_idf_version {
git::Ref::Branch(b) if idf.esp_idf.get_default_branch()?.as_ref() == Some(b) => {
MASTER_PATCHES
let install_location = InstallLocation::get("espressif")?;

if idf_frompath.is_some()
&& install_location.is_some()
&& !matches!(install_location, Some(InstallLocation::FromPath))
{
bail!(
"ESP-IDF tooling detected on path, however user has overriden with `{}` via `{}`",
install_location.unwrap(),
InstallLocation::get_env_var_name()
);
}

let idf = if let Some(idf_frompath) = idf_frompath {
match install_location {
None | Some(InstallLocation::FromPath) => idf_frompath,
Some(install_location) => bail!(
"Install location is configured to `{}` via `{}`, however there is ESP-IDF tooling detected on path",
install_location,
InstallLocation::get_env_var_name()),
}
git::Ref::Tag(t) if t == DEFAULT_ESP_IDF_VERSION => STABLE_PATCHES,
_ => {
cargo::print_warning(format_args!(
"`esp-idf` version ({:?}) not officially supported by `esp-idf-sys`. \
Supported versions are 'master', '{}'.",
&idf.esp_idf_version, DEFAULT_ESP_IDF_VERSION
));
&[]
} else {
let install_location = install_location
.map(Result::Ok)
.unwrap_or_else(|| InstallLocation::new_workspace("espressif"))?;

if matches!(install_location, InstallLocation::FromPath) {
bail!(
"Install location is configured to `{}` via `{}`, however no ESP-IDF tooling was detected on path",
InstallLocation::FromPath,
InstallLocation::get_env_var_name());
}

let cmake_tool = espidf::Tools::cmake()?;
let tools = espidf::Tools::new(
vec!["ninja", chip.gcc_toolchain()]
.into_iter()
.chain(chip.ulp_gcc_toolchain()),
);

let idf_version = esp_idf_version()?;

let idf = espidf::Installer::new(idf_version.clone())
.install_dir(install_location.path().map(PathBuf::from))
.with_tools(tools)
.with_tools(cmake_tool)
.install()
.context("Could not install esp-idf")?;

// Apply patches, only if the patches were not previously applied and only if the used esp-idf instance is managed.
if let espidf::EspIdfVersion::Managed((_, gitref)) = &idf_version {
let patch_set = match gitref {
git::Ref::Branch(b) if idf.esp_idf.get_default_branch()?.as_ref() == Some(b) => {
MASTER_PATCHES
}
git::Ref::Tag(t) if t == DEFAULT_ESP_IDF_VERSION => STABLE_PATCHES,
_ => {
cargo::print_warning(format_args!(
"`esp-idf` version ({:?}) not officially supported by `esp-idf-sys`. \
Supported versions are 'master', '{}'.",
gitref, DEFAULT_ESP_IDF_VERSION
));
&[]
}
};
if !patch_set.is_empty() {
idf.esp_idf
.apply_once(patch_set.iter().map(|p| manifest_dir.join(p)))?;
}
}

idf
};
if !patch_set.is_empty() {
idf.esp_idf
.apply_once(patch_set.iter().map(|p| manifest_dir.join(p)))?;
}

env::set_var("PATH", &idf.exported_path);

Expand Down Expand Up @@ -319,12 +355,46 @@ fn build_cargo_first() -> Result<EspIdfBuildOutput> {
Ok(build_output)
}

fn esp_idf_version() -> Result<git::Ref> {
let version = match env::var(ESP_IDF_VERSION_VAR) {
Err(env::VarError::NotPresent) => DEFAULT_ESP_IDF_VERSION.to_owned(),
v => v?,
fn esp_idf_version() -> Result<espidf::EspIdfVersion> {
let unmanaged = espidf::EspIdfVersion::try_from_env_var()?;

let managed_repo_url = match env::var(ESP_IDF_REPOSITORY_VAR) {
Err(env::VarError::NotPresent) => None,
git_url => Some(git_url?),
};
Ok(espidf::decode_esp_idf_version_ref(&version))

let managed_version = match env::var(ESP_IDF_VERSION_VAR) {
Err(env::VarError::NotPresent) => None,
v => Some(v?),
};

if let Some(unmanaged) = unmanaged {
if managed_repo_url.is_some() {
println!(
"cargo:warning=User-supplied ESP-IDF detected via {}, setting `{}` will be ignored",
espidf::IDF_PATH_VAR,
ESP_IDF_REPOSITORY_VAR
);
}

if managed_version.is_some() {
println!(
"cargo:warning=User-supplied ESP-IDF detected via {}, setting `{}` will be ignored",
espidf::IDF_PATH_VAR,
ESP_IDF_VERSION_VAR
);
}

Ok(espidf::EspIdfVersion::Unmanaged(unmanaged))
} else {
let managed_version = managed_version
.as_deref()
.unwrap_or(DEFAULT_ESP_IDF_VERSION);

Ok(espidf::EspIdfVersion::Managed(
espidf::EspIdfVersion::from_version_str(managed_repo_url, managed_version),
))
}
}

// Generate `sdkconfig.defaults` content based on the crate manifest (`Cargo.toml`).
Expand Down
42 changes: 36 additions & 6 deletions build/pio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,44 @@ pub fn build() -> Result<EspIdfBuildOutput> {
let workspace_dir = workspace_dir()?;
let profile = build_profile();

let install_dir = get_install_dir("platformio")?;

if let Some(install_dir) = install_dir.as_ref() {
// Workaround an issue in embuild until it is fixed in the next version
fs::create_dir_all(install_dir)?;
let pio_frompath = pio::Pio::detect_from_path()?;

let install_location = InstallLocation::get("platformio")?;

if pio_frompath.is_some()
&& install_location.is_some()
&& !matches!(install_location, Some(InstallLocation::FromPath))
{
println!(
"cargo:info=PlatformIO executable detected on path, however user has overriden with `{}` via `{}`",
install_location.as_ref().unwrap(),
InstallLocation::get_env_var_name());
}

let pio = pio::Pio::install(install_dir, pio::LogLevel::Standard, false)?;
let pio = match install_location {
Some(InstallLocation::FromPath) => {
pio_frompath.map(Result::Ok).unwrap_or_else(|| bail!(
"Install location is configured to `{}` via `{}`, however no PlatformIO executable was detected on path",
InstallLocation::FromPath,
InstallLocation::get_env_var_name()))?
},
install_location => {
let install_location = install_location
.map(Result::Ok)
.unwrap_or_else(|| InstallLocation::new_workspace("platformio"))?;

if let Some(install_dir) = install_location.path() {
// Workaround an issue in embuild until it is fixed in the next version
fs::create_dir_all(install_dir)?;
}

pio::Pio::install(
install_location.path().map(|p| p.to_owned()),
pio::LogLevel::Standard,
false,
)?
},
};

let resolution = pio::Resolver::new(pio.clone())
.params(pio::ResolutionParams {
Expand Down

0 comments on commit 948bd1f

Please sign in to comment.