print_cxx_include_dirs/
lib.rs

1// build.rs:
2// #![no_main] extern crate print_cxx_include_dirs;
3//
4// main.rs:
5// include!(env!("PRINT_CXX_INCLUDE_DIRS"));
6
7use std::env::{self, ArgsOs};
8use std::fs::{self, File};
9use std::io::{self, ErrorKind, Write};
10use std::os::raw::c_int;
11use std::panic;
12use std::path::Path;
13
14#[no_mangle]
15pub extern "C" fn main() -> c_int {
16    panic::catch_unwind(do_main).unwrap_or(1)
17}
18
19fn do_main() -> c_int {
20    let out_dir = env::var_os("OUT_DIR").unwrap();
21    let out_dir = Path::new(&out_dir);
22    let args_os = env::args_os();
23    match if args_os.len() <= 1 {
24        do_compile(out_dir)
25    } else {
26        do_print(out_dir, args_os)
27    } {
28        Ok(()) => 0,
29        Err(err) => {
30            let _ = writeln!(io::stderr(), "{}", err);
31            1
32        }
33    }
34}
35
36fn do_compile(out_dir: &Path) -> io::Result<()> {
37    let include_dirs = out_dir.join("include-dirs");
38    if let Err(err) = fs::remove_file(include_dirs) {
39        if err.kind() != ErrorKind::NotFound {
40            return Err(err);
41        }
42    }
43
44    let current_exe = env::current_exe()?;
45
46    let bridge_rs = out_dir.join("bridge.rs");
47    fs::write(&bridge_rs, "#[cxx::bridge] mod ffi {}")?;
48    cxx_build::bridge(&bridge_rs)
49        .compiler(&current_exe)
50        .archiver(&current_exe)
51        .cargo_metadata(false)
52        .compile("unused");
53
54    Ok(())
55}
56
57fn do_print(out_dir: &Path, mut args_os: ArgsOs) -> io::Result<()> {
58    let include_dirs = out_dir.join("include-dirs");
59    let mut file = match File::options()
60        .read(true)
61        .write(true)
62        .create_new(true)
63        .open(include_dirs)
64    {
65        Ok(file) => file,
66        Err(err) if err.kind() == ErrorKind::AlreadyExists => return Ok(()),
67        Err(err) => return Err(err),
68    };
69
70    while let Some(arg) = args_os.next() {
71        if arg == "-I" {
72            let include_dir = args_os.next().unwrap();
73            let include_dir = Path::new(&include_dir);
74            if !include_dir.starts_with(out_dir) {
75                let include_dir = include_dir.to_str().unwrap();
76                assert!(!include_dir.contains('\n'));
77                writeln!(file, "{}", include_dir)?;
78            }
79        }
80    }
81
82    let main_rs = out_dir.join("main.rs");
83    fs::write(&main_rs, MAIN_RS)?;
84
85    writeln!(
86        io::stdout(),
87        "cargo:rustc-env=PRINT_CXX_INCLUDE_DIRS={}",
88        main_rs.to_str().unwrap(),
89    )
90}
91
92const MAIN_RS: &str = "\
93fn main() {
94    let _ = std::io::Write::write_all(
95        &mut std::io::stdout(),
96        include_bytes!(concat!(env!(\"OUT_DIR\"), \"/include-dirs\")),
97    );
98}
99";