Skip to content

Commit f41277b

Browse files
ivmarkovN3xed
andauthored
build: support user-provided esp-idf and activated environment (#42)
Allows the user to specify their own esp-idf and makes it possible to use an activated esp-idf environment. For the pio builder, allows re-using an already available `platformio` from $PATH. For the native builder: - If an activated esp-idf is available and $ESP_IDF_TOOLS_INSTALL_DIR == "fromenv" or unset, use it. - If $IDF_PATH is valid, use it as a user-provided esp-idf repository (but installer manages tools). - Otherwise, the installer manages everything and respects $ESP_IDF_REPOSITORY and $ESP_IDF_VERSION. For the pio builder: - If the `platformio` executable is in $PATH and $ESP_IDF_TOOLS_INSTALL_DIR == "fromenv" or unset, use it. - Otherwise, the installer manages platformio as before. * Preconfigured env and custom esp-idf support * Fix cargo fmt * Improve logging * Implement pio, update README * Fix cargo fmt * Upgrade embuild and strum * Fix typos in README Co-authored-by: N3xed <[email protected]>
1 parent 64b7fc9 commit f41277b

File tree

5 files changed

+304
-117
lines changed

5 files changed

+304
-117
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ pio = ["embuild/pio"]
3232
paste = "1"
3333

3434
[build-dependencies]
35-
embuild = { version = "0.28.4", features = ["glob"] }
35+
embuild = { version = "0.29.0", features = ["glob"] }
3636
anyhow = "1"
37-
strum = { version = "0.23", features = ["derive"], optional = true }
37+
strum = { version = "0.24", features = ["derive"], optional = true }
3838
regex = "1.5"
3939
bindgen = "0.59"

README.md

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,27 +106,40 @@ The following environment variables are used by the build script:
106106

107107
- `ESP_IDF_TOOLS_INSTALL_DIR`:
108108

109-
The location where the ESP-IDF framework tooling is assumed to be/will be installed.
110-
The framework tooling is either PlatformIO (when the `pio` builder is used), or the ESP-IDF native toolset (when the `native` builder is used).
109+
The location where the ESP-IDF framework tooling is assumed to be/will be installed. The
110+
framework tooling is either PlatformIO (when the `pio` builder is used), or the ESP-IDF
111+
native toolset (when the `native` builder is used).
111112

112-
This variable can take one of the following values:
113+
This variable can take one of the following values:
113114
- `workspace` (default) - the tooling will be installed/used in
114115
`<crate-workspace-dir>/.embuild/platformio` for `pio`, and `<crate-workspace-dir>/.embuild/espressif` for the `native` builder;
115116
- `out` - the tooling will be installed/used inside the crate's build output directory, and will be deleted when `cargo clean` is invoked;
116117
- `global` - the tooling will be installed/used in its standard directory (`~/.platformio` for PlatformIO, and `~./espressif` for the native ESP-IDF toolset);
117118
- `custom:<dir>` - the tooling will be installed/used in the directory specified by `<dir>`. If this directory is a relative location, it is assumed to be
118-
relative to the crate's workspace dir.
119-
120-
**ATTENTION**: Please be extra careful with the `custom:<dir>` setting when switching from `pio` to `native` and the other way around, because
121-
the builder will install the tooling in `<dir>` without using any additional `platformio` or `espressif` subdirectories, so if you are not careful, you might end up with
122-
both PlatformIO, as well as the ESP-IDF native tooling intermingled together in a single folder.
123-
124-
125-
Note that both builders (`native` and `pio`) clone the ESP-IDF GIT repository *inside* the tooling directory as well. This restriction might be lifted soon for the `native` builder, whereas the user would be able to point the build to a custom ESP-IDF repository location.
119+
relative to the crate's workspace dir;
120+
- `fromenv` - use the build framework from the environment
121+
- *native* builder: use activated esp-idf environment (see esp-idf docs
122+
[unix](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html#step-4-set-up-the-environment-variables)
123+
/
124+
[windows](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup.html#using-the-command-prompt))
125+
- *pio* builder: use `platformio` from the environment (i.e. `$PATH`)
126+
127+
and error if this is not possible.
128+
129+
**ATTENTION**: Please be extra careful with the `custom:<dir>` setting when switching from `pio` to `native` and the other way around, because
130+
the builder will install the tooling in `<dir>` without using any additional `platformio` or `espressif` subdirectories, so if you are not careful, you might end up with
131+
both PlatformIO, as well as the ESP-IDF native tooling intermingled together in a single folder.
132+
133+
134+
Note that both builders (`native` and `pio`) clone the ESP-IDF GIT repository *inside* the tooling directory as well. This restriction might be lifted soon for the `native` builder, whereas the user would be able to point the build to a custom ESP-IDF repository location.
135+
136+
- `IDF_PATH` (*native* builder only):
137+
A path to a user-provided local clone of the [`esp-idf`](https://github.com/espressif/esp-idf),
138+
that will be used instead of the one downloaded by the build script.
126139

127140
- `ESP_IDF_VERSION` (*native* builder only):
128141

129-
The version used for the `esp-idf` can be one of the following:
142+
The version used for the `esp-idf`, can be one of the following:
130143
- `commit:<hash>`: Uses the commit `<hash>` of the `esp-idf` repository.
131144
Note that this will clone the whole `esp-idf` not just one commit.
132145
- `tag:<tag>`: Uses the tag `<tag>` of the `esp-idf` repository.

build/common.rs

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::collections::HashSet;
2+
use std::fmt::Display;
23
use std::iter::once;
34
use std::path::{Path, PathBuf};
45
use std::str::FromStr;
56
use std::{env, error, fs};
67

7-
use anyhow::*;
8+
use anyhow::{anyhow, bail, Result};
89
use embuild::cargo::{self, IntoWarning};
910
use embuild::utils::{OsStrExt, PathExt};
1011
use embuild::{bindgen, build, kconfig};
@@ -24,9 +25,6 @@ pub const V_4_3_2_PATCHES: &[&str] = &[
2425
"patches/pthread_destructor_fix.diff",
2526
];
2627

27-
#[allow(unused)]
28-
pub const NO_PATCHES: &[&str] = &[];
29-
3028
const TOOLS_WORKSPACE_INSTALL_DIR: &str = ".embuild";
3129

3230
const ALL_COMPONENTS: &[&str] = &[
@@ -207,32 +205,85 @@ pub fn list_specific_sdkconfigs(
207205
})
208206
}
209207

210-
pub fn get_install_dir(builder_name: impl AsRef<str>) -> Result<Option<PathBuf>> {
211-
let location = match env::var(ESP_IDF_TOOLS_INSTALL_DIR_VAR) {
212-
Err(env::VarError::NotPresent) => None,
213-
var => Some(var?.to_lowercase()),
214-
};
215-
216-
let dir = match location.as_deref() {
217-
None | Some("workspace") => Some(
218-
workspace_dir()?
219-
.join(TOOLS_WORKSPACE_INSTALL_DIR)
220-
.join(builder_name.as_ref()),
221-
),
222-
Some("global") => None,
223-
Some("out") => Some(cargo::out_dir().join(builder_name.as_ref())),
224-
Some(custom) => {
225-
if let Some(suffix) = custom.strip_prefix("custom:") {
226-
Some(PathBuf::from(suffix).abspath_relative_to(&workspace_dir()?))
227-
} else {
228-
bail!("Invalid installation directory format. Should be one of `global`, `workspace`, `out` or `custom:<dir>`");
208+
#[derive(Clone, Debug)]
209+
pub enum InstallDir {
210+
Global,
211+
Workspace(PathBuf),
212+
Out(PathBuf),
213+
Custom(PathBuf),
214+
FromEnv,
215+
}
216+
217+
impl InstallDir {
218+
/// Get the install directory from the [`ESP_IDF_TOOLS_INSTALL_DIR_VAR`] env variable.
219+
///
220+
/// If this env variable is unset or empty uses `default_install_dir` instead.
221+
/// On success returns `(install_dir as InstallDir, is_default as bool)`.
222+
pub fn from_env_or(
223+
default_install_dir: &str,
224+
builder_name: &str,
225+
) -> Result<(InstallDir, bool)> {
226+
let location = env::var_os(ESP_IDF_TOOLS_INSTALL_DIR_VAR);
227+
let (location, is_default) = match &location {
228+
None => (default_install_dir, true),
229+
Some(val) => {
230+
let val = val.try_to_str()?.trim();
231+
if val.is_empty() {
232+
(default_install_dir, true)
233+
} else {
234+
(val, false)
235+
}
229236
}
237+
};
238+
let install_dir = match location.to_lowercase().as_str() {
239+
"global" => Self::Global,
240+
"workspace" => Self::Workspace(
241+
workspace_dir()?
242+
.join(TOOLS_WORKSPACE_INSTALL_DIR)
243+
.join(builder_name),
244+
),
245+
"out" => Self::Out(cargo::out_dir().join(builder_name)),
246+
"fromenv" => Self::FromEnv,
247+
_ => Self::Custom({
248+
if let Some(suffix) = location.strip_prefix("custom:") {
249+
Path::new(suffix).abspath_relative_to(&workspace_dir()?)
250+
} else {
251+
bail!(
252+
"Invalid installation directory format. \
253+
Should be one of `global`, `workspace`, `out`, `fromenv` or `custom:<dir>`."
254+
);
255+
}
256+
}),
257+
};
258+
Ok((install_dir, is_default))
259+
}
260+
261+
pub fn is_from_env(&self) -> bool {
262+
matches!(self, Self::FromEnv)
263+
}
264+
265+
pub fn path(&self) -> Option<&Path> {
266+
match self {
267+
Self::Global | Self::FromEnv => None,
268+
Self::Workspace(ref path) => Some(path.as_ref()),
269+
Self::Out(ref path) => Some(path.as_ref()),
270+
Self::Custom(ref path) => Some(path.as_ref()),
230271
}
231-
};
272+
}
273+
}
232274

233-
Ok(dir)
275+
impl Display for InstallDir {
276+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277+
match self {
278+
Self::Global => write!(f, "global"),
279+
Self::Workspace(ref path) => write!(f, "workspace ({})", path.display()),
280+
Self::Out(ref path) => write!(f, "out ({})", path.display()),
281+
Self::Custom(ref path) => write!(f, "custom ({})", path.display()),
282+
Self::FromEnv => write!(f, "fromenv"),
283+
}
284+
}
234285
}
235286

236287
pub fn workspace_dir() -> Result<PathBuf> {
237-
Ok(cargo::workspace_dir().ok_or_else(|| anyhow!("Cannot fetch crate's workspace dir"))?)
288+
cargo::workspace_dir().ok_or_else(|| anyhow!("Cannot fetch crate's workspace dir"))
238289
}

0 commit comments

Comments
 (0)