Skip to content

Commit

Permalink
Support custom pre-generated and generated include
Browse files Browse the repository at this point in the history
The default patterns are `{root_dir}/assets/capi/include/**/*` and
`{out_dir}/capi/include/**/*`.
  • Loading branch information
lu-zero committed Jun 30, 2021
1 parent bd11f6a commit 4c915b2
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 20 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ serde_derive = "1.0"
serde_json = "1.0.62"
anyhow = "1.0"
cc = "1.0"

glob = "0.3"
itertools = "0.10"

[features]
default = []
Expand Down
12 changes: 12 additions & 0 deletions example-project/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cargo_metadata::*;
use std::path::*;

fn main() {
let path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
Expand All @@ -9,4 +10,15 @@ fn main() {
.unwrap();

println!("{:?}", meta);

let out = std::env::var("OUT_DIR").unwrap();

let path = Path::new(&out).join("capi/include/");
let subdir = path.join("subdir");

std::fs::create_dir_all(&path).unwrap();
std::fs::create_dir_all(&subdir).unwrap();

std::fs::write(path.join("generated.h"), "// Generated").unwrap();
std::fs::write(subdir.join("in_subdir.h"), "// Generated").unwrap();
}
126 changes: 115 additions & 11 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ fn build_implib_file(
struct FingerPrint<'a> {
name: &'a str,
root_output: &'a Path,
build_targets: &'a BuildTargets,
build_targets: BuildTargets,
install_paths: &'a InstallPaths,
static_libs: &'a str,
}
Expand All @@ -319,7 +319,7 @@ impl<'a> FingerPrint<'a> {
fn new(
name: &'a str,
root_output: &'a Path,
build_targets: &'a BuildTargets,
build_targets: BuildTargets,
install_paths: &'a InstallPaths,
) -> Self {
Self {
Expand Down Expand Up @@ -405,6 +405,7 @@ pub struct CApiConfig {
pub header: HeaderCApiConfig,
pub pkg_config: PkgConfigCApiConfig,
pub library: LibraryCApiConfig,
pub install: InstallCApiConfig,
}

pub struct HeaderCApiConfig {
Expand Down Expand Up @@ -432,6 +433,61 @@ pub struct LibraryCApiConfig {
pub rustflags: Vec<String>,
}

pub struct InstallCApiConfig {
pub include: Vec<InstallTarget>,
}

pub enum InstallTarget {
Asset(InstallTargetPaths),
Generated(InstallTargetPaths),
}

#[derive(Clone)]
pub struct InstallTargetPaths {
/// pattern to feed to glob::glob()
///
/// if the InstallTarget is Asset its root is the the root_path
/// if the InstallTarget is Generated its root is the root_output
pub from: String,
/// The path to be joined to the canonical directory to install the files discovered by the
/// glob, e.g. `{includedir}/{to}` for includes.
pub to: String,
}

impl InstallTargetPaths {
pub fn install_paths(
&self,
root: &Path,
) -> anyhow::Result<impl Iterator<Item = (PathBuf, PathBuf)>> {
let pattern = root.join(&self.from);
let base_pattern = if self.from.contains("/**") {
pattern
.iter()
.take_while(|&c| c != std::ffi::OsStr::new("**"))
.collect()
} else {
root.to_path_buf()
};
let pattern = pattern.to_str().unwrap();
let to = PathBuf::from(&self.to);
let g = glob::glob(pattern)?.filter_map(move |p| {
if let Ok(p) = p {
if p.is_file() {
let from = p.to_path_buf();
let to = to.join(p.strip_prefix(&base_pattern).unwrap());
Some((from, to))
} else {
None
}
} else {
None
}
});

Ok(g)
}
}

fn load_manifest_capi_config(
name: &str,
root_path: &Path,
Expand Down Expand Up @@ -601,10 +657,28 @@ fn load_manifest_capi_config(
rustflags,
};

let default_assets_include = InstallTargetPaths {
from: "assets/capi/include/**/*".to_string(),
to: header.subdirectory.clone(),
};

let default_generated_include = InstallTargetPaths {
from: "capi/include/**/*".to_string(),
to: header.subdirectory.clone(),
};

let include = vec![
InstallTarget::Asset(default_assets_include),
InstallTarget::Generated(default_generated_include),
];

let install = InstallCApiConfig { include };

Ok(CApiConfig {
header,
pkg_config,
library,
install,
})
}

Expand Down Expand Up @@ -699,7 +773,7 @@ impl Executor for Exec {
}
}

use cargo::core::compiler::{unit_graph, Compilation, UnitInterner};
use cargo::core::compiler::{unit_graph, UnitInterner};
use cargo::ops::create_bcx;
use cargo::util::profile;

Expand All @@ -725,7 +799,7 @@ fn compile_with_exec<'a>(
exec: &Arc<dyn Executor>,
leaf_args: &[String],
global_args: &[String],
) -> CargoResult<Compilation<'a>> {
) -> CargoResult<String> {
ws.emit_warnings()?;
let interner = UnitInterner::new();
let mut bcx = create_bcx(ws, options, &interner)?;
Expand All @@ -741,11 +815,33 @@ fn compile_with_exec<'a>(

if options.build_config.unit_graph {
unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph, ws.config())?;
return Compilation::new(&bcx);
return Ok(String::new());
}
let _p = profile::start("compiling");
let cx = cargo::core::compiler::Context::new(&bcx)?;
cx.compile(exec)

let r = cx.compile(exec)?;

// NOTE: right now we have only a single cdylib since we have a single package to build.
let out_dir = r
.cdylibs
.iter()
.filter_map(|l| {
l.script_meta.map(|m| {
r.extra_env.get(&m).unwrap().iter().filter_map(|e| {
if e.0 == "OUT_DIR" {
Some(e.1.clone())
} else {
None
}
})
})
})
.flatten()
.next()
.unwrap();

Ok(out_dir)
}

pub fn cbuild(
Expand Down Expand Up @@ -829,10 +925,11 @@ pub fn cbuild(
leaf_args.push("target-feature=+crt-static".into());
}

let build_targets =
BuildTargets::new(&name, &rustc_target, &root_output, &libkinds, &capi_config);
let mut build_targets =
BuildTargets::new(&name, &rustc_target, &root_output, &libkinds, &capi_config)?;

let mut finger_print = FingerPrint::new(&name, &root_output, &build_targets, &install_paths);
let mut finger_print =
FingerPrint::new(&name, &root_output, build_targets.clone(), &install_paths);

let pristine = finger_print.load_previous().is_err();

Expand All @@ -842,14 +939,20 @@ pub fn cbuild(
}

let exec = Arc::new(Exec::default());
let _r = compile_with_exec(
let out_dir = compile_with_exec(
ws,
&compile_opts,
&(exec.clone() as Arc<dyn Executor>),
&leaf_args,
&capi_config.library.rustflags,
)?;

let out_dir = Path::new(&out_dir);

build_targets
.extra
.setup(&capi_config, &root_path, &out_dir)?;

if pristine {
// restore the default to make sure the tests do not trigger a second rebuild.
compile_opts.build_config.force_rebuild = false;
Expand Down Expand Up @@ -903,7 +1006,8 @@ pub fn cbuild(
&root_output,
&libkinds,
&capi_config,
);
)?;

if let (Some(from_static_lib), Some(to_static_lib)) = (
from_build_targets.static_lib.as_ref(),
build_targets.static_lib.as_ref(),
Expand Down
46 changes: 41 additions & 5 deletions src/build_targets.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
use std::path::{Path, PathBuf};

use crate::build::CApiConfig;
use crate::build::{CApiConfig, InstallTarget};
use crate::target::Target;

#[derive(Debug)]
#[derive(Debug, Default, Clone)]
pub struct ExtraTargets {
pub include: Vec<(PathBuf, PathBuf)>,
}

impl ExtraTargets {
pub fn setup(
&mut self,
capi_config: &CApiConfig,
root_dir: &Path,
out_dir: &Path,
) -> anyhow::Result<()> {
self.include = extra_targets(&capi_config.install.include, root_dir, out_dir)?;

Ok(())
}
}

fn extra_targets(
targets: &[InstallTarget],
root_path: &Path,
root_output: &Path,
) -> anyhow::Result<Vec<(PathBuf, PathBuf)>> {
use itertools::*;
targets
.iter()
.map(|t| match t {
InstallTarget::Asset(paths) => paths.install_paths(root_path),
InstallTarget::Generated(paths) => paths.install_paths(root_output),
})
.flatten_ok()
.collect()
}

#[derive(Debug, Clone)]
pub struct BuildTargets {
pub include: Option<PathBuf>,
pub static_lib: Option<PathBuf>,
Expand All @@ -12,6 +46,7 @@ pub struct BuildTargets {
pub def: Option<PathBuf>,
pub pc: PathBuf,
pub target: Target,
pub extra: ExtraTargets,
}

impl BuildTargets {
Expand All @@ -21,7 +56,7 @@ impl BuildTargets {
targetdir: &Path,
libkinds: &[&str],
capi_config: &CApiConfig,
) -> BuildTargets {
) -> anyhow::Result<BuildTargets> {
let pc = targetdir.join(&format!("{}.pc", &capi_config.pkg_config.filename));
let include = if capi_config.header.enabled {
let mut header_name = PathBuf::from(&capi_config.header.name);
Expand Down Expand Up @@ -83,14 +118,15 @@ impl BuildTargets {
None
};

BuildTargets {
Ok(BuildTargets {
pc,
include,
static_lib,
shared_lib,
impl_lib,
def,
target: target.clone(),
}
extra: Default::default(),
})
}
}
12 changes: 9 additions & 3 deletions src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use structopt::clap::ArgMatches;
use cargo::core::Workspace;
use semver::Version;

use crate::build::CApiConfig;
use crate::build::*;
use crate::build_targets::BuildTargets;

use anyhow::Context;
Expand Down Expand Up @@ -184,8 +184,7 @@ pub fn cinstall(

let install_path_lib = append_to_destdir(destdir, &install_path_lib);
let install_path_pc = append_to_destdir(destdir, &paths.pkgconfigdir);
let install_path_include =
append_to_destdir(destdir, &paths.includedir).join(&paths.subdir_name);
let install_path_include = append_to_destdir(destdir, &paths.includedir);

fs::create_dir_all(&install_path_lib)?;
fs::create_dir_all(&install_path_pc)?;
Expand All @@ -199,6 +198,7 @@ pub fn cinstall(
)?;

if capi_config.header.enabled {
let install_path_include = install_path_include.join(&paths.subdir_name);
fs::create_dir_all(&install_path_include)?;
ws.config().shell().status("Installing", "header file")?;
let include = &build_targets.include.clone().unwrap();
Expand All @@ -208,6 +208,12 @@ pub fn cinstall(
)?;
}

for (from, to) in build_targets.extra.include.iter() {
let to = install_path_include.join(to);
fs::create_dir_all(to.parent().unwrap())?;
copy(from, to)?;
}

if let Some(ref static_lib) = build_targets.static_lib {
ws.config().shell().status("Installing", "static library")?;
copy(
Expand Down

0 comments on commit 4c915b2

Please sign in to comment.