Skip to content

Commit 9428748

Browse files
committed
libc-test: port windows to use ctest-next
1 parent e634372 commit 9428748

File tree

7 files changed

+156
-5
lines changed

7 files changed

+156
-5
lines changed

.github/workflows/ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
# Remove `-Dwarnings` at the MSRV since lints may be different
9090
export RUSTFLAGS=""
9191
# Remove `ctest-next` which uses the 2024 edition
92-
perl -i -ne 'print unless /"ctest-(next|test)",/' Cargo.toml
92+
perl -i -ne 'print unless /"ctest-(next|test)",/ || /"libc-test",/' Cargo.toml
9393
fi
9494
9595
./ci/verify-build.sh
@@ -320,7 +320,7 @@ jobs:
320320
- name: Install Rust
321321
run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV"
322322
- name: Remove edition 2024 crates
323-
run: perl -i -ne 'print unless /"ctest-(next|test)",/' Cargo.toml
323+
run: perl -i -ne 'print unless /"ctest-(next|test)",/ || /"libc-test",/' Cargo.toml
324324
- uses: Swatinem/rust-cache@v2
325325
- run: cargo build -p ctest
326326

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ctest-next/src/template.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::ops::Deref;
22

33
use askama::Template;
4+
use proc_macro2::Span;
45
use quote::ToTokens;
56
use syn::spanned::Spanned;
67

@@ -517,7 +518,14 @@ impl<'a> TranslateHelper<'a> {
517518
// inside of `Fn` when parsed.
518519
MapInput::Fn(_) => unimplemented!(),
519520
// For structs/unions/aliases, their type is the same as their identifier.
520-
MapInput::Alias(a) => (a.ident(), a.ident().to_string()),
521+
// FIXME(ctest): For some specific primitives such as c_uint, they don't exist on the
522+
// C side and have to be manually translated. If they are removed to use `std::ffi`,
523+
// then this becomes unneeded (although it won't break).
524+
MapInput::Alias(a) => (
525+
a.ident(),
526+
self.translator
527+
.translate_primitive_type(&syn::Ident::new(a.ident(), Span::call_site())),
528+
),
521529
MapInput::Struct(s) => (s.ident(), s.ident().to_string()),
522530
MapInput::Union(u) => (u.ident(), u.ident().to_string()),
523531

ctest-next/src/translator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl Translator {
228228
}
229229

230230
/// Translate a Rust primitive type into its C equivalent.
231-
fn translate_primitive_type(&self, ty: &syn::Ident) -> String {
231+
pub(crate) fn translate_primitive_type(&self, ty: &syn::Ident) -> String {
232232
match ty.to_string().as_str() {
233233
"usize" => "size_t".to_string(),
234234
"isize" => "ssize_t".to_string(),

libc-test/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ annotate-snippets = { version = "0.11.5", features = ["testing-colors"] }
2121
[build-dependencies]
2222
cc = "1.2.29"
2323
ctest = { path = "../ctest" }
24+
ctest-next = { path = "../ctest-next" }
2425
regex = "1.11.1"
2526

2627
[features]
@@ -33,6 +34,11 @@ name = "main"
3334
path = "test/main.rs"
3435
harness = false
3536

37+
[[test]]
38+
name = "main_next"
39+
path = "test/main_next.rs"
40+
harness = false
41+
3642
[[test]]
3743
name = "linux-fcntl"
3844
path = "test/linux_fcntl.rs"

libc-test/build.rs

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ fn do_ctest() {
6565
t if t.contains("solaris") => test_solarish(t),
6666
t if t.contains("illumos") => test_solarish(t),
6767
t if t.contains("wasi") => test_wasi(t),
68-
t if t.contains("windows") => test_windows(t),
68+
t if t.contains("windows") => {
69+
test_windows_next(t);
70+
test_windows(t);
71+
}
6972
t if t.contains("vxworks") => test_vxworks(t),
7073
t if t.contains("nto-qnx") => test_neutrino(t),
7174
t if t.contains("aix") => return test_aix(t),
@@ -77,6 +80,10 @@ fn ctest_cfg() -> ctest::TestGenerator {
7780
ctest::TestGenerator::new()
7881
}
7982

83+
fn ctest_next_cfg() -> ctest_next::TestGenerator {
84+
ctest_next::TestGenerator::new()
85+
}
86+
8087
fn do_semver() {
8188
let mut out = PathBuf::from(env::var("OUT_DIR").unwrap());
8289
out.push("semver.rs");
@@ -164,6 +171,13 @@ fn main() {
164171
let re = regex::bytes::Regex::new(r"(?-u:\b)crate::").unwrap();
165172
copy_dir_hotfix(Path::new("../src"), &hotfix_dir, &re, b"::");
166173

174+
// FIXME(ctest): Only needed until ctest-next supports all tests.
175+
std::fs::write(
176+
format!("{}/main_next.rs", std::env::var("OUT_DIR").unwrap()),
177+
"\nfn main() { println!(\"test result: ok\"); }\n",
178+
)
179+
.unwrap_or_default();
180+
167181
do_cc();
168182
do_ctest();
169183
do_semver();
@@ -945,6 +959,123 @@ fn test_windows(target: &str) {
945959
cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
946960
}
947961

962+
fn test_windows_next(target: &str) {
963+
assert!(target.contains("windows"));
964+
let gnu = target.contains("gnu");
965+
let i686 = target.contains("i686");
966+
967+
let mut cfg = ctest_next_cfg();
968+
if target.contains("msvc") {
969+
cfg.flag("/wd4324");
970+
}
971+
cfg.define("_WIN32_WINNT", Some("0x8000"));
972+
973+
headers! { cfg:
974+
"direct.h",
975+
"errno.h",
976+
"fcntl.h",
977+
"io.h",
978+
"limits.h",
979+
"locale.h",
980+
"process.h",
981+
"signal.h",
982+
"stddef.h",
983+
"stdint.h",
984+
"stdio.h",
985+
"stdlib.h",
986+
"sys/stat.h",
987+
"sys/types.h",
988+
"sys/utime.h",
989+
"time.h",
990+
"wchar.h",
991+
[gnu]: "ws2tcpip.h",
992+
[!gnu]: "Winsock2.h",
993+
}
994+
995+
cfg.rename_struct_ty(|ty| {
996+
match ty {
997+
// Just pass all these through, no need for a "struct" prefix
998+
"FILE" | "DIR" | "Dl_info" => ty.to_string().into(),
999+
t if t.ends_with("_t") => t.to_string().into(),
1000+
// Windows uppercase structs don't have `struct` in fr.into()ont:
1001+
t if ty.chars().next().unwrap().is_uppercase() => t.to_string().into(),
1002+
"stat" => "struct __stat64".to_string().into(),
1003+
"utimbuf" => "struct __utimbuf64".to_string().into(),
1004+
_ => None,
1005+
}
1006+
});
1007+
cfg.rename_type(move |ty| {
1008+
match ty {
1009+
// FIXME(windows): these don't exist:
1010+
"time64_t" => "__time64_t".to_string().into(),
1011+
"ssize_t" => "SSIZE_T".to_string().into(),
1012+
1013+
"sighandler_t" if !gnu => "_crt_signal_t".to_string().into(),
1014+
"sighandler_t" if gnu => "__p_sig_fn_t".to_string().into(),
1015+
_ => None,
1016+
}
1017+
});
1018+
1019+
cfg.rename_fn(move |func| {
1020+
func.link_name()
1021+
.map(|l| l.to_string())
1022+
.or(func.ident().to_string().into())
1023+
});
1024+
1025+
cfg.skip_alias(move |alias| match alias.ident() {
1026+
"SSIZE_T" if !gnu => true,
1027+
"ssize_t" if !gnu => true,
1028+
// FIXME(windows): The size and alignment of this type are incorrect
1029+
"time_t" if gnu && i686 => true,
1030+
_ => false,
1031+
});
1032+
1033+
cfg.skip_struct(move |struct_| {
1034+
let ty = struct_.ident();
1035+
if ty.starts_with("__c_anonymous_") {
1036+
return true;
1037+
}
1038+
match ty {
1039+
// FIXME(windows): The size and alignment of this struct are incorrect
1040+
"timespec" if gnu && i686 => true,
1041+
_ => false,
1042+
}
1043+
});
1044+
cfg.skip_union(move |union_| union_.ident().starts_with("__c_anonymous_"));
1045+
1046+
cfg.skip_const(move |constant| {
1047+
match constant.ident() {
1048+
// FIXME(windows): API error:
1049+
// SIG_ERR type is "void (*)(int)", not "int"
1050+
"SIG_ERR" |
1051+
// Similar for SIG_DFL/IGN/GET/SGE/ACK
1052+
"SIG_DFL" | "SIG_IGN" | "SIG_GET" | "SIG_SGE" | "SIG_ACK" => true,
1053+
// FIXME(windows): newer windows-gnu environment on CI?
1054+
"_O_OBTAIN_DIR" if gnu => true,
1055+
_ => false,
1056+
}
1057+
});
1058+
1059+
cfg.skip_struct_field(move |s, field| s.ident() == "CONTEXT" && field.ident() == "Fp");
1060+
// FIXME(windows): All functions point to the wrong addresses?
1061+
// cfg.skip_fn_ptr_check(|_| true);
1062+
1063+
cfg.skip_signededness(move |c| {
1064+
match c {
1065+
// windows-isms
1066+
n if n.starts_with("P") => true,
1067+
n if n.starts_with("H") => true,
1068+
n if n.starts_with("LP") => true,
1069+
"sighandler_t" if gnu => true,
1070+
_ => false,
1071+
}
1072+
});
1073+
1074+
cfg.skip_fn(|_| false);
1075+
1076+
ctest_next::generate_test(&mut cfg, "../src/lib.rs", "main_next.rs").unwrap();
1077+
}
1078+
9481079
fn test_redox(target: &str) {
9491080
assert!(target.contains("redox"));
9501081

libc-test/test/main_next.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![allow(unused_imports, deprecated)]
2+
3+
use libc::*;
4+
5+
include!(concat!(env!("OUT_DIR"), "/main_next.rs"));

0 commit comments

Comments
 (0)