Windows 32-bit fixes

This commit is contained in:
Alex Crichton 2015-09-10 23:43:41 -07:00
parent dc376401f6
commit 31504843db
5 changed files with 180 additions and 25 deletions

4
libc-test/Cargo.lock generated
View File

@ -2,7 +2,7 @@
name = "libc-test"
version = "0.1.0"
dependencies = [
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (git+https://github.com/alexcrichton/gcc-rs)",
"libc 0.1.10",
"syntex_syntax 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/alexcrichton/gcc-rs#e429c775dcbb03eb049bcb7f7215cf8d9ee3b837"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -9,7 +9,7 @@ libc = { path = ".." }
[build-dependencies]
syntex_syntax = "0.13.0"
gcc = "0.3"
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
[lib]
name = "libc_test"

View File

@ -8,10 +8,13 @@ use std::io::BufWriter;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use syntax::abi::Abi;
use syntax::ast;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::InternedString;
use syntax::attr::{self, ReprAttr};
use syntax::diagnostic::SpanHandler;
use syntax::ext::base::SyntaxExtension;
use syntax::ext::expand;
use syntax::parse::token::{intern, InternedString};
use syntax::parse::{self, ParseSess};
use syntax::visit::{self, Visitor};
@ -28,6 +31,7 @@ struct TestGenerator<'a> {
c: Box<Write>,
sh: &'a SpanHandler,
structs: HashSet<String>,
abi: Abi,
}
struct StructFinder {
@ -37,12 +41,21 @@ struct StructFinder {
impl<'a> TestGenerator<'a> {
fn defines(&self) -> Vec<&'static str> {
let mut ret = Vec::new();
// Pull in extra goodies on linux
if self.target.contains("unknown-linux") {
ret.push("_GNU_SOURCE");
}
// MSVC doesn't have stdalign.h so get alignof ourselves
if self.target.contains("msvc") {
ret.push("alignof __alignof");
}
// Pull in extra goodies on mingw
if self.target.contains("windows") {
ret.push("_WIN32_WINNT 0x8000");
}
return ret
}
@ -82,6 +95,11 @@ impl<'a> TestGenerator<'a> {
base.push("windows.h");
base.push("process.h");
base.push("ws2ipdef.h");
if self.target.contains("gnu") {
base.push("stdalign.h");
base.push("ws2tcpip.h");
}
} else {
base.push("ctype.h");
base.push("dirent.h");
@ -123,13 +141,19 @@ impl<'a> TestGenerator<'a> {
s => s.to_string(),
}
}
// Perhaps this should be renamed in libc...
"ip6_mreq" => "struct ipv6_mreq".to_string(),
// Just pass all these through, no need for a "struct" prefix
"glob_t" |
"FILE" |
"DIR" |
"fpos_t" => ty.to_string(),
t if t.starts_with("pthread") => t.to_string(),
// Windows uppercase structs don't have `struct` in front, there's a
// few special cases for windows, and then otherwise put `struct` in
// front of everything.
t if self.structs.contains(t) => {
if windows && ty.chars().next().unwrap().is_uppercase() {
t.to_string()
@ -142,14 +166,18 @@ impl<'a> TestGenerator<'a> {
}
}
// Fixup a few types on windows that don't actually exist.
"time64_t" if windows => "__time64_t".to_string(),
"ssize_t" if windows => "SSIZE_T".to_string(),
t => t.to_string(),
}
}
fn rust2cfield(&self, struct_: &str, field: &str) -> String {
match field {
// Our stat *_nsec fields normally don't actually exist but are part
// of a timeval struct
s if s.ends_with("_nsec") && struct_ == "stat" => {
if self.target.contains("apple-darwin") {
s.replace("_nsec", "spec.tv_nsec")
@ -207,12 +235,21 @@ fn main() {
c: Box::new(c_out),
sh: &sess.span_diagnostic,
structs: HashSet::new(),
abi: Abi::C,
};
// Parse the libc crate
let src = Path::new("../src/lib.rs");
let cfg = Vec::new();
let mut krate = parse::parse_crate_from_file(src, cfg, &sess);
let krate = parse::parse_crate_from_file(src, cfg, &sess);
// expand macros
let ecfg = expand::ExpansionConfig::default("libc".to_string());
let exts = vec![
(intern("macro_rules"), SyntaxExtension::MacroRulesTT),
];
let mut krate = expand::expand_crate(&sess, ecfg, Vec::new(),
exts, &mut Vec::new(), krate);
// Strip the crate down to just what's configured for our target
for (k, v) in tg.cfg_list() {
@ -359,8 +396,22 @@ impl<'a> TestGenerator<'a> {
}
fn test_const(&mut self, name: &str, rust_ty: &str) {
let mingw = self.target.contains("windows-gnu");
// Apparently these don't exist in mingw headers?
match name {
"MEM_RESET_UNDO" |
"FILE_ATTRIBUTE_NO_SCRUB_DATA" |
"FILE_ATTRIBUTE_INTEGRITY_STREAM" |
"ERROR_NOTHING_TO_TERMINATE" if mingw => return,
_ => {}
}
let cty = self.rust_ty_to_c_ty(rust_ty);
// SIG_IGN has weird types on platforms, just worry about it as a size_t
let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
t!(writeln!(self.c, r#"
int __test_const_{name}({cty} *outptr) {{
*outptr = {cast}({name});
@ -387,7 +438,7 @@ impl<'a> TestGenerator<'a> {
fn test_extern_fn(&mut self, name: &str, cname: &str,
args: &[String], ret: &str,
variadic: bool) {
variadic: bool, abi: Abi) {
match name {
// manually verified
"execv" |
@ -408,11 +459,20 @@ impl<'a> TestGenerator<'a> {
.connect(", ") + if variadic {", ..."} else {""}
};
let cret = self.rust_ty_to_c_ty(ret);
let abi = match abi {
Abi::C => "",
Abi::Stdcall => "__stdcall ",
Abi::System if self.target.contains("i686-pc-windows") => {
"__stdcall "
}
Abi::System => "",
a => panic!("unknown ABI: {}", a),
};
t!(writeln!(self.c, r#"
{ret} (*__test_fn_{name}(void))({args}) {{
{ret} ({abi}*__test_fn_{name}(void))({args}) {{
return {cname};
}}
"#, name = name, cname = cname, args = args, ret = cret));
"#, name = name, cname = cname, args = args, ret = cret, abi = abi));
t!(writeln!(self.rust, r#"
#[test]
#[cfg_attr(windows, ignore)] // FIXME -- dllimport weirdness?
@ -473,6 +533,7 @@ impl<'a> TestGenerator<'a> {
impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
fn visit_item(&mut self, i: &'v ast::Item) {
let prev_abi = self.abi;
match i.node {
ast::ItemTy(_, ref generics) => {
self.assert_no_generics(i.ident, generics);
@ -497,9 +558,14 @@ impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
self.test_const(&i.ident.to_string(), &ty);
}
ast::ItemForeignMod(ref fm) => {
self.abi = fm.abi;
}
_ => {}
}
visit::walk_item(self, i)
visit::walk_item(self, i);
self.abi = prev_abi;
}
fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
@ -514,8 +580,9 @@ impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
}
_ => i.ident.to_string(),
};
let abi = self.abi;
self.test_extern_fn(&i.ident.to_string(), &cname, &args, &ret,
variadic);
variadic, abi);
}
ast::ForeignItemStatic(_, _) => {
}

View File

@ -67,6 +67,9 @@
#![allow(bad_style, raw_pointer_derive)]
#[macro_use]
mod macros;
// Explicit export lists for the intersection (provided here) mean that
// you can write more-platform-agnostic code if you stick to just these
// symbols.
@ -1829,10 +1832,13 @@ pub mod types {
pub type clock_t = i32;
#[cfg(target_arch = "x86")]
pub type time_t = i32;
#[cfg(target_arch = "x86_64")]
pub type time_t = i64;
cfg_if! {
if #[cfg(all(target_arch = "x86", target_env = "gnu"))] {
pub type time_t = i32;
} else {
pub type time_t = i64;
}
}
pub type wchar_t = u16;
}
@ -2508,8 +2514,6 @@ pub mod consts {
pub const BUFSIZ : c_uint = 512;
pub const FOPEN_MAX : c_uint = 20;
pub const FILENAME_MAX : c_uint = 260;
pub const L_tmpnam : c_uint = 260;
pub const TMP_MAX : c_uint = 0x7fff_ffff;
pub const WSAEINTR: c_int = 10004;
pub const WSAEBADF: c_int = 10009;
@ -2563,6 +2567,16 @@ pub mod consts {
pub const WSAEINVALIDPROCTABLE: c_int = 10104;
pub const WSAEINVALIDPROVIDER: c_int = 10105;
pub const WSAEPROVIDERFAILEDINIT: c_int = 10106;
cfg_if! {
if #[cfg(all(target_env = "gnu"))] {
pub const L_tmpnam : c_uint = 14;
pub const TMP_MAX : c_uint = 0x7fff;
} else {
pub const L_tmpnam : c_uint = 260;
pub const TMP_MAX : c_uint = 0x7fff_ffff;
}
}
}
pub mod c99 {
}
@ -6141,9 +6155,8 @@ pub mod funcs {
#[cfg(windows)]
pub mod bsd43 {
use types::common::c95::{c_void};
use types::os::common::bsd44::{sockaddr, SOCKET};
use types::os::arch::c95::c_int;
use types::os::arch::c95::{c_int, c_char};
extern "system" {
pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> SOCKET;
@ -6159,17 +6172,17 @@ pub mod funcs {
pub fn getsockname(socket: SOCKET, address: *mut sockaddr,
address_len: *mut c_int) -> c_int;
pub fn setsockopt(socket: SOCKET, level: c_int, name: c_int,
value: *const c_void,
value: *const c_char,
option_len: c_int) -> c_int;
pub fn closesocket(socket: SOCKET) -> c_int;
pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int,
pub fn recv(socket: SOCKET, buf: *mut c_char, len: c_int,
flags: c_int) -> c_int;
pub fn send(socket: SOCKET, buf: *const c_void, len: c_int,
pub fn send(socket: SOCKET, buf: *const c_char, len: c_int,
flags: c_int) -> c_int;
pub fn recvfrom(socket: SOCKET, buf: *mut c_void, len: c_int,
pub fn recvfrom(socket: SOCKET, buf: *mut c_char, len: c_int,
flags: c_int, addr: *mut sockaddr,
addrlen: *mut c_int) -> c_int;
pub fn sendto(socket: SOCKET, buf: *const c_void, len: c_int,
pub fn sendto(socket: SOCKET, buf: *const c_char, len: c_int,
flags: c_int, addr: *const sockaddr,
addrlen: c_int) -> c_int;
pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
@ -6414,7 +6427,7 @@ pub mod funcs {
lpNumberOfBytesRead: LPDWORD,
lpOverlapped: LPOVERLAPPED) -> BOOL;
pub fn WriteFile(hFile: HANDLE,
lpBuffer: LPVOID,
lpBuffer: LPCVOID,
nNumberOfBytesToWrite: DWORD,
lpNumberOfBytesWritten: LPDWORD,
lpOverlapped: LPOVERLAPPED) -> BOOL;

75
src/macros.rs Normal file
View File

@ -0,0 +1,75 @@
//! A macro for defining #[cfg] if-else statements.
//!
//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
//! emitting the implementation which matches first.
//!
//! This allows you to conveniently provide a long list #[cfg]'d blocks of code
//! without having to rewrite each clause multiple times.
macro_rules! cfg_if {
($(
if #[cfg($($meta:meta),*)] { $($it:item)* }
) else * else {
$($it2:item)*
}) => {
__cfg_if_items! {
() ;
$( ( ($($meta),*) ($($it)*) ), )*
( () ($($it2)*) ),
}
}
}
#[doc(hidden)]
macro_rules! __cfg_if_items {
(($($not:meta,)*) ; ) => {};
(($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
__cfg_if_apply! { cfg(all($($m,)* not(any($($not),*)))), $($it)* }
__cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
}
}
#[doc(hidden)]
macro_rules! __cfg_if_apply {
($m:meta, $($it:item)*) => {
$(#[$m] $it)*
}
}
#[cfg(test)]
mod tests {
cfg_if! {
if #[cfg(test)] {
use std::option::Option as Option2;
fn works1() -> Option2<u32> { Some(1) }
} else {
fn works1() -> Option<u32> { None }
}
}
cfg_if! {
if #[cfg(foo)] {
fn works2() -> bool { false }
} else if #[cfg(test)] {
fn works2() -> bool { true }
} else {
fn works2() -> bool { false }
}
}
cfg_if! {
if #[cfg(foo)] {
fn works3() -> bool { false }
} else {
fn works3() -> bool { true }
}
}
#[test]
fn it_works() {
assert!(works1().is_some());
assert!(works2());
assert!(works3());
}
}