blob: 77a0c6580415f01a2fee62e40179eaf1dd99f6ee [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 Tolnay2967b662020-05-11 00:53:06 -07005mod find;
David Tolnay7db73692019-10-20 14:51:12 -04006pub(super) mod include;
7pub(super) mod out;
8mod write;
9
David Tolnay52509842020-04-25 19:38:59 -070010use self::error::{format_err, Error, Result};
David Tolnay08419302020-04-19 20:38:20 -070011use crate::syntax::namespace::Namespace;
David Tolnay0dd85ff2020-05-03 23:43:33 -070012use crate::syntax::report::Errors;
David Tolnayb6cf3142020-04-19 20:56:09 -070013use crate::syntax::{self, check, Types};
David Tolnay7db73692019-10-20 14:51:12 -040014use std::fs;
David Tolnay7db73692019-10-20 14:51:12 -040015use std::path::Path;
David Tolnay2967b662020-05-11 00:53:06 -070016use syn::Item;
David Tolnay7db73692019-10-20 14:51:12 -040017
18struct Input {
David Tolnay754e21c2020-03-29 20:58:46 -070019 namespace: Namespace,
David Tolnay7db73692019-10-20 14:51:12 -040020 module: Vec<Item>,
21}
22
David Tolnay33d30292020-03-18 18:02:02 -070023#[derive(Default)]
24pub(super) struct Opt {
25 /// 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 Taylor8205e622020-07-21 21:53:59 -070047 match generate(&source, opt, header) {
48 Ok(out) => out,
David Tolnay7db73692019-10-20 14:51:12 -040049 Err(err) => format_err(path, &source, err),
50 }
51}
Adrian Taylor8205e622020-07-21 21:53:59 -070052
53fn generate(source: &str, opt: Opt, header: bool) -> Result<Vec<u8>> {
54 proc_macro2::fallback::force();
55 let ref mut errors = Errors::new();
56 let syntax = syn::parse_file(&source)?;
57 let bridge = find::find_bridge_mod(syntax)?;
58 let ref namespace = bridge.namespace;
59 let ref apis = syntax::parse_items(errors, bridge.module);
60 let ref types = Types::collect(errors, apis);
61 errors.propagate()?;
62 check::typecheck(errors, namespace, apis, types);
63 errors.propagate()?;
64 let out = write::gen(namespace, apis, types, opt, header);
65 Ok(out.content())
66}
67
68#[cfg(test)]
69mod tests {
70 use crate::gen::{generate, Opt};
71
72 const CPP_EXAMPLE: &'static str = r#"
73 #[cxx::bridge]
74 mod ffi {
75 extern "C" {
76 pub fn do_cpp_thing(foo: &str);
77 }
78 }
79 "#;
80
81 #[test]
82 fn test_cpp() {
83 let opts = Opt {
84 include: Vec::new(),
85 cxx_impl_annotations: None,
86 };
87 let output = generate(CPP_EXAMPLE, opts, false).unwrap();
88 let output = std::str::from_utf8(&output).unwrap();
89 // To avoid continual breakage we won't test every byte.
90 // Let's look for the major features.
91 assert!(output.contains("void cxxbridge03$do_cpp_thing(::rust::Str::Repr foo)"));
92 }
93
94 #[test]
95 fn test_annotation() {
96 let opts = Opt {
97 include: Vec::new(),
98 cxx_impl_annotations: Some("ANNOTATION".to_string()),
99 };
100 let output = generate(CPP_EXAMPLE, opts, false).unwrap();
101 let output = std::str::from_utf8(&output).unwrap();
102 assert!(output.contains("ANNOTATION void cxxbridge03$do_cpp_thing(::rust::Str::Repr foo)"));
103 }
104}