Windows 32-bit fixes
This commit is contained in:
parent
dc376401f6
commit
31504843db
|
@ -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)",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(_, _) => {
|
||||
}
|
||||
|
|
41
src/lib.rs
41
src/lib.rs
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue