blob: 556e7575a7b08580875627bdcf8c8faf7cc8e595 [file] [log] [blame]
Alex Crichton8e5f0cd2015-09-09 22:46:19 -07001#![allow(unused_must_use)]
2
3extern crate gcc;
4extern crate syntex_syntax as syntax;
5
6use std::env;
7use std::fs::File;
8use std::io::BufWriter;
9use std::io::prelude::*;
10use std::path::{Path, PathBuf};
11
12use syntax::ast;
13use syntax::parse::token::InternedString;
14use syntax::attr;
15use syntax::parse::{self, ParseSess};
16use syntax::visit::{self, Visitor};
17
18struct TestGenerator {
19 rust: Box<Write>,
20 c: Box<Write>,
21}
22
23fn 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
59fn 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
86impl 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
116impl<'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}