blob: cabe2b11421d44c976ecd4ba5fb9a76c94698645 [file] [log] [blame]
David Tolnayf8ed0732020-04-29 12:34:47 -07001//! The CXX code generator for constructing and compiling C++ code.
2//!
3//! This is intended to be used from Cargo build scripts to execute CXX's
4//! C++ code generator, set up any additional compiler flags depending on
5//! the use case, and make the C++ compiler invocation.
6//!
7//! <br>
8//!
9//! # Example
10//!
11//! Example of a canonical Cargo build script that builds a CXX bridge:
12//!
13//! ```no_run
14//! // build.rs
15//!
16//! fn main() {
17//! cxx_build::bridge("src/main.rs")
18//! .file("../demo-cxx/demo.cc")
19//! .flag("-std=c++11")
20//! .compile("cxxbridge-demo");
21//!
22//! println!("cargo:rerun-if-changed=src/main.rs");
23//! println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
24//! println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
25//! }
26//! ```
27//!
28//! A runnable working setup with this build script is shown in the
29//! *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
30//!
31//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
32//!
33//! <br>
34//!
35//! # Alternatives
36//!
37//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
38//! alternate way of invoking the C++ code generator as a standalone command
39//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
40//!
41//! ```bash
42//! $ cargo install cxxbridge-cmd # or build it from the repo
43//!
44//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
45//! $ cxxbridge src/main.rs > path/to/mybridge.cc
46//! ```
47
David Tolnaydb450b02020-05-05 10:16:57 -070048#![allow(
49 clippy::inherent_to_string,
50 clippy::needless_doctest_main,
51 clippy::new_without_default,
52 clippy::toplevel_ref_arg
53)]
54
David Tolnayf8ed0732020-04-29 12:34:47 -070055mod error;
56mod gen;
57mod paths;
58mod syntax;
59
60use crate::error::Result;
61use crate::gen::Opt;
62use anyhow::anyhow;
63use std::fs;
64use std::io::{self, Write};
65use std::path::Path;
66use std::process;
67
68/// This returns a [`cc::Build`] on which you should continue to set up any
69/// additional source files or compiler flags, and lastly call its [`compile`]
70/// method to execute the C++ build.
71///
72/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
73#[must_use]
74pub fn bridge(rust_source_file: impl AsRef<Path>) -> cc::Build {
75 match try_generate_bridge(rust_source_file.as_ref()) {
76 Ok(build) => build,
77 Err(err) => {
78 let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
79 process::exit(1);
80 }
81 }
82}
83
84fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
85 let header = gen::do_generate_header(rust_source_file, Opt::default());
86 let header_path = paths::out_with_extension(rust_source_file, ".h")?;
87 fs::create_dir_all(header_path.parent().unwrap())?;
88 fs::write(&header_path, header)?;
89 paths::symlink_header(&header_path, rust_source_file);
90
91 let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
92 let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
93 fs::write(&bridge_path, bridge)?;
94 let mut build = paths::cc_build();
95 build.file(&bridge_path);
96
97 let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
98 let _ = fs::create_dir_all(cxx_h.parent().unwrap());
99 let _ = fs::remove_file(cxx_h);
100 let _ = fs::write(cxx_h, gen::include::HEADER);
101
102 Ok(build)
103}