Split cxx runtime and build components
diff --git a/src/error.rs b/src/error.rs
deleted file mode 100644
index 740ab94..0000000
--- a/src/error.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::error::Error as StdError;
-use std::fmt::{self, Display};
-use std::io;
-
-pub(super) type Result<T, E = Error> = std::result::Result<T, E>;
-
-#[derive(Debug)]
-pub(super) enum Error {
-    MissingOutDir,
-    TargetDir,
-    Io(io::Error),
-}
-
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Error::MissingOutDir => write!(f, "missing OUT_DIR environment variable"),
-            Error::TargetDir => write!(f, "failed to locate target dir"),
-            Error::Io(err) => err.fmt(f),
-        }
-    }
-}
-
-impl StdError for Error {
-    fn source(&self) -> Option<&(dyn StdError + 'static)> {
-        match self {
-            Error::Io(err) => Some(err),
-            _ => None,
-        }
-    }
-}
-
-impl From<io::Error> for Error {
-    fn from(err: io::Error) -> Self {
-        Error::Io(err)
-    }
-}
diff --git a/src/gen b/src/gen
deleted file mode 120000
index 334e0fb..0000000
--- a/src/gen
+++ /dev/null
@@ -1 +0,0 @@
-../gen
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index cff1e88..7e8e9ec 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -224,8 +224,7 @@
 //! // build.rs
 //!
 //! fn main() {
-//!     cxx::Build::new()
-//!         .bridge("src/main.rs")  // returns a cc::Build
+//!     cxx_build::bridge("src/main.rs")  // returns a cc::Build
 //!         .file("../demo-cxx/demo.cc")
 //!         .flag("-std=c++11")
 //!         .compile("cxxbridge-demo");
@@ -363,18 +362,14 @@
 
 mod cxx_string;
 mod cxx_vector;
-mod error;
 mod exception;
 mod function;
-mod gen;
 mod opaque;
-mod paths;
 mod result;
 mod rust_sliceu8;
 mod rust_str;
 mod rust_string;
 mod rust_vec;
-mod syntax;
 mod unique_ptr;
 mod unwind;
 
@@ -398,107 +393,3 @@
     pub use crate::unique_ptr::UniquePtrTarget;
     pub use crate::unwind::catch_unwind;
 }
-
-use crate::error::Result;
-use crate::gen::Opt;
-use anyhow::anyhow;
-use std::fs;
-use std::io::{self, Write};
-use std::path::Path;
-use std::process;
-
-/// The CXX code generator for constructing and compiling C++ code.
-///
-/// This is intended to be used from Cargo build scripts to execute CXX's
-/// C++ code generator, set up any additional compiler flags depending on
-/// the use case, and make the C++ compiler invocation.
-///
-/// <br>
-///
-/// # Example
-///
-/// Example of a canonical Cargo build script that builds a CXX bridge:
-///
-/// ```no_run
-/// // build.rs
-///
-/// fn main() {
-///     cxx::Build::new()
-///         .bridge("src/main.rs")
-///         .file("../demo-cxx/demo.cc")
-///         .flag("-std=c++11")
-///         .compile("cxxbridge-demo");
-///
-///     println!("cargo:rerun-if-changed=src/main.rs");
-///     println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
-///     println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
-/// }
-/// ```
-///
-/// A runnable working setup with this build script is shown in the
-/// *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
-///
-/// [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
-///
-/// <br>
-///
-/// # Alternatives
-///
-/// For use in non-Cargo builds like Bazel or Buck, CXX provides an
-/// alternate way of invoking the C++ code generator as a standalone command
-/// line tool. The tool is packaged as the `cxxbridge-cmd` crate.
-///
-/// ```bash
-/// $ cargo install cxxbridge-cmd  # or build it from the repo
-///
-/// $ cxxbridge src/main.rs --header > path/to/mybridge.h
-/// $ cxxbridge src/main.rs > path/to/mybridge.cc
-/// ```
-#[must_use]
-pub struct Build {
-    _private: (),
-}
-
-impl Build {
-    /// Begin with a [`cc::Build`] in its default configuration.
-    pub fn new() -> Self {
-        Build { _private: () }
-    }
-
-    /// This returns a [`cc::Build`] on which you should continue to set up
-    /// any additional source files or compiler flags, and lastly call its
-    /// [`compile`] method to execute the C++ build.
-    ///
-    /// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
-    #[must_use]
-    pub fn bridge(&self, rust_source_file: impl AsRef<Path>) -> cc::Build {
-        match try_generate_bridge(rust_source_file.as_ref()) {
-            Ok(build) => build,
-            Err(err) => {
-                let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
-                process::exit(1);
-            }
-        }
-    }
-}
-
-fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
-    let header = gen::do_generate_header(rust_source_file, Opt::default());
-    let header_path = paths::out_with_extension(rust_source_file, ".h")?;
-    fs::create_dir_all(header_path.parent().unwrap())?;
-    fs::write(&header_path, header)?;
-    paths::symlink_header(&header_path, rust_source_file);
-
-    let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
-    let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
-    fs::write(&bridge_path, bridge)?;
-    let mut build = paths::cc_build();
-    build.file(&bridge_path);
-
-    let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
-    let _ = fs::create_dir_all(cxx_h.parent().unwrap());
-    let _ = fs::remove_file(cxx_h);
-    let _ = fs::write(cxx_h, gen::include::HEADER);
-
-    Ok(build)
-}
diff --git a/src/paths.rs b/src/paths.rs
deleted file mode 100644
index ca183d9..0000000
--- a/src/paths.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-use crate::error::{Error, Result};
-use std::env;
-use std::fs;
-use std::path::{Path, PathBuf};
-
-fn out_dir() -> Result<PathBuf> {
-    env::var_os("OUT_DIR")
-        .map(PathBuf::from)
-        .ok_or(Error::MissingOutDir)
-}
-
-pub(crate) fn cc_build() -> cc::Build {
-    try_cc_build().unwrap_or_default()
-}
-
-fn try_cc_build() -> Result<cc::Build> {
-    let mut build = cc::Build::new();
-    build.include(include_dir()?);
-    build.include(target_dir()?.parent().unwrap());
-    Ok(build)
-}
-
-// Symlink the header file into a predictable place. The header generated from
-// path/to/mod.rs gets linked to targets/cxxbridge/path/to/mod.rs.h.
-pub(crate) fn symlink_header(path: &Path, original: &Path) {
-    let _ = try_symlink_header(path, original);
-}
-
-fn try_symlink_header(path: &Path, original: &Path) -> Result<()> {
-    let suffix = relative_to_parent_of_target_dir(original)?;
-    let ref dst = include_dir()?.join(suffix);
-
-    fs::create_dir_all(dst.parent().unwrap())?;
-    let _ = fs::remove_file(dst);
-    symlink_or_copy(path, dst)?;
-
-    let mut file_name = dst.file_name().unwrap().to_os_string();
-    file_name.push(".h");
-    let ref dst2 = dst.with_file_name(file_name);
-    symlink_or_copy(path, dst2)?;
-
-    Ok(())
-}
-
-fn relative_to_parent_of_target_dir(original: &Path) -> Result<PathBuf> {
-    let target_dir = target_dir()?;
-    let mut outer = target_dir.parent().unwrap();
-    let original = canonicalize(original)?;
-    loop {
-        if let Ok(suffix) = original.strip_prefix(outer) {
-            return Ok(suffix.to_owned());
-        }
-        match outer.parent() {
-            Some(parent) => outer = parent,
-            None => return Ok(original.components().skip(1).collect()),
-        }
-    }
-}
-
-pub(crate) fn out_with_extension(path: &Path, ext: &str) -> Result<PathBuf> {
-    let mut file_name = path.file_name().unwrap().to_owned();
-    file_name.push(ext);
-
-    let out_dir = out_dir()?;
-    let rel = relative_to_parent_of_target_dir(path)?;
-    Ok(out_dir.join(rel).with_file_name(file_name))
-}
-
-pub(crate) fn include_dir() -> Result<PathBuf> {
-    let target_dir = target_dir()?;
-    Ok(target_dir.join("cxxbridge"))
-}
-
-fn target_dir() -> Result<PathBuf> {
-    let mut dir = out_dir().and_then(canonicalize)?;
-    loop {
-        if dir.ends_with("target") {
-            return Ok(dir);
-        }
-        if !dir.pop() {
-            return Err(Error::TargetDir);
-        }
-    }
-}
-
-#[cfg(not(windows))]
-fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
-    Ok(fs::canonicalize(path)?)
-}
-
-#[cfg(windows)]
-fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
-    // Real fs::canonicalize on Windows produces UNC paths which cl.exe is
-    // unable to handle in includes. Use a poor approximation instead.
-    // https://github.com/rust-lang/rust/issues/42869
-    // https://github.com/alexcrichton/cc-rs/issues/169
-    Ok(env::current_dir()?.join(path))
-}
-
-#[cfg(unix)]
-use std::os::unix::fs::symlink as symlink_or_copy;
-
-#[cfg(windows)]
-fn symlink_or_copy(src: &Path, dst: &Path) -> Result<()> {
-    use std::os::windows::fs::symlink_file;
-
-    // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
-    // require Developer Mode. If it fails, fall back to copying the file.
-    if symlink_file(src, dst).is_err() {
-        fs::copy(src, dst)?;
-    }
-    Ok(())
-}
-
-#[cfg(not(any(unix, windows)))]
-use std::fs::copy as symlink_or_copy;
diff --git a/src/syntax b/src/syntax
deleted file mode 120000
index f400712..0000000
--- a/src/syntax
+++ /dev/null
@@ -1 +0,0 @@
-../syntax
\ No newline at end of file