From 62b655feabb63627b3f9cce51c0e7f470c44a1f9 Mon Sep 17 00:00:00 2001 From: N3xed Date: Tue, 2 Aug 2022 21:58:13 +0200 Subject: [PATCH 1/2] Improve README Add table of contents. Document `$CARGO_WORKSPACE_DIR` and conditional compilation using rust cfgs. --- README.md | 127 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d303fe41f34..3317fa99159 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ [![CI](https://github.com/esp-rs/esp-idf-sys/actions/workflows/ci.yml/badge.svg)](https://github.com/esp-rs/esp-idf-sys/actions/workflows/ci.yml) [![Documentation](https://img.shields.io/badge/docs-esp--rs-brightgreen)](https://esp-rs.github.io/esp-idf-sys/esp_idf_sys/index.html) -## Background - The ESP-IDF API in Rust, with support for each ESP chip (ESP32, ESP32S2, ESP32S3, ESP32C3, etc.) based on the Rust target. For more information, check out: @@ -16,6 +14,15 @@ For more information, check out: * The [Rust for Xtensa toolchain](https://github.com/esp-rs/rust-build) * The [Rust-with-STD demo](https://github.com/ivmarkov/rust-esp32-std-demo) project +**Table of contents** +- [Build](#build) +- [Features](#features) +- [sdkconfig](#sdkconfig) +- [Build configuration](#build-configuration) +- [Extra esp-idf components](#extra-esp-idf-components) +- [Conditional compilation](#conditional-compilation) +- [More info](#more-info) + ## Build - To build this crate, please follow all the build requirements specified in the [ESP-IDF Rust Hello World template crate](https://github.com/esp-rs/esp-idf-template) @@ -26,34 +33,43 @@ For more information, check out: - Check the [ESP-IDF Rust Hello World template crate](https://github.com/esp-rs/esp-idf-template) for a "Hello, world!" Rust template demonstrating how to use and build this crate. - Check the [demo](https://github.com/ivmarkov/rust-esp32-std-demo) crate for a more comprehensive example in terms of capabilities. -## Feature `native` -This is the default feature for downloading all tools and building the ESP-IDF framework using the framework's "native" (own) tooling. -It relies on build and installation utilities available in the [embuild](https://github.com/ivmarkov/embuild) crate. +## Features +- ### `native` + This is the default feature for downloading all tools and building the ESP-IDF framework using the framework's "native" (own) tooling. + It relies on build and installation utilities available in the [embuild](https://github.com/ivmarkov/embuild) crate. -The `native` builder installs all needed tools to compile this crate as well as the ESP-IDF framework itself. + The `native` builder installs all needed tools to compile this crate as well as the ESP-IDF framework itself. -### (Native builder only) Using cargo-idf to interactively modify ESP-IDF's `sdkconfig` file +- ### `pio` -TBD: Upcoming + This is a backup feature for installing all build tools and building the ESP-IDF framework. It uses [PlatformIO](https://platformio.org/) via the + [embuild](https://github.com/ivmarkov/embuild) crate. + + Similarly to the `native` builder, the `pio` builder also automatically installs all needed tools (PlatformIO packages and frameworks in this case) to compile this crate as well as the ESP-IDF framework itself. -## Feature `pio` -This is a backup feature for installing all build tools and building the ESP-IDF framework. It uses [PlatformIO](https://platformio.org/) via the -[embuild](https://github.com/ivmarkov/embuild) crate. + > ⚠️ The `pio` builder is less flexible than the default `native` builder in that it can work with only **one, specific** version of ESP-IDF. At the time of writing, this is V4.3.2. -Similarly to the `native` builder, the `pio` builder also automatically installs all needed tools (PlatformIO packages and frameworks in this case) to compile this crate as well as the ESP-IDF framework itself. +## sdkconfig -**NOTE:** The `pio` builder is less flexible than the default `native` builder in that it can work with only **one, specific** version of ESP-IDF. At the time of writing, this is V4.3.2. +The esp-idf makes use of an [sdkconfig](#espidfsdkconfig-espidfsdkconfig) file for its +compile-time component configuration (see the [esp-idf +docs](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#project-configuration) +for more information). This config is separate from the [build configuration](#build-configuration). -### (PIO builder only) Using cargo-pio to interactively modify ESP-IDF's `sdkconfig` file +### (*native* builder only) Using cargo-idf to interactively modify ESP-IDF's `sdkconfig` file + +TBD: Upcoming + +### (*pio* builder only) Using cargo-pio to interactively modify ESP-IDF's `sdkconfig` file To enable Bluetooth, or do other configurations to the ESP-IDF sdkconfig you might take advantage of the cargo-pio Cargo subcommand: * To install it, issue `cargo install cargo-pio --git https://github.com/ivmarkov/cargo-pio` * To open the ESP-IDF interactive menuconfig system, issue `cargo pio espidf menuconfig` in the root of your **binary crate** project * To use the generated/updated `sdkconfig` file, follow the steps described in the "Bluetooth Support" section -## Configuration +## Build configuration -There are two ways to configure how the ESP-IDF framework is compiled. +There are two ways to configure how the ESP-IDF framework is compiled: 1. Environment variables, denoted by `$VARIABLE`; > The environment variables can be passed on the command line, or put into the `[env]` @@ -70,11 +86,15 @@ There are two ways to configure how the ESP-IDF framework is compiled. > ⚠️ Environment variables always take precedence over `Cargo.toml` metadata. -> 🛈 **Note**: *workspace directory* +> 🛈 **Note**: *workspace directory* +> The workspace directory mentioned here is always the directory containing the +> `Cargo.lock` file and the `target` directory (where the build artifacts are stored). It +> can be overridden with the `CARGO_WORKSPACE_DIR` environment variable, should this not +> be the right directory. +> (See +> [`embuild::cargo::workspace_dir`](https://docs.rs/embuild/latest/embuild/cargo/fn.workspace_dir.html) +> for more information). > -> The workspace directory mentioned here is always the -> directory containing the `Cargo.lock` file and the `target` directory (where the build -> artifacts are stored). > There is no need to explicitly add a > [`[workspace]`](https://doc.rust-lang.org/cargo/reference/workspaces.html#the-workspace-section) > section to the `Cargo.toml` of the workspace directory. @@ -90,6 +110,8 @@ The following configuration options are available: Defaults to `sdkconfig.defaults`. + In case of the environment variable, multiple elements should be `;`-separated. + > 🛈 **Note** > For each defaults file in this list, a more specific file will also be searched and > used. This happens with the following patterns and order (least to most specific): @@ -131,7 +153,7 @@ The following configuration options are available: > determine the compiler optimizations of the `esp-idf`, **however** if the compiler > optimization options are already set in the `sdkconfig` **they will be used instead.** -- ### *`esp_idf_tools_install_dir`*, `$ESP_IDF_TOOLS_INSTALL_DIR`: +- ### *`esp_idf_tools_install_dir`*, `$ESP_IDF_TOOLS_INSTALL_DIR` The install location for the ESP-IDF framework tooling. @@ -147,7 +169,7 @@ The following configuration options are available: directory](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script), and will be deleted when `cargo clean` is invoked; - `global` - the tooling will be installed or used in its standard directory - (`~/.platformio` for PlatformIO, and `~./espressif` for the native ESP-IDF toolset); + (`~/.platformio` for PlatformIO, and `~/.espressif` for the native ESP-IDF toolset); - `custom:` - the tooling will be installed or used in the directory specified by ``. If this directory is a relative location, it is assumed to be relative to the *workspace directory*; @@ -164,7 +186,7 @@ The following configuration options are available: > the builder will install the tooling in `` without using any additional `platformio` or `espressif` subdirectories, so if you are not careful, you might end up with > both PlatformIO, as well as the ESP-IDF native tooling intermingled together in a single folder. - > 🛈 **Note** + > 🛈 **Note** > The [ESP-IDF git repository](https://github.com/espressif/esp-idf) will be cloned > *inside* the tooling directory. The *native* builder will use the esp-idf at > [*`idf_path`*](#idfpath-idfpath-native-builder-only) of available. @@ -173,7 +195,7 @@ The following configuration options are available: A path to a user-provided local clone of the [esp-idf](https://github.com/espressif/esp-idf), that will be used instead of the one downloaded by the build script. -- ### *`esp_idf_version`*, `$ESP_IDF_VERSION` (*native* builder only): +- ### *`esp_idf_version`*, `$ESP_IDF_VERSION` (*native* builder only) The version used for the `esp-idf`, can be one of the following: - `commit:`: Uses the commit `` of the `esp-idf` repository. @@ -185,7 +207,7 @@ The following configuration options are available: Defaults to `v4.4.1`. -- ### *`esp_idf_repository`*, `$ESP_IDF_REPOSITORY` (*native* builder only): +- ### *`esp_idf_repository`*, `$ESP_IDF_REPOSITORY` (*native* builder only) The URL to the git repository of the `esp-idf`, defaults to . @@ -201,7 +223,7 @@ The following configuration options are available: > its own ESP-IDF distribution, so the user-provided ESP-IDF branch may or may not compile. The current > PlatformIO tooling is suitable for compiling ESP-IDF branches derived from versions 4.3.X and 4.4.X. -- ### `$ESP_IDF_GLOB[_XXX]_BASE` and `$ESP_IDF_GLOB[_XXX]_YYY`: +- ### `$ESP_IDF_GLOB[_XXX]_BASE` and `$ESP_IDF_GLOB[_XXX]_YYY` A pair of environment variable prefixes that enable copying files and directory trees that match a certain glob mask into the native C project used for building the ESP-IDF framework: - `ESP_IDF_GLOB[_XXX]_BASE` specifies the base directory which will be glob-ed for resources to be copied @@ -214,7 +236,7 @@ The following configuration options are available: Note also that `_HOMEDIR` in the above example is optional, and is just a mechanism allowing the user to specify more than one base directory and its glob patterns. -- ### `$ESP_IDF_PIO_CONF_XXX` (*pio* builder only): +- ### `$ESP_IDF_PIO_CONF_XXX` (*pio* builder only) A PlatformIO setting (or multiple settings separated by a newline) that will be passed as-is to the `platformio.ini` file of the C project that compiles the ESP-IDF. @@ -228,7 +250,7 @@ The following configuration options are available: > starting with `ESP_IDF_PIO_CONF_`. For example, passing `ESP_IDF_PIO_CONF_1` as well as > `ESP_IDF_PIO_CONF_FOO` is valid and all such variables will be honored. -- ### *`esp_idf_cmake_generator`*, `$ESP_IDF_CMAKE_GENERATOR` (*native* builder only): +- ### *`esp_idf_cmake_generator`*, `$ESP_IDF_CMAKE_GENERATOR` (*native* builder only) The CMake generator to be used when building the ESP-IDF. @@ -241,14 +263,26 @@ The following configuration options are available: supports](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#cmake-generators) with **spaces and hyphens removed**. -- ### *`mcu`*, `$MCU`: +- ### *`mcu`*, `$MCU` The MCU name (i.e. `esp32`, `esp32s2`, `esp32s3` `esp32c3` and `esp32h2`). If not set this will be automatically detected from the cargo target. > ⚠️ - > [Older ESP-IDF versions might not support all MCUs from above](https://github.com/espressif/esp-idf#esp-idf-release-and-soc-compatibility). + > [Older ESP-IDF versions might not support all MCUs from above.](https://github.com/espressif/esp-idf#esp-idf-release-and-soc-compatibility) + +### Example + +An example of the `[package.metadata.esp-idf-sys]` section of the `Cargo.toml`. +```toml +[package.metadata.esp-idf-sys] +esp_idf_tools_install_dir = "global" +esp_idf_sdkconfig = "sdkconfig" +esp_idf_sdkconfig_defaults = ["sdkconfig.defaults", "sdkconfig.defaults.ble"] +# native builder only +esp_idf_version = "branch:release/v4.4" +``` ## Extra esp-idf components @@ -310,6 +344,39 @@ extra_components = [ ] ``` +## Conditional compilation + +The *esp-idf-sys* build script will set [rustc *cfg*s](https://doc.rust-lang.org/reference/conditional-compilation.html) +available for its sources. + +> ⚠️ If an upstream crate also wants to have access to the *cfg*s it must: +> - have `esp-idf-sys` as a dependency, and +> - propagate the *cfg*s in its [build +> script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) with +> +> ```rust +> embuild::build::CfgArgs::output_propagated("ESP_IDF").expect("no esp-idf-sys cfgs"); +> ``` +> using the [embuild](https://crates.io/crates/embuild) crate. + +The list of available *cfg*s: +- `esp_idf_comp_{component}_enabled` for each [component](#espidfcomponents-espidfcomponents-native-builder-only) +- `esp_idf_version="{major}.{minor}"` +- `esp_idf_version_full="{major}.{minor}.{patch}"` +- `esp_idf_version_major="{major}"` +- `esp_idf_version_minor="{minor}"` +- `esp_idf_version_patch="{patch}"` +- `esp_idf_{sdkconfig_option}` + + Each [sdkconfig + setting](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#configuration-options-reference) + where `{sdkconfig_option}` corresponds to the option set in the sdkconfig **lowercased** + and **without** the `CONFIG_` prefix. Only options set to `y` will get a *cfg*. + +- `{mcu}` + + Corresponds to the [mcu](#mcu-mcu) for which the esp-idf is compiled for. + ## More info If you are interested in how it all works under the hood, check the [build.rs](build/build.rs) From 3a955f4a6506cc28aa5c51524da7441839565a4a Mon Sep 17 00:00:00 2001 From: N3xed Date: Tue, 2 Aug 2022 22:03:18 +0200 Subject: [PATCH 2/2] Allow to specify which components are built Add `$ESP_IDF_COMPONENTS` and `esp_idf_components` configuration option that allow to specify a list of esp-idf components to build. This list can be used to trim down the esp-idf build and reduce compile time. Only implemented for the native build driver. Fixes #83 --- README.md | 13 +++++++++++++ build/config.rs | 19 ++++++++++--------- build/native/cargo_driver.rs | 7 +++++++ build/native/cargo_driver/config.rs | 14 ++++++++++++++ resources/cmake_project/CMakeLists.txt | 7 ++++++- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3317fa99159..756b780bd06 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,19 @@ The following configuration options are available: > ⚠️ > [Older ESP-IDF versions might not support all MCUs from above.](https://github.com/espressif/esp-idf#esp-idf-release-and-soc-compatibility) +- ### *`esp_idf_components`*, `$ESP_IDF_COMPONENTS` (*native* builder only) + + The list of esp-idf components (names) that should be built. This list is used to + trim the esp-idf build. Any component that is a dependency of a component in this + list will also automatically be built. + + Defaults to all components being built. + + > 🛈 **Note** + > Some components must be explicitly enabled in the sdkconfig. + > [Extra components](#extra-esp-idf-components) must also be added to this list if + > they are to be built. + ### Example An example of the `[package.metadata.esp-idf-sys]` section of the `Cargo.toml`. diff --git a/build/config.rs b/build/config.rs index 126a5ebc02d..6b081599906 100644 --- a/build/config.rs +++ b/build/config.rs @@ -23,7 +23,7 @@ pub struct BuildConfig { esp_idf_sdkconfig: Option, /// One or more paths to sdkconfig.defaults files used by the esp-idf. - #[serde(deserialize_with = "parse::sdkconfig_defaults")] + #[serde(deserialize_with = "parse::list")] esp_idf_sdkconfig_defaults: Option>, /// The MCU (esp32, esp32s2, esp32s3, esp32c3, ...) to compile for if unset will be @@ -173,21 +173,22 @@ where } } -mod parse { - use std::path::PathBuf; - +pub mod parse { use serde::{Deserialize, Deserializer}; use super::utils::ValueOrVec; - pub fn sdkconfig_defaults<'d, D: Deserializer<'d>>( - de: D, - ) -> Result>, D::Error> { - Option::>::deserialize(de).map(|val| match val { + /// Parse a string into a `;`-separated list of `T`s or parse a list of `T`s directly. + pub fn list<'d, T, D>(de: D) -> Result>, D::Error> + where + D: Deserializer<'d>, + T: for<'s> From<&'s str> + Deserialize<'d>, + { + Option::>::deserialize(de).map(|val| match val { Some(ValueOrVec::Val(s)) => Some( s.split(';') .filter(|s| !s.is_empty()) - .map(PathBuf::from) + .map(Into::into) .collect(), ), Some(ValueOrVec::Vec(v)) => Some(v), diff --git a/build/native/cargo_driver.rs b/build/native/cargo_driver.rs index c00eebaea15..fb8e777af93 100644 --- a/build/native/cargo_driver.rs +++ b/build/native/cargo_driver.rs @@ -317,6 +317,11 @@ pub fn build() -> Result { cmake_config.env("IDF_TOOLS_PATH", install_dir); } + // specify the components that should be built + if let Some(components) = &config.native.esp_idf_components { + cmake_config.env("COMPONENTS", components.join(";")); + } + // Build the esp-idf. cmake_config.build(); @@ -373,6 +378,8 @@ pub fn build() -> Result { }) .collect::>(); + eprintln!("Built components: {}", components.join(", ")); + let sdkconfig_json = path_buf![&cmake_build_dir, "config", "sdkconfig.json"]; let build_output = EspIdfBuildOutput { cincl_args: build::CInclArgs::try_from(&target.compile_groups[0])?, diff --git a/build/native/cargo_driver/config.rs b/build/native/cargo_driver/config.rs index ac2c4b3d429..62870bf6ab3 100644 --- a/build/native/cargo_driver/config.rs +++ b/build/native/cargo_driver/config.rs @@ -48,8 +48,19 @@ pub struct NativeConfig { /// /// Can be specified in the root crate's `package.metadata.esp-idf-sys` and all direct /// dependencies'. + /// + /// This option is not available as an environment variable. #[serde(alias = "extra-components")] pub extra_components: Vec, + + /// A list of esp-idf components (names) that should be built. This list is used to + /// trim the esp-idf build. Any component that is a dependency of a component in this + /// list will also automatically be built. + /// + /// If this option is not specified, all components will be built. Note though that + /// some components must be explicitly enabled in the sdkconfig. + #[serde(default, deserialize_with = "parse::list")] + pub esp_idf_components: Option>, } impl NativeConfig { @@ -181,6 +192,7 @@ impl NativeConfig { esp_idf_cmake_generator, idf_path, extra_components, + esp_idf_components, }, } = EspIdfSys::deserialize(&root.metadata)?; @@ -188,6 +200,7 @@ impl NativeConfig { set_when_none(&mut self.esp_idf_repository, esp_idf_repository); set_when_none(&mut self.esp_idf_cmake_generator, esp_idf_cmake_generator); set_when_none(&mut self.idf_path, idf_path); + set_when_none(&mut self.esp_idf_components, esp_idf_components); fn make_processor( package: &Package, @@ -317,6 +330,7 @@ mod parse { use strum::IntoEnumIterator; use super::*; + pub use crate::config::parse::*; use crate::config::utils::ValueOrVec; /// Parse a cmake generator, either `default` or one of [`cmake::Generator`]. diff --git a/resources/cmake_project/CMakeLists.txt b/resources/cmake_project/CMakeLists.txt index cb02dd545af..70e1c285db4 100644 --- a/resources/cmake_project/CMakeLists.txt +++ b/resources/cmake_project/CMakeLists.txt @@ -8,7 +8,12 @@ foreach(component_dir IN ITEMS $ENV{EXTRA_COMPONENT_DIRS}) idf_build_component(${component_dir}) endforeach() -idf_build_process($ENV{IDF_TARGET} SDKCONFIG $ENV{SDKCONFIG} SDKCONFIG_DEFAULTS $ENV{SDKCONFIG_DEFAULTS}) +if(DEFINED ENV{COMPONENTS}) + idf_build_process($ENV{IDF_TARGET} SDKCONFIG $ENV{SDKCONFIG} SDKCONFIG_DEFAULTS $ENV{SDKCONFIG_DEFAULTS} COMPONENTS $ENV{COMPONENTS}) +else() + idf_build_process($ENV{IDF_TARGET} SDKCONFIG $ENV{SDKCONFIG} SDKCONFIG_DEFAULTS $ENV{SDKCONFIG_DEFAULTS}) +endif() + idf_build_get_property(aliases BUILD_COMPONENT_ALIASES) add_executable(libespidf.elf main.c)