blob: bcdb412c2abec27f4fe9e5d5d291888eb0ee24fa [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;
Alex Crichtona9adfbf2015-09-09 23:21:27 -070013use syntax::diagnostic::SpanHandler;
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070014use syntax::parse::token::InternedString;
Alex Crichtona9adfbf2015-09-09 23:21:27 -070015use syntax::attr::{self, ReprAttr};
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070016use syntax::parse::{self, ParseSess};
17use syntax::visit::{self, Visitor};
18
Alex Crichtona9adfbf2015-09-09 23:21:27 -070019struct TestGenerator<'a> {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070020 rust: Box<Write>,
21 c: Box<Write>,
Alex Crichtona9adfbf2015-09-09 23:21:27 -070022 sh: &'a SpanHandler,
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070023}
24
25fn main() {
Alex Crichton16083062015-09-09 22:59:24 -070026 let target = env::var("TARGET").unwrap();
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070027
Alex Crichton16083062015-09-09 22:59:24 -070028 let sess = ParseSess::new();
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070029 let src = Path::new("../src/lib.rs");
30 let cfg = Vec::new();
31 let mut krate = parse::parse_crate_from_file(src, cfg, &sess);
Alex Crichton16083062015-09-09 22:59:24 -070032 build_cfg(&mut krate.config, &target);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070033
34 let mut gated_cfgs = Vec::new();
35 let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
36 krate,
37 &mut gated_cfgs);
38
39 let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
40 let rust_out = BufWriter::new(File::create(out.join("all.rs")).unwrap());
41 let mut c_out = BufWriter::new(File::create(out.join("all.c")).unwrap());
42
43 writeln!(c_out, "
Alex Crichtona9adfbf2015-09-09 23:21:27 -070044#include <glob.h>
45#include <ifaddrs.h>
46#include <netdb.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070047#include <netinet/in.h>
48#include <netinet/ip.h>
Alex Crichtona9adfbf2015-09-09 23:21:27 -070049#include <pthread.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070050#include <signal.h>
Alex Crichton16083062015-09-09 22:59:24 -070051#include <stdalign.h>
52#include <stddef.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070053#include <stdint.h>
Alex Crichton16083062015-09-09 22:59:24 -070054#include <sys/resource.h>
Alex Crichtona9adfbf2015-09-09 23:21:27 -070055#include <sys/socket.h>
56#include <sys/stat.h>
57#include <sys/time.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070058#include <sys/types.h>
Alex Crichtona9adfbf2015-09-09 23:21:27 -070059#include <sys/un.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070060#include <time.h>
Alex Crichtona9adfbf2015-09-09 23:21:27 -070061#include <utime.h>
Alex Crichton16083062015-09-09 22:59:24 -070062#include <wchar.h>
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070063");
64
Alex Crichton16083062015-09-09 22:59:24 -070065 if target.contains("apple-darwin") {
66 writeln!(c_out, "
67#include <mach/mach_time.h>
68");
69 }
70
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070071 visit::walk_crate(&mut TestGenerator {
72 rust: Box::new(rust_out),
73 c: Box::new(c_out),
Alex Crichtona9adfbf2015-09-09 23:21:27 -070074 sh: &sess.span_diagnostic,
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070075 }, &krate);
76
77 gcc::Config::new()
78 .file(out.join("all.c"))
79 .compile("liball.a");
80}
81
Alex Crichton16083062015-09-09 22:59:24 -070082fn build_cfg(cfg: &mut ast::CrateConfig, target: &str) {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070083 let (arch, target_pointer_width) = if target.starts_with("x86_64") {
84 ("x86_64", "64")
85 } else if target.starts_with("i686") {
86 ("x86", "32")
87 } else {
88 panic!("unknown arch/pointer width: {}", target)
89 };
90 let (os, family, env) = if target.contains("unknown-linux") {
91 ("linux", "unix", "gnu")
Alex Crichton16083062015-09-09 22:59:24 -070092 } else if target.contains("apple-darwin") {
93 ("macos", "unix", "")
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070094 } else {
95 panic!("unknown os/family width: {}", target)
96 };
97
98 let mk = attr::mk_name_value_item_str;
99 let s = InternedString::new;
100 cfg.push(attr::mk_word_item(s(family)));
101 cfg.push(mk(s("target_os"), s(os)));
102 cfg.push(mk(s("target_family"), s(family)));
103 cfg.push(mk(s("target_arch"), s(arch)));
104 // skip endianness
105 cfg.push(mk(s("target_pointer_width"), s(target_pointer_width)));
106 cfg.push(mk(s("target_env"), s(env)));
107}
108
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700109impl<'a> TestGenerator<'a> {
110 fn test_type(&mut self, ty: &str) {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700111 let cty = if ty.starts_with("c_") {
112 let rest = ty[2..].replace("long", " long");
113 if rest.starts_with("u") {
114 format!("unsigned {}", &rest[1..])
Alex Crichton16083062015-09-09 22:59:24 -0700115 } else if rest.starts_with("s") && rest != "short" {
116 format!("signed {}", &rest[1..])
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700117 } else {
118 rest
119 }
120 } else {
121 (match ty {
Alex Crichton16083062015-09-09 22:59:24 -0700122 "sighandler_t" => return,
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700123 ty => ty,
124 }).to_string()
125 };
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700126 self.test_size_align(ty, &cty);
127 }
Alex Crichton16083062015-09-09 22:59:24 -0700128
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700129 fn test_struct(&mut self, ty: &str, _s: &ast::StructDef) {
130 let cty = if ty.starts_with("pthread") || ty == "glob_t" {
131 ty.to_string()
132 } else if ty == "ip6_mreq" {
133 "struct ipv6_mreq".to_string()
134 } else {
135 format!("struct {}", ty)
136 };
137 self.test_size_align(ty, &cty);
138 }
139
140 fn test_size_align(&mut self, rust: &str, c: &str) {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700141 writeln!(self.c, r#"
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700142 uint64_t __test_size_{ty}() {{ return sizeof({cty}); }}
143 uint64_t __test_align_{ty}() {{ return alignof({cty}); }}
144 "#, ty = rust, cty = c);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700145 writeln!(self.rust, r#"
146 #[test]
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700147 fn size_align_{ty}() {{
Alex Crichton16083062015-09-09 22:59:24 -0700148 extern {{
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700149 fn __test_size_{ty}() -> u64;
150 fn __test_align_{ty}() -> u64;
Alex Crichton16083062015-09-09 22:59:24 -0700151 }}
152 unsafe {{
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700153 let a = mem::size_of::<{ty}>() as u64;
154 let b = __test_size_{ty}();
155 assert!(a == b, "bad size: rust {{}} != c {{}}", a, b);
156 let a = mem::align_of::<{ty}>() as u64;
157 let b = __test_align_{ty}();
158 assert!(a == b, "bad align: rust {{}} != c {{}}", a, b);
Alex Crichton16083062015-09-09 22:59:24 -0700159 }}
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700160 }}
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700161 "#, ty = rust);
162 }
163
164 fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
165 assert!(generics.lifetimes.len() == 0);
166 assert!(generics.ty_params.len() == 0);
167 assert!(generics.where_clause.predicates.len() == 0);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700168 }
169}
170
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700171impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700172 fn visit_item(&mut self, i: &'v ast::Item) {
173 match i.node {
174 ast::ItemTy(_, ref generics) => {
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700175 self.assert_no_generics(i, generics);
176 self.test_type(&i.ident.to_string());
177 }
178
179 ast::ItemStruct(ref s, ref generics) => {
180 self.assert_no_generics(i, generics);
181 let is_c = i.attrs.iter().any(|a| {
182 attr::find_repr_attrs(self.sh, a).iter().any(|a| {
183 *a == ReprAttr::ReprExtern
184 })
185 });
186 if !is_c {
187 panic!("{} is not marked #[repr(C)]", i.ident);
188 }
189 self.test_struct(&i.ident.to_string(), s);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700190 }
191
192 _ => {}
193 }
194 visit::walk_item(self, i)
195 }
196}