| // Functionality that is shared between the cxx_build::bridge entry point and |
| // the cxxbridge CLI command. |
| |
| mod error; |
| mod file; |
| pub(super) mod include; |
| pub(super) mod out; |
| mod write; |
| |
| #[cfg(test)] |
| mod tests; |
| |
| use self::error::{format_err, Error, Result}; |
| use self::file::File; |
| use crate::syntax::report::Errors; |
| use crate::syntax::{self, check, Types}; |
| use std::fs; |
| use std::path::Path; |
| |
| #[derive(Default)] |
| pub(super) struct Opt { |
| /// Any additional headers to #include |
| pub include: Vec<String>, |
| /// Whether to set __attribute__((visibility("default"))) |
| /// or similar annotations on function implementations. |
| pub cxx_impl_annotations: Option<String>, |
| } |
| |
| pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> { |
| let header = false; |
| generate_from_path(path, opt, header) |
| } |
| |
| pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> { |
| let header = true; |
| generate_from_path(path, opt, header) |
| } |
| |
| fn generate_from_path(path: &Path, opt: Opt, header: bool) -> Vec<u8> { |
| let source = match fs::read_to_string(path) { |
| Ok(source) => source, |
| Err(err) => format_err(path, "", Error::Io(err)), |
| }; |
| let mut source = source.as_str(); |
| if source.starts_with("#!") && !source.starts_with("#![") { |
| let shebang_end = source.find('\n').unwrap_or(source.len()); |
| source = &source[shebang_end..]; |
| } |
| match generate(source, opt, header) { |
| Ok(out) => out, |
| Err(err) => format_err(path, source, err), |
| } |
| } |
| |
| fn generate(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> { |
| proc_macro2::fallback::force(); |
| let ref mut errors = Errors::new(); |
| let syntax: File = syn::parse_str(source)?; |
| let bridge = syntax |
| .modules |
| .into_iter() |
| .next() |
| .ok_or(Error::NoBridgeMod)?; |
| let ref namespace = bridge.namespace; |
| let ref apis = syntax::parse_items(errors, bridge.content); |
| let ref types = Types::collect(errors, apis); |
| errors.propagate()?; |
| check::typecheck(errors, namespace, apis, types); |
| errors.propagate()?; |
| let out = write::gen(namespace, apis, types, opt, header); |
| Ok(out.content()) |
| } |