blob: 320ff66c5c7041b1ff466e61e2322d98bc9107b7 [file] [log] [blame]
David Tolnayb4dba232020-05-11 00:55:29 -07001// Functionality that is shared between the cxx_build::bridge entry point and
2// the cxxbridge CLI command.
David Tolnay7db73692019-10-20 14:51:12 -04003
4mod error;
David Tolnayfcd8f462020-08-29 12:13:09 -07005mod file;
David Tolnay7db73692019-10-20 14:51:12 -04006pub(super) mod include;
7pub(super) mod out;
8mod write;
9
David Tolnay0d47a532020-07-30 19:39:04 -070010#[cfg(test)]
11mod tests;
12
David Tolnay6f7f6862020-08-29 22:55:03 -070013pub use self::error::Error;
14use self::error::{format_err, Result};
David Tolnayfcd8f462020-08-29 12:13:09 -070015use self::file::File;
David Tolnay0dd85ff2020-05-03 23:43:33 -070016use crate::syntax::report::Errors;
David Tolnayb6cf3142020-04-19 20:56:09 -070017use crate::syntax::{self, check, Types};
Adrian Taylor9fc08462020-08-14 10:51:00 -070018use std::clone::Clone;
David Tolnay7db73692019-10-20 14:51:12 -040019use std::fs;
David Tolnay7db73692019-10-20 14:51:12 -040020use std::path::Path;
David Tolnay7db73692019-10-20 14:51:12 -040021
Adrian Taylor0926f642020-08-25 13:08:06 -070022/// Options for C++ code generation.
Adrian Taylor9fc08462020-08-14 10:51:00 -070023#[derive(Default, Clone)]
Adrian Taylor0926f642020-08-25 13:08:06 -070024pub struct Opt {
David Tolnay33d30292020-03-18 18:02:02 -070025 /// Any additional headers to #include
26 pub include: Vec<String>,
Adrian Taylor21f0ff02020-07-21 16:21:48 -070027 /// Whether to set __attribute__((visibility("default")))
28 /// or similar annotations on function implementations.
29 pub cxx_impl_annotations: Option<String>,
David Tolnay33d30292020-03-18 18:02:02 -070030}
31
David Tolnay7ece56f2020-03-29 21:21:38 -070032pub(super) fn do_generate_bridge(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040033 let header = false;
Adrian Taylor8205e622020-07-21 21:53:59 -070034 generate_from_path(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040035}
36
David Tolnay7ece56f2020-03-29 21:21:38 -070037pub(super) fn do_generate_header(path: &Path, opt: Opt) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040038 let header = true;
Adrian Taylor8205e622020-07-21 21:53:59 -070039 generate_from_path(path, opt, header)
David Tolnay7db73692019-10-20 14:51:12 -040040}
41
Adrian Taylor8205e622020-07-21 21:53:59 -070042fn generate_from_path(path: &Path, opt: Opt, header: bool) -> Vec<u8> {
David Tolnay7db73692019-10-20 14:51:12 -040043 let source = match fs::read_to_string(path) {
44 Ok(source) => source,
45 Err(err) => format_err(path, "", Error::Io(err)),
46 };
Adrian Taylor593eddb2020-08-21 23:46:08 -070047 match generate_from_string(&source, opt, header) {
Adrian Taylor8205e622020-07-21 21:53:59 -070048 Ok(out) => out,
David Tolnay7db73692019-10-20 14:51:12 -040049 Err(err) => format_err(path, &source, err),
Adrian Taylor593eddb2020-08-21 23:46:08 -070050 }
51}
52
53fn generate_from_string(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> {
David Tolnay5fc28552020-08-29 22:05:53 -070054 let mut source = source;
David Tolnay17c32302020-08-29 12:21:16 -070055 if source.starts_with("#!") && !source.starts_with("#![") {
56 let shebang_end = source.find('\n').unwrap_or(source.len());
57 source = &source[shebang_end..];
58 }
David Tolnay5fc28552020-08-29 22:05:53 -070059 let syntax: File = syn::parse_str(source)?;
Adrian Taylor593eddb2020-08-21 23:46:08 -070060 let results = generate(syntax, opt, header, !header)?;
61 match results {
62 (Some(hdr), None) => Ok(hdr),
63 (None, Some(cxx)) => Ok(cxx),
Adrian Taylor9fc08462020-08-14 10:51:00 -070064 _ => panic!("Unexpected generation"),
David Tolnay7db73692019-10-20 14:51:12 -040065 }
66}
Adrian Taylor8205e622020-07-21 21:53:59 -070067
David Tolnay366c41a2020-08-29 22:28:21 -070068pub(super) fn generate(
Adrian Taylor9fc08462020-08-14 10:51:00 -070069 syntax: File,
70 opt: Opt,
71 gen_header: bool,
72 gen_cxx: bool,
73) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
Adrian Taylor8205e622020-07-21 21:53:59 -070074 proc_macro2::fallback::force();
75 let ref mut errors = Errors::new();
David Tolnay3c64a4e2020-08-29 14:07:38 -070076 let bridge = syntax
77 .modules
78 .into_iter()
79 .next()
80 .ok_or(Error::NoBridgeMod)?;
Adrian Taylor8205e622020-07-21 21:53:59 -070081 let ref namespace = bridge.namespace;
David Tolnay805dca32020-08-29 19:09:55 -070082 let trusted = bridge.unsafety.is_some();
83 let ref apis = syntax::parse_items(errors, bridge.content, trusted);
Adrian Taylor8205e622020-07-21 21:53:59 -070084 let ref types = Types::collect(errors, apis);
85 errors.propagate()?;
86 check::typecheck(errors, namespace, apis, types);
87 errors.propagate()?;
Adrian Taylor9fc08462020-08-14 10:51:00 -070088 // Some callers may wish to generate both header and C++
89 // from the same token stream to avoid parsing twice. But others
90 // only need to generate one or the other.
91 let hdr = if gen_header {
92 Some(write::gen(namespace, apis, types, opt.clone(), true).content())
93 } else {
94 None
95 };
96 let cxx = if gen_cxx {
97 Some(write::gen(namespace, apis, types, opt, false).content())
98 } else {
99 None
100 };
101 Ok((hdr, cxx))
Adrian Taylor8205e622020-07-21 21:53:59 -0700102}