Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ jobs:
# env: { ARCH_BITS: 32, ARCH: i686 }
- target: i686-pc-windows-msvc
os: windows-2025
env: { ARCH_BITS: 32, ARCH: i686 }
- target: i686-pc-windows-msvc
os: windows-2025
env: { ARCH_BITS: 32, ARCH: i686, RUST_LIBC_UNSTABLE_WINDOWS_TIME32: 1 }
artifact-tag: windows_time32
- target: i686-unknown-linux-gnu
- target: x86_64-pc-windows-gnu
os: windows-2025
Expand Down
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const ALLOWED_CFGS: &[&str] = &[
// Corresponds to `_REDIR_TIME64` in musl
"musl32_time64",
"vxworks_lt_25_09",
// Corresponds to `_USE_32BIT_TIME_T` in Windows CRT
"windows_use_time32",
];

// Extra values to allow for check-cfg.
Expand Down Expand Up @@ -123,6 +125,11 @@ fn main() {
}
}

let windows_use_time32 = env::var("RUST_LIBC_UNSTABLE_WINDOWS_TIME32").is_ok();
println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_WINDOWS_TIME32");
if windows_use_time32 {
set_cfg("windows_use_time32");
}
let linux_time_bits64 = env::var("RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64").is_ok();
println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64");
if linux_time_bits64 {
Expand Down
2 changes: 1 addition & 1 deletion ci/install-rust.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ if [ -n "${INSTALL_RUST_SRC:-}" ]; then
fi

if [ "$os" = "windows" ]; then
if [ "${ARCH_BITS:-}" = "i686" ]; then
if [ "${ARCH:-}" = "i686" ]; then
echo "Install MinGW32"
choco install mingw --x86 --force
fi
Expand Down
43 changes: 14 additions & 29 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,6 @@ fn test_cygwin(target: &str) {
fn test_windows(target: &str) {
assert!(target.contains("windows"));
let gnu = target.contains("gnu");
let i686 = target.contains("i686");

let mut cfg = ctest_cfg();

Expand All @@ -744,6 +743,11 @@ fn test_windows(target: &str) {
}
cfg.define("_WIN32_WINNT", Some("0x8000"));

if env::var("RUST_LIBC_UNSTABLE_WINDOWS_TIME32").is_ok() {
cfg.define("_USE_32BIT_TIME_T", None);
cfg.cfg("windows_use_time32", None);
}

headers!(
cfg,
"direct.h",
Expand Down Expand Up @@ -772,23 +776,18 @@ fn test_windows(target: &str) {
// Just pass all these through, no need for a "struct" prefix
"FILE" | "DIR" | "Dl_info" => ty.to_string().into(),
t if t.ends_with("_t") => t.to_string().into(),
// Windows uppercase structs don't have `struct` in fr.into()ont:
// Windows uppercase structs don't have `struct` in front:
t if ty.chars().next().unwrap().is_uppercase() => t.to_string().into(),
"stat" => "struct __stat64".to_string().into(),
"utimbuf" => "struct __utimbuf64".to_string().into(),
_ => None,
}
});
cfg.rename_type(move |ty| {
match ty {
// FIXME(windows): these don't exist:
"time64_t" => "__time64_t".to_string().into(),
"ssize_t" => "SSIZE_T".to_string().into(),

"sighandler_t" if !gnu => "_crt_signal_t".to_string().into(),
"sighandler_t" if gnu => "__p_sig_fn_t".to_string().into(),
_ => None,
}
cfg.rename_type(move |ty| match ty {
"time64_t" => "__time64_t".to_string().into(),
"ssize_t" => "SSIZE_T".to_string().into(),
"sighandler_t" if !gnu => "_crt_signal_t".to_string().into(),
"sighandler_t" if gnu => "__p_sig_fn_t".to_string().into(),
_ => None,
});

cfg.rename_fn(move |func| {
Expand All @@ -800,19 +799,9 @@ fn test_windows(target: &str) {
cfg.skip_alias(move |alias| match alias.ident() {
"SSIZE_T" if !gnu => true,
"ssize_t" if !gnu => true,
// FIXME(windows): The size and alignment of this type are incorrect
"time_t" if gnu && i686 => true,
_ => false,
});

cfg.skip_struct(move |struct_| {
match struct_.ident() {
// FIXME(windows): The size and alignment of this struct are incorrect
"timespec" if gnu && i686 => true,
_ => false,
}
});

cfg.skip_const(move |constant| {
match constant.ident() {
// FIXME(windows): API error:
Expand Down Expand Up @@ -1380,7 +1369,6 @@ fn test_netbsd(target: &str) {
});

cfg.skip_fn(move |func| {
#[expect(clippy::wildcard_in_or_patterns)]
match func.ident() {
// FIXME(netbsd): Look into setting `_POSIX_C_SOURCE` to enable this
"qsort_r" => true,
Expand Down Expand Up @@ -3085,11 +3073,8 @@ fn test_emscripten(target: &str) {
});

cfg.skip_alias(|ty| {
match ty.ident() {
// LFS64 types have been removed in Emscripten 3.1.44
// https://github.com/emscripten-core/emscripten/pull/19812
ty => ty.ends_with("64") || ty.ends_with("64_t"),
}
let ty = ty.ident();
ty.ends_with("64") || ty.ends_with("64_t")
});

cfg.skip_struct(move |struct_| {
Expand Down
60 changes: 44 additions & 16 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ pub type clock_t = i32;
pub type errno_t = c_int;

cfg_if! {
if #[cfg(all(target_arch = "x86", target_env = "gnu"))] {
if #[cfg(windows_use_time32)] {
pub type time_t = c_long;
} else if #[cfg(all(
any(target_arch = "x86", target_arch = "arm"),
target_env = "gnu"
))] {
pub type time_t = i32;
} else {
pub type time_t = i64;
Expand All @@ -39,7 +44,6 @@ pub type time64_t = i64;
pub type SOCKET = crate::uintptr_t;

s! {
// note this is the struct called stat64 in Windows. Not stat, nor stati64.
pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
Expand All @@ -48,16 +52,15 @@ s! {
pub st_uid: c_short,
pub st_gid: c_short,
pub st_rdev: dev_t,
pub st_size: i64,
pub st_atime: time64_t,
pub st_mtime: time64_t,
pub st_ctime: time64_t,
pub st_size: off_t,
pub st_atime: time_t,
pub st_mtime: time_t,
pub st_ctime: time_t,
}

// note that this is called utimbuf64 in Windows
pub struct utimbuf {
pub actime: time64_t,
pub modtime: time64_t,
pub actime: time_t,
pub modtime: time_t,
}

pub struct tm {
Expand Down Expand Up @@ -379,9 +382,32 @@ extern "C" {
pub fn raise(signum: c_int) -> c_int;

pub fn clock() -> clock_t;
#[cfg_attr(windows_use_time32, link_name = "_ctime32")]
#[cfg_attr(not(windows_use_time32), link_name = "_ctime64")]
#[cfg_attr(
target_env = "msvc",
deprecated(
since = "0.2.184",
note = "This function, among other older functions in the CRT, were marked deprecated \
and have more secure variants with the same symbols but `_s`-suffixed. If you \
use this specific routine, we're requesting comments at #PENDING."
)
)]
pub fn ctime(sourceTime: *const time_t) -> *mut c_char;
#[cfg_attr(windows_use_time32, link_name = "_difftime32")]
#[cfg_attr(not(windows_use_time32), link_name = "_difftime64")]
#[cfg_attr(
target_env = "msvc",
deprecated(
since = "0.2.184",
note = "This function, among other older functions in the CRT, were marked deprecated \
and have more secure variants with the same symbols but `_s`-suffixed. If you \
use this specific routine, we're requesting comments at #PENDING."
)
)]
pub fn difftime(timeEnd: time_t, timeStart: time_t) -> c_double;
#[link_name = "_gmtime64_s"]
#[cfg_attr(windows_use_time32, link_name = "_gmtime32_s")]
#[cfg_attr(not(windows_use_time32), link_name = "_gmtime64_s")]
pub fn gmtime_s(destTime: *mut tm, srcTime: *const time_t) -> c_int;
#[link_name = "_get_daylight"]
pub fn get_daylight(hours: *mut c_int) -> errno_t;
Expand All @@ -396,9 +422,11 @@ extern "C" {
size_in_bytes: size_t,
index: c_int,
) -> errno_t;
#[link_name = "_localtime64_s"]
#[cfg_attr(windows_use_time32, link_name = "_localtime32_s")]
#[cfg_attr(not(windows_use_time32), link_name = "_localtime64_s")]
pub fn localtime_s(tmDest: *mut tm, sourceTime: *const time_t) -> crate::errno_t;
#[link_name = "_time64"]
#[cfg_attr(windows_use_time32, link_name = "_time32")]
#[cfg_attr(not(windows_use_time32), link_name = "_time64")]
pub fn time(destTime: *mut time_t) -> time_t;
#[link_name = "_tzset"]
pub fn tzset();
Expand All @@ -410,13 +438,13 @@ extern "C" {
pub fn mkdir(path: *const c_char) -> c_int;
#[link_name = "_wrmdir"]
pub fn wrmdir(path: *const wchar_t) -> c_int;
#[link_name = "_fstat64"]
#[link_name = "_fstat"]
pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
#[link_name = "_stat64"]
#[link_name = "_stat"]
pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
#[link_name = "_wstat64"]
#[link_name = "_wstat"]
pub fn wstat(path: *const wchar_t, buf: *mut stat) -> c_int;
#[link_name = "_wutime64"]
#[link_name = "_wutime"]
pub fn wutime(file: *const wchar_t, buf: *mut utimbuf) -> c_int;
#[link_name = "_popen"]
pub fn popen(command: *const c_char, mode: *const c_char) -> *mut crate::FILE;
Expand Down
Loading