Skip to content

Commit

Permalink
Workaround relative linker args
Browse files Browse the repository at this point in the history
This workaround currently simply copies the esp-idf build output to the workspace directory,
this creates the folder `esp-idf` in the workspace root after a build, which should be added to the gitignore.
It is currently the simplest solution as this doesn't require any additional tools.

Also improved the code a bit.
  • Loading branch information
N3xed committed Aug 11, 2021
1 parent c4e4fad commit a29faf2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 96 deletions.
6 changes: 6 additions & 0 deletions sdk_build_support/cmake_file_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ impl IndexReply {
CodemodelTarget::from_file(&path_buf![&self.reply_dir, &self.json_file])
}

/// Try to get the target with name `target_name`.
///
/// Note:
/// This method takes a `&mut self` because it caches all references to the json files
/// which actually contain all information about the target (Please look at the
/// cmake-file-api documentation for more information).
pub fn get_target(&mut self, target_name: &str) -> Result<Option<target::Target>> {
if self.targets.is_empty() {
self.targets = self.get_targets()?;
Expand Down
80 changes: 31 additions & 49 deletions sdk_build_support/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ pub mod consts;
use chip::*;
use utils::*;

use std::array::{self};
use std::array;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::process::Stdio;
use std::{env, path::PathBuf};

use anyhow::*;
Expand Down Expand Up @@ -190,18 +189,23 @@ pub fn build(build_env: &BuildEnv) -> Result<()> {
.map(|s| s.to_owned())
.collect();
bin_paths.pop();
let bin_paths: Vec<_> = bin_paths.into_iter().map(|s| to_win_path(s)).collect();
let bin_paths: Vec<_> = bin_paths
.into_iter()
.map(|s| PathBuf::from(to_win_path(s)))
.chain(env::split_paths(&env::var("PATH")?))
.collect();
let gcc_bin_dir = PathBuf::from(
bin_paths
.iter()
.find(|s| s.contains(chip.target_triple()))
.find(|s| s.to_string_lossy().contains(chip.target_triple()))
.ok_or_else(|| {
anyhow!(
"Could not get the path to the toolchain of chip '{}'.",
chip_target_triple
)
})?,
);
let paths = env::join_paths(bin_paths.iter())?;

// Create dummy cmake project (copies from `cmake_project`).
let libespidf_dir = path_buf![out_dir, "libespidf"];
Expand All @@ -215,13 +219,6 @@ pub fn build(build_env: &BuildEnv) -> Result<()> {
&libespidf_dir
)?;

let paths = env::join_paths(
bin_paths
.iter()
.map(PathBuf::from)
.chain(env::split_paths(&env::var("PATH")?)),
)?;

// Create cmake-file-api query file.
let file_api_dir = path_buf![&libespidf_build_dir, ".cmake", "api", "v1"];
let query_dir = path_buf![&file_api_dir, "query", "client-esp_idf_sys"];
Expand Down Expand Up @@ -269,7 +266,15 @@ pub fn build(build_env: &BuildEnv) -> Result<()> {
// Note: This unconditionally adds `/build` to the here specified path.
.out_dir(&libespidf_dir)
.build_target("all")
.define("CMAKE_TOOLCHAIN_FILE", path_buf![&esp_idf_dir, "tools", "cmake", &format!("toolchain-{}.cmake", &mcu)])
.define(
"CMAKE_TOOLCHAIN_FILE",
path_buf![
&esp_idf_dir,
"tools",
"cmake",
&format!("toolchain-{}.cmake", &mcu)
],
)
.always_configure(false)
.pic(false)
.asmflag(chip.asmflags())
Expand Down Expand Up @@ -338,53 +343,30 @@ pub fn build(build_env: &BuildEnv) -> Result<()> {

// Create archive of all libraries and write linker args to file.
env::set_current_dir(&libespidf_build_dir)?;
let args = utils::parse_linker_args(target.link);

let mut espidf_ar_mri = vec![];
let linker_args_file = out_dir.join("linker_args.rsp");
let mut linker_args_rsp = fs::File::create(&linker_args_file)?;

let espidf_lib = "libespidf.a";
write!(
&mut linker_args_rsp,
"\"{}\" ",
libespidf_build_dir
.join(&espidf_lib)
.to_string_lossy()
.replace('\\', "/")
)?;

espidf_ar_mri.push(format!("CREATE {}", espidf_lib));
for (arg, arg_type) in args {
match arg_type {
LinkArgType::Library => {
espidf_ar_mri.push(format!("ADDLIB {}", arg));
}
LinkArgType::Flags => {
write!(&mut linker_args_rsp, "{} ", arg)?;
}
}
for f in target.link.command_fragments {
write!(&mut linker_args_rsp, "{} ", f.fragment.replace('\\', "/"))?;
}
espidf_ar_mri.push("SAVE".into());
espidf_ar_mri.push("END".into());

drop(linker_args_rsp);

let ar = format!("{}-ar", &chip_target_triple);
let mut handle = cmd_spawn!(ar, "-M";
env=("PATH", &paths),
stdin=(Stdio::piped()),
stdout=(Stdio::inherit()),
stderr=(Stdio::inherit())
)?;
write!(
&mut handle.stdin.take().unwrap(),
"{}",
espidf_ar_mri.join("\n")
cmd!("cmake", "-E", "rm", "-rf", workspace_dir.join("esp-idf")).ok();
cmd!(
"cmake",
"-E",
"copy_directory",
libespidf_build_dir.join("esp-idf"),
workspace_dir.join("esp-idf")
)?;
handle.wait()?;

println!("cargo:LINKER_ARG=@{}", linker_args_file.display());
println!(
"cargo:LINKER={}/{}-gcc",
gcc_bin_dir.display(),
chip_target_triple
);

Ok(())
}
51 changes: 4 additions & 47 deletions sdk_build_support/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use std::{

use anyhow::Result;

use crate::cmake_file_api::{self, target::Role};

/// Build a [`PathBuf`].
///
/// # Examples
Expand Down Expand Up @@ -35,7 +33,7 @@ macro_rules! cmd_spawn {
$(builder.arg($cmdarg);)*
$(builder. $k $v;)*

Ok::<_, std::io::Error>(builder.spawn()?)
builder.spawn()
}};
($cmd:expr $(,$cmdarg:expr)*) => {
cmd_spawn!($cmd, $($cmdarg),*;)
Expand All @@ -54,7 +52,7 @@ macro_rules! cmd {
Err(err) => Err(err.into()),
Ok(result) => {
if !result.success() {
Err(anyhow::anyhow!("Command '{:?}' (args = [{}]) failed with exit code {:?}.", cmd, stringify!($($cmdarg),*), result.code()))
Err(anyhow::anyhow!("Command '{:?}' failed with exit code {:?}.", &builder, result.code()))
}
else {
Ok(result)
Expand Down Expand Up @@ -95,7 +93,7 @@ macro_rules! cmd_output {
std::io::stdout().write_all(&result.stdout[..]).ok();
std::io::stderr().write_all(&result.stderr[..]).ok();

Err(anyhow::anyhow!("Command '{:?}' (args = [{}]) failed with exit code {:?}.", cmd, stringify!($($cmdarg),*), result.status.code()))
Err(anyhow::anyhow!("Command '{:?}' failed with exit code {:?}.", &builder, result.status.code()))
}
else {
Ok(String::from_utf8_lossy(&result.stdout[..]).trim_end_matches(&['\n', '\r'][..]).to_string())
Expand Down Expand Up @@ -129,7 +127,7 @@ pub fn abspath(file: impl AsRef<Path>) -> Result<PathBuf> {
if file.as_ref().is_absolute() {
return Ok(file.as_ref().to_owned());
}

Ok(env::current_dir()?.join(file))
}

Expand All @@ -152,45 +150,4 @@ pub fn push_current_dir(path: impl AsRef<Path>) -> Result<PushedPathGuard> {
env::set_current_dir(path)?;

Ok(PushedPathGuard(last_dir))
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum LinkArgType {
Flags,
Library,
}

pub fn parse_linker_args(link: cmake_file_api::target::Link) -> Vec<(String, LinkArgType)> {
let mut args: Vec<(String, LinkArgType)> = vec![];

link.command_fragments.into_iter().rev().map(|f| {
let frag = f.fragment;
if f.role != Role::Libraries {
return (frag, LinkArgType::Flags);
}

if frag.starts_with("-") {
(frag, LinkArgType::Flags)
}
else if Path::new(&frag).exists() {
(frag, LinkArgType::Library)
}
else {
(frag, LinkArgType::Flags)
}
}).for_each(|arg| {
if args.iter().find(|v| v.1 == arg.1 && &v.0 == &arg.0).is_none() {
args.push(arg)
}
});
args.reverse();

#[cfg(windows)]
{
for (f, _) in args.iter_mut() {
*f = f.replace('\\', "/");
}
}

args
}

0 comments on commit a29faf2

Please sign in to comment.