Alex Crichton | 8e5f0cd | 2015-09-09 22:46:19 -0700 | [diff] [blame^] | 1 | #![allow(unused_must_use)] |
| 2 | |
| 3 | extern crate gcc; |
| 4 | extern crate syntex_syntax as syntax; |
| 5 | |
| 6 | use std::env; |
| 7 | use std::fs::File; |
| 8 | use std::io::BufWriter; |
| 9 | use std::io::prelude::*; |
| 10 | use std::path::{Path, PathBuf}; |
| 11 | |
| 12 | use syntax::ast; |
| 13 | use syntax::parse::token::InternedString; |
| 14 | use syntax::attr; |
| 15 | use syntax::parse::{self, ParseSess}; |
| 16 | use syntax::visit::{self, Visitor}; |
| 17 | |
| 18 | struct TestGenerator { |
| 19 | rust: Box<Write>, |
| 20 | c: Box<Write>, |
| 21 | } |
| 22 | |
| 23 | fn main() { |
| 24 | let sess = ParseSess::new(); |
| 25 | |
| 26 | let src = Path::new("../src/lib.rs"); |
| 27 | let cfg = Vec::new(); |
| 28 | let mut krate = parse::parse_crate_from_file(src, cfg, &sess); |
| 29 | build_cfg(&mut krate.config); |
| 30 | |
| 31 | let mut gated_cfgs = Vec::new(); |
| 32 | let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic, |
| 33 | krate, |
| 34 | &mut gated_cfgs); |
| 35 | |
| 36 | let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| 37 | let rust_out = BufWriter::new(File::create(out.join("all.rs")).unwrap()); |
| 38 | let mut c_out = BufWriter::new(File::create(out.join("all.c")).unwrap()); |
| 39 | |
| 40 | writeln!(c_out, " |
| 41 | #include <netinet/in.h> |
| 42 | #include <netinet/ip.h> |
| 43 | #include <signal.h> |
| 44 | #include <stdint.h> |
| 45 | #include <sys/types.h> |
| 46 | #include <time.h> |
| 47 | "); |
| 48 | |
| 49 | visit::walk_crate(&mut TestGenerator { |
| 50 | rust: Box::new(rust_out), |
| 51 | c: Box::new(c_out), |
| 52 | }, &krate); |
| 53 | |
| 54 | gcc::Config::new() |
| 55 | .file(out.join("all.c")) |
| 56 | .compile("liball.a"); |
| 57 | } |
| 58 | |
| 59 | fn build_cfg(cfg: &mut ast::CrateConfig) { |
| 60 | let target = env::var("TARGET").unwrap(); |
| 61 | |
| 62 | let (arch, target_pointer_width) = if target.starts_with("x86_64") { |
| 63 | ("x86_64", "64") |
| 64 | } else if target.starts_with("i686") { |
| 65 | ("x86", "32") |
| 66 | } else { |
| 67 | panic!("unknown arch/pointer width: {}", target) |
| 68 | }; |
| 69 | let (os, family, env) = if target.contains("unknown-linux") { |
| 70 | ("linux", "unix", "gnu") |
| 71 | } else { |
| 72 | panic!("unknown os/family width: {}", target) |
| 73 | }; |
| 74 | |
| 75 | let mk = attr::mk_name_value_item_str; |
| 76 | let s = InternedString::new; |
| 77 | cfg.push(attr::mk_word_item(s(family))); |
| 78 | cfg.push(mk(s("target_os"), s(os))); |
| 79 | cfg.push(mk(s("target_family"), s(family))); |
| 80 | cfg.push(mk(s("target_arch"), s(arch))); |
| 81 | // skip endianness |
| 82 | cfg.push(mk(s("target_pointer_width"), s(target_pointer_width))); |
| 83 | cfg.push(mk(s("target_env"), s(env))); |
| 84 | } |
| 85 | |
| 86 | impl TestGenerator { |
| 87 | fn typedef(&mut self, ty: &str) { |
| 88 | let cty = if ty.starts_with("c_") { |
| 89 | let rest = ty[2..].replace("long", " long"); |
| 90 | if rest.starts_with("u") { |
| 91 | format!("unsigned {}", &rest[1..]) |
| 92 | } else { |
| 93 | rest |
| 94 | } |
| 95 | } else { |
| 96 | (match ty { |
| 97 | ty => ty, |
| 98 | }).to_string() |
| 99 | }; |
| 100 | writeln!(self.c, r#" |
| 101 | uint64_t ty_{ty}_size() {{ |
| 102 | return sizeof({cty}); |
| 103 | }} |
| 104 | "#, ty = ty, cty = cty); |
| 105 | writeln!(self.rust, r#" |
| 106 | #[test] |
| 107 | fn test_{ty}_size() {{ |
| 108 | extern {{ fn ty_{ty}_size() -> u64; }} |
| 109 | assert_eq!(mem::size_of::<libc::{ty}>() as u64, |
| 110 | unsafe {{ ty_{ty}_size() }}); |
| 111 | }} |
| 112 | "#, ty = ty); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | impl<'v> Visitor<'v> for TestGenerator { |
| 117 | fn visit_item(&mut self, i: &'v ast::Item) { |
| 118 | match i.node { |
| 119 | ast::ItemTy(_, ref generics) => { |
| 120 | assert!(generics.lifetimes.len() == 0); |
| 121 | assert!(generics.ty_params.len() == 0); |
| 122 | assert!(generics.where_clause.predicates.len() == 0); |
| 123 | self.typedef(&i.ident.to_string()); |
| 124 | } |
| 125 | |
| 126 | _ => {} |
| 127 | } |
| 128 | visit::walk_item(self, i) |
| 129 | } |
| 130 | } |