Skip to content

Commit

Permalink
Improve documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
N3xed committed Jul 20, 2022
1 parent 1a0a4cf commit 14c2bb6
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 20 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Build support for embedded Rust

![CI](https://github.com/esp-rs/embuild/actions/workflows/ci.yml/badge.svg)
![docs.rs](https://img.shields.io/docsrs/embuild)

A library with many utilities for building embedded frameworks, libraries, and other
artifacts in a cargo build script.
Expand All @@ -10,30 +11,32 @@ It is currently mainly used to simplify building the [`esp-idf`](https://github.
utilities are organized into specific modules so that they and their dependencies can be
turned on or off with features.

The follwing is the current list of features and their utilities:
A list of current features and their utilities:

- `pio = ["ureq", "bindgen", "tempfile", "which", "manifest", "serde", "serde_json"]`
- `pio`
- Platformio support.
- `cmake = ["dep-cmake", "tempfile", "bindgen", "serde", "serde_json", "strum"]`
- `cmake`
- CMake file-api support and utilities.
- `glob = ["globwalk"]`
- `glob` (used in the `build` module)
- Glob utilities.
- `manifest = ["cargo_toml", "toml"]`
- `manifest` (used in the `cargo` module)
- Cargo.toml and config.toml utilities.
- `espidf = ["tempfile", "which", "git", "serde", "serde_json", "strum", "dirs"]`
- `espidf`
- An installer to install the esp-idf framework.
- `git = ["remove_dir_all"]`
- `git`
- Git utilities for manipulating repositories using the git CLI.
- `kconfig = ["serde", "serde_json"]`
- `kconfig`
- kconfig file parsing.
- `elf = ["xmas-elf"]`
- `elf` (`bingen`, `symgen` and `espidf::ulp_fsm` modules)
- Elf file manipulation.

Other utilities that are not behind features include:
- `cargo`
- Utils for interacting with cargo through the CLI, and stdout in a build script.
- `cmd`
- Macros and wrappers for running commands and getting their results easier.
- `cli`
- Command line arguments manipulation.

## Tools

Expand Down
13 changes: 12 additions & 1 deletion src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use anyhow::{anyhow, bail, Context, Error, Result};
use crate::utils::OsStrExt;
use crate::{cargo, cmd};

/// The environment variable name containing the file path of the file that contains the
/// generated bindings.
pub const VAR_BINDINGS_FILE: &str = "EMBUILD_GENERATED_BINDINGS_FILE";

/// A builder for creating a [`bindgen::Builder`].
Expand All @@ -23,6 +25,8 @@ pub struct Factory {
}

impl Factory {
/// Create a new factory populating the clang args, linker and mcu from the
/// Scons variables of a platformio project.
#[cfg(feature = "pio")]
pub fn from_scons_vars(scons_vars: &crate::pio::project::SconsVariables) -> Result<Self> {
use crate::cli;
Expand All @@ -41,6 +45,8 @@ impl Factory {
})
}

/// Create a new factory populating the clang args, force cpp, and sysroot from the
/// cmake file-api compile group.
#[cfg(feature = "cmake")]
pub fn from_cmake(
compile_group: &crate::cmake::file_api::codemodel::target::CompileGroup,
Expand Down Expand Up @@ -98,10 +104,12 @@ impl Factory {
self
}

/// Create a [`bindgen::Builder`] with these settings.
pub fn builder(self) -> Result<bindgen::Builder> {
self.create_builder(false)
}

/// Create a [`bindgen::Builder`] creating C++ bindings with these settings.
pub fn cpp_builder(self) -> Result<bindgen::Builder> {
self.create_builder(true)
}
Expand Down Expand Up @@ -147,6 +155,8 @@ impl Factory {
}
}

/// Create rust bindings in the out dir and set the environment variable named
/// [`VAR_BINDINGS_FILE`] to the path of the bindings file.
pub fn run(builder: bindgen::Builder) -> Result<PathBuf> {
let output_file = PathBuf::from(env::var("OUT_DIR")?).join("bindings.rs");
run_for_file(builder, &output_file)?;
Expand All @@ -156,6 +166,7 @@ pub fn run(builder: bindgen::Builder) -> Result<PathBuf> {
Ok(output_file)
}

/// Create rust bindings in `output_file` and run `cargo fmt` over that file.
pub fn run_for_file(builder: bindgen::Builder, output_file: impl AsRef<Path>) -> Result<()> {
let output_file = output_file.as_ref();

Expand All @@ -182,7 +193,7 @@ pub fn run_for_file(builder: bindgen::Builder, output_file: impl AsRef<Path>) ->
.is_err()
{
cargo::print_warning(
"cargo:warning=rustfmt not found in the current toolchain, nor in stable or nightly. \
"rustfmt not found in the current toolchain, nor in stable or nightly. \
The generated bindings will not be properly formatted.",
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ const VAR_CFG_ARGS: &str = "EMBUILD_CFG_ARGS";

const LINK_ARGS_FILE_NAME: &str = "linker_args.txt";

/// The name of the ldproxy executable.
pub const LDPROXY_NAME: &str = "ldproxy";

/// The `--ldproxy-linker` argument definition.
pub const LDPROXY_LINKER_ARG: ArgDef = Arg::option("ldproxy-linker").long();
/// The `--ldproxy-dedup-libs` argument definition.
pub const LDPROXY_DEDUP_LIBS_ARG: ArgDef = Arg::flag("ldproxy-dedup-libs").long();
/// The `--ldproxy-cwd` argument definition.
pub const LDPROXY_WORKING_DIRECTORY_ARG: ArgDef = Arg::option("ldproxy-cwd").long();

pub fn env_options_iter(
Expand Down Expand Up @@ -159,7 +163,7 @@ pub struct LinkArgsBuilder {
impl LinkArgsBuilder {
/// Whether the linker should be `ldproxy`.
///
/// See https://crates.io/crates/ldproxy for more information.
/// See <https://crates.io/crates/ldproxy> for more information.
pub fn force_ldproxy(mut self, value: bool) -> Self {
self.force_ldproxy = value;
self
Expand Down
6 changes: 6 additions & 0 deletions src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,23 @@ use log::*;
use crate::utils::{OsStrExt, PathExt};
use crate::{cargo, cmd};

/// Which cargo command to execute and whether the standard library should be built
/// locally.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum CargoCmd {
New(BuildStd),
Init(BuildStd),
Upgrade,
}

/// Which part of the rust standard library should be built.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum BuildStd {
/// None.
None,
/// Only `core`.
Core,
/// `std` (which includes `core` and `alloc`).
Std,
}

Expand Down
17 changes: 15 additions & 2 deletions src/cli/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::fmt::Display;

use bitflags::bitflags;

/// The type of a command line argument.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Arg {
/// A flag with a name (ex. `-n` or `--name`).
Expand Down Expand Up @@ -46,6 +47,9 @@ impl Arg {
}

bitflags! {
/// Argument options for parsing and formatting arguments.
///
/// See [`ArgDef::parse`] and [`ArgDef::format`] for parsing and formatting.
pub struct ArgOpts: u32 {
/// The argument can use a single hypen (ex. `-<argname>`)
const SINGLE_HYPHEN = (1 << 0);
Expand Down Expand Up @@ -108,17 +112,22 @@ impl ArgOpts {
}
}

/// An command line argument definition of how to parse and format a specific argument.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[must_use]
pub struct ArgDef<'s, 'a> {
/// The type of argument (flag or option).
pub arg: Arg,
/// The name of the argument.
pub name: &'s str,
/// One or more alias and optionally corresponding [`ArgOpts`].
pub alias: &'a [(&'a str, Option<ArgOpts>)],
/// The default [`ArgOpts`].
pub opts: ArgOpts,
}

impl<'s, 'a> ArgDef<'s, 'a> {
/// Set the `alias`(s) for this definition, each alias can have their own [`ArgOpts`]
/// Set the `alias`(es) for this definition, each alias can have their own [`ArgOpts`]
/// which override the default [`opts`](ArgDef::opts) when set.
pub const fn with_alias<'b>(self, alias: &'b [(&'b str, Option<ArgOpts>)]) -> ArgDef<'s, 'b> {
ArgDef {
Expand Down Expand Up @@ -157,7 +166,11 @@ impl<'s, 'a> ArgDef<'s, 'a> {

/// Generate individual arguments from this argument definition and a `value`.
///
/// The `value` is ignored if this definition is a [`Arg::Flag`].
/// `value` is ignored if this definition is of type [`Arg::Flag`].
///
/// The returned value can be iterated over to get all whitespace-separated parts of
/// the argument, and it can be [`Display`]ed as a single string, where the parts will
/// be separated by a whitespace.
pub fn format(&self, value: Option<&str>) -> impl Iterator<Item = String> + Display {
let ArgDef {
arg, name, opts, ..
Expand Down
8 changes: 7 additions & 1 deletion src/cli/parse_args.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::{Arg, ArgDef};

/// The error when parsing an command line argument.
#[derive(PartialEq, Eq, Debug)]
pub enum ParseError {
/// The command line argument or flag was not found.
NotFound,
}

Expand All @@ -12,7 +14,8 @@ impl std::fmt::Display for ParseError {
}
}

pub type Result<T> = std::result::Result<T, ParseError>;
/// The result of parsing an command line argument.
pub type Result<T, E = ParseError> = std::result::Result<T, E>;

impl super::ArgDef<'_, '_> {
/// Parse this argument definition from `args` at offset `i`.
Expand Down Expand Up @@ -73,7 +76,10 @@ impl super::ArgDef<'_, '_> {
}
}

/// An extension trait for parsing a collection of [`ArgDef`]s from a [`Vec`] of argument
/// [`String`]s.
pub trait ParseFrom<const N: usize> {
/// Result type of the parsed command line argument.
type R;

fn parse_from(&self, args: &mut Vec<String>) -> Self::R;
Expand Down
1 change: 1 addition & 0 deletions src/espidf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl Tools {
}
}

/// The error returned by [`EspIdf::try_from_env`].
#[derive(Debug, thiserror::Error)]
pub enum FromEnvError {
/// No `esp-idf` repository detected in the environment.
Expand Down
5 changes: 4 additions & 1 deletion src/git.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Git utilities.
//! Git repository manipulation through the git CLI.
// TODO: maybe use `git2` crate

use std::ffi::OsStr;
Expand Down Expand Up @@ -76,6 +76,7 @@ impl Repository {
})
}

/// Get the path to the worktree of this git repository.
pub fn worktree(&self) -> &Path {
&self.worktree
}
Expand Down Expand Up @@ -349,6 +350,7 @@ impl std::fmt::Display for ResetMode {
}
}

/// A reference to a git tag, branch or commit.
#[derive(Debug, Clone)]
pub enum Ref {
Tag(String),
Expand All @@ -366,6 +368,7 @@ impl Display for Ref {
}
}

/// Options for how a repository should be cloned by [`Repository::clone_ext`].
#[derive(Debug, Default)]
#[must_use]
pub struct CloneOptions {
Expand Down
20 changes: 20 additions & 0 deletions src/kconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,41 @@ use std::path::Path;

use anyhow::Result;

/// A tristate kconfig configuration item.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Tristate {
/// The item is enabled, compiled, true.
True,
/// The item is disabled, excluded, false.
False,
/// The item is compiled as module.
///
/// Related to a linux kernel functionality that should be compiled as a loadable
/// module (hence the name).
Module,
/// The item is unset.
NotSet,
}

/// Value of a kconfig configuration item.
#[derive(Clone, Debug)]
pub enum Value {
/// A [`Tristate`] value.
Tristate(Tristate),
/// A [`String`] value.
String(String),
}

impl Value {
/// Turn a configuration value of an item named `key` into a valid rust cfg.
///
/// Only the following cfgs will be generated:
/// - For a [`Tristate::True`], `<prefix>_<key>`;
/// - for a [`String`], `<prefix>_<key>="<value>"`.
///
/// All other values return [`None`].
///
/// Both `prefix` and `key` will be lowercased before being.
pub fn to_rustc_cfg(&self, prefix: impl AsRef<str>, key: impl AsRef<str>) -> Option<String> {
match self {
Value::Tristate(Tristate::True) => Some(""),
Expand Down
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//! # Build support for embedded Rust
//!
//! A library with many utilities for building embedded frameworks, libraries, and other
//! artifacts in a cargo build script.
//!
//! It is currently mainly used to simplify building the [`esp-idf`](https://github.com/espressif/esp-idf) in the build script of the
//! [`esp-idf-sys`](https://github.com/esp-rs/esp-idf-sys) crate, but anyone may use them as they're intended to be general. The
//! utilities are organized into specific modules so that they and their dependencies can be
//! turned on or off with features.

// Allows docs.rs to document any needed features for items
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

Expand Down
5 changes: 5 additions & 0 deletions src/pio.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Platformio installation and manipulation support.

pub mod project;

use std::collections::{HashMap, HashSet};
Expand All @@ -20,6 +22,7 @@ use crate::utils;
const INSTALLER_URL: &str = "https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py";
const INSTALLER_BLOB: &[u8] = include_bytes!("pio/resources/get-platformio.py.resource");

/// The logging verbosity level when executing platformio.
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum LogLevel {
Quiet,
Expand All @@ -33,6 +36,7 @@ impl Default for LogLevel {
}
}

/// A platformio platform defintion.
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct Platform {
pub ownername: String,
Expand All @@ -47,6 +51,7 @@ pub struct Platform {
pub versions: Vec<String>,
}

/// A platformio framework definition.
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
#[serde(default)]
pub struct Framework {
Expand Down
15 changes: 11 additions & 4 deletions src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ use anyhow::{anyhow, Context, Result};

use crate::cmd;

#[cfg(windows)]
pub const PYTHON: &str = "python"; // No 'python3.exe' on Windows
#[cfg(not(windows))]
pub const PYTHON: &str = "python3";
/// Python 3 executable name.
///
/// `python` for Window, `python3` otherwise.
pub const PYTHON: &str = {
if cfg!(windows) {
// No 'python3.exe' on Windows
"python"
} else {
"python3"
}
};

/// Check that python is at least `major.minor`.
pub fn check_python_at_least(major: u32, minor: u32) -> Result<()> {
Expand Down
Loading

0 comments on commit 14c2bb6

Please sign in to comment.