blob: dda79a4b225717da52146be0646dcab474dc005e [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_") {
Alex Crichton3e5155b2015-09-09 23:46:19 -0700112 match &ty[2..].replace("long", " long")[..] {
113 s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
114 "short" => format!("short"),
115 s if s.starts_with("s") => format!("signed {}", &s[1..]),
116 s => s.to_string(),
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700117 }
118 } else {
119 (match ty {
Alex Crichton16083062015-09-09 22:59:24 -0700120 "sighandler_t" => return,
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700121 ty => ty,
122 }).to_string()
123 };
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700124 self.test_size_align(ty, &cty);
125 }
Alex Crichton16083062015-09-09 22:59:24 -0700126
Alex Crichton3e5155b2015-09-09 23:46:19 -0700127 fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
128 let cty = match ty {
129 t if ty.starts_with("pthread") => t.to_string(),
130 "glob_t" => "glob_t".to_string(),
131 "ip6_mreq" => "struct ipv6_mreq".to_string(),
132 s => format!("struct {}", s),
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700133 };
134 self.test_size_align(ty, &cty);
Alex Crichton3e5155b2015-09-09 23:46:19 -0700135
136 writeln!(self.rust, r#"
137 #[test]
138 fn field_offset_size_{ty}() {{
139 "#, ty = ty);
140 for field in s.fields.iter() {
141 let name = match field.node.kind {
142 ast::NamedField(name, ast::Public) => name,
143 ast::NamedField(_, ast::Inherited) => continue,
144 ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
145 };
146
147 let cname = match &name.to_string()[..] {
148 s if s.ends_with("_nsec") && ty == "stat" => {
149 s.replace("_nsec", "spec.tv_nsec")
150 }
151 s => s.to_string(),
152 };
153
154 writeln!(self.c, r#"
155 uint64_t __test_offset_{ty}_{rust_field}() {{
156 return offsetof({cty}, {c_field});
157 }}
158 uint64_t __test_size_{ty}_{rust_field}() {{
159 {cty}* foo = NULL;
160 return sizeof(foo->{c_field});
161 }}
162 "#, ty = ty, cty = cty, rust_field = name, c_field = cname);
163 writeln!(self.rust, r#"
164 extern {{
165 fn __test_offset_{ty}_{field}() -> u64;
166 fn __test_size_{ty}_{field}() -> u64;
167 }}
168 unsafe {{
169 let foo = 0 as *const {ty};
170 same(offset_of!({ty}, {field}),
171 __test_offset_{ty}_{field}(),
172 "field offset {field} of {ty}");
173 same(mem::size_of_val(&(*foo).{field}) as u64,
174 __test_size_{ty}_{field}(),
175 "field size {field} of {ty}");
176 }}
177 "#, ty = ty, field = name);
178 }
179 writeln!(self.rust, r#"
180 }}
181 "#);
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700182 }
183
184 fn test_size_align(&mut self, rust: &str, c: &str) {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700185 writeln!(self.c, r#"
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700186 uint64_t __test_size_{ty}() {{ return sizeof({cty}); }}
187 uint64_t __test_align_{ty}() {{ return alignof({cty}); }}
188 "#, ty = rust, cty = c);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700189 writeln!(self.rust, r#"
190 #[test]
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700191 fn size_align_{ty}() {{
Alex Crichton16083062015-09-09 22:59:24 -0700192 extern {{
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700193 fn __test_size_{ty}() -> u64;
194 fn __test_align_{ty}() -> u64;
Alex Crichton16083062015-09-09 22:59:24 -0700195 }}
196 unsafe {{
Alex Crichton3e5155b2015-09-09 23:46:19 -0700197 same(mem::size_of::<{ty}>() as u64,
198 __test_size_{ty}(), "size");
199 same(mem::align_of::<{ty}>() as u64,
200 __test_align_{ty}(), "align");
Alex Crichton16083062015-09-09 22:59:24 -0700201 }}
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700202 }}
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700203 "#, ty = rust);
204 }
205
206 fn assert_no_generics(&self, _i: &ast::Item, generics: &ast::Generics) {
207 assert!(generics.lifetimes.len() == 0);
208 assert!(generics.ty_params.len() == 0);
209 assert!(generics.where_clause.predicates.len() == 0);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700210 }
211}
212
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700213impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700214 fn visit_item(&mut self, i: &'v ast::Item) {
215 match i.node {
216 ast::ItemTy(_, ref generics) => {
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700217 self.assert_no_generics(i, generics);
218 self.test_type(&i.ident.to_string());
219 }
220
221 ast::ItemStruct(ref s, ref generics) => {
222 self.assert_no_generics(i, generics);
223 let is_c = i.attrs.iter().any(|a| {
224 attr::find_repr_attrs(self.sh, a).iter().any(|a| {
225 *a == ReprAttr::ReprExtern
226 })
227 });
228 if !is_c {
229 panic!("{} is not marked #[repr(C)]", i.ident);
230 }
231 self.test_struct(&i.ident.to_string(), s);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700232 }
233
234 _ => {}
235 }
236 visit::walk_item(self, i)
237 }
238}