Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
44c84be
ci: Add testing for NetBSD
tgross35 Oct 27, 2025
8fd353b
Add `core::cfg` to the prelude
tgross35 Nov 3, 2025
23cc63d
test: Factor out a fallible command runner
tgross35 Nov 2, 2025
8f67a0f
NetBSD: Delete items from the semver file that don't exist
tgross35 Oct 28, 2025
7f354aa
NetBSD: riscv64: Fix the mcontext types
tgross35 Nov 2, 2025
99c9f2d
NetBSD: Update test headers and skips
tgross35 Oct 28, 2025
3707e00
NetBSD: Skip tests on 9.x for network structs with alignment mismatches
tgross35 Nov 3, 2025
a16d143
NetBSD: Remove IFF_NOTRAILERS
tgross35 Oct 28, 2025
e59edd0
NetBSD: Remove `*_MAXID` constants and `AT_SUN_LDPGSIZE`
tgross35 Oct 29, 2025
c0258a1
NetBSD: Remove `vm_size_t`
tgross35 Oct 28, 2025
185a565
NetBSD: Remove BPF constants
tgross35 Oct 29, 2025
e65f8f1
NetBSD: Replace REG_ENOSYS with REG_ILLSEQ
tgross35 Oct 28, 2025
cc2d05d
NetBSD: Fix `uucred.cr_ngroups` from `int` to `short`
tgross35 Oct 28, 2025
63f4037
NetBSD: Fix the type of `kevent.udata`
tgross35 Oct 28, 2025
a1426ae
NetBSD: Fix the value of `PT_SUSPEND`
tgross35 Oct 29, 2025
03761f1
NetBSD: Fix the values of FNM_* constants
tgross35 Oct 28, 2025
3aa7044
NetBSD: Fix the type of `mcontext_t.__fpregs`
tgross35 Oct 28, 2025
75fff51
NetBSD: Increase the size of `sockaddr_dl.sdl_data` from 12 to 24
tgross35 Oct 28, 2025
9b0dedb
NetBSD: Make `_cpuset` an extern type
tgross35 Oct 28, 2025
b260634
NetBSD: Account for upstream changes to ptrace with LWP
tgross35 Oct 28, 2025
579a145
NetBSD: Introduce `statvfs.rs`
tgross35 Oct 29, 2025
18e8315
NetBSD: Make `statvfs.f_spare` non-public
tgross35 Oct 28, 2025
50ddd7b
NetBSD: Skip tests for structvfs on NetBSD10
tgross35 Nov 3, 2025
0255bbd
NetBSD: Correct `ipc_perm`, split from OpenBSD as `ipc.rs`
tgross35 Oct 29, 2025
ef16a02
NetBSD: Introduce `utmp_.rs`, correct the definition of `lastlog`
tgross35 Oct 29, 2025
5eebe27
NetBSD: Introduce `utmpx_.rs`, correct utmpx definitions
tgross35 Oct 29, 2025
9dff509
NetBSD: Introduce `types.rs`, correct the definition of `lwpid_t`
tgross35 Oct 29, 2025
60500e6
NetBSD: Introduce `timex.rs`
tgross35 Oct 29, 2025
438b06c
NetBSD: Introduce `time.rs`, fix the values of `CLOCK_*_CPUTIME_ID`
tgross35 Oct 29, 2025
c1dc9ea
NetBSD: Introduce `if_.rs`, fix the definition of `ifreq`
tgross35 Oct 29, 2025
e08f2e0
NetBSD: Correct a number of symbol link names
tgross35 Oct 29, 2025
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
21 changes: 21 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ jobs:
matrix:
include:
- target: x86_64-pc-solaris
- target: x86_64-unknown-netbsd
timeout-minutes: 25
steps:
- uses: actions/checkout@v5
Expand All @@ -290,6 +291,26 @@ jobs:
export PATH=$HOME/.rust_solaris/bin:$PATH
./ci/run.sh ${{ matrix.target }}

- name: Test on NetBSD
uses: vmactions/netbsd-vm@v1
if: contains(matrix.target, 'netbsd')
with:
release: "10.1"
usesh: true
mem: 4096
copyback: false
prepare: |
set -x
/usr/sbin/pkg_add curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
--profile minimal --default-toolchain nightly -y
run: |
set -x
. "$HOME/.cargo/env"
which rustc
rustc -Vv
./ci/run.sh ${{ matrix.target }}

ctest_msrv:
name: Check ctest MSRV
runs-on: ubuntu-24.04
Expand Down
162 changes: 128 additions & 34 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,12 @@ fn test_netbsd(target: &str) {
assert!(target.contains("netbsd"));
let mut cfg = ctest_cfg();

// Assume netbsd10 but check for netbsd9 for test config.
let netbsd9 = match try_command_output("uname", &["-sr"]) {
Some(s) if s.starts_with("NetBSD 9.") => true,
_ => false,
};

cfg.flag("-Wno-deprecated-declarations");
cfg.define("_NETBSD_SOURCE", Some("1"));

Expand All @@ -1195,10 +1201,12 @@ fn test_netbsd(target: &str) {
"ctype.h",
"dirent.h",
"dlfcn.h",
"execinfo.h",
"glob.h",
"grp.h",
"ifaddrs.h",
"langinfo.h",
"lwp.h",
"net/bpf.h",
"net/if.h",
"net/if_arp.h",
Expand All @@ -1217,25 +1225,30 @@ fn test_netbsd(target: &str) {
"sched.h",
"semaphore.h",
"signal.h",
"spawn.h",
"string.h",
"sys/endian.h",
"sys/exec_elf.h",
"sys/xattr.h",
"sys/extattr.h",
"sys/file.h",
(!netbsd9, "sys/futex.h"),
"sys/ioctl.h",
"sys/ioctl_compat.h",
"sys/ipc.h",
"sys/ktrace.h",
"sys/mman.h",
"sys/mount.h",
"sys/ptrace.h",
(!netbsd9, "sys/random.h"),
"sys/resource.h",
"sys/sched.h",
"sys/shm.h",
"sys/socket.h",
"sys/statvfs.h",
"sys/sysctl.h",
"sys/time.h",
(!netbsd9, "sys/timerfd.h"),
"sys/times.h",
"sys/timex.h",
"sys/ucontext.h",
Expand All @@ -1258,6 +1271,8 @@ fn test_netbsd(target: &str) {
"sys/reboot.h",
"sys/shm.h",
"iconv.h",
"utmp.h",
"utmpx.h",
);

cfg.rename_type(move |ty| {
Expand Down Expand Up @@ -1289,10 +1304,14 @@ fn test_netbsd(target: &str) {
}
});

cfg.alias_is_c_enum(|ty| ty == "fae_action");

cfg.skip_alias(move |ty| {
match ty.ident() {
// FIXME(netbsd): sighandler_t is crazy across platforms
"sighandler_t" => true,
// Incomplete type in C
"cpuset_t" => true,
_ => false,
}
});
Expand All @@ -1302,6 +1321,14 @@ fn test_netbsd(target: &str) {
// These are tested as part of the linux_fcntl tests since there are
// header conflicts when including them with all the other structs.
"termios2" => true,
// Anon struct
"__exit_status" => true,
// FIXME(netbsd): Should be importable but aren't for some reason.
"Aux32Info" | "Aux64Info" => true,
// deprecated, obsolete upstream
"ptrace_lwpinfo" => true,
// ABI change in NetBSD10, with symbol versioning.
"statvfs" if !netbsd9 => true,
_ => false,
}
});
Expand All @@ -1321,26 +1348,38 @@ fn test_netbsd(target: &str) {
"SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
"SIGUNUSED" => true, // removed in glibc 2.26

// deprecated, obsolete upstream
"PT_LWPINFO" | "PL_EVENT_NONE" | "PL_EVENT_SIGNAL" | "PL_EVENT_SUSPENDED" => true,

// weird signed extension or something like that?
"MS_NOUSER" => true,
"MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
"BOTHER" => true,
"GRND_RANDOM" | "GRND_INSECURE" | "GRND_NONBLOCK" => true, // netbsd 10 minimum

// Due to the NetBSD `__BIT` macro this turns out to be an `unsigned long`, but
// the futex syscall takes `int` ops.
"FUTEX_CMD_MASK" => true,

_ => false,
}
});

cfg.skip_fn(move |func| {
#[expect(clippy::wildcard_in_or_patterns)]
match func.ident() {
// FIXME(netbsd): netbsd 10 minimum
"getentropy" | "getrandom" => true,
// FIXME(netbsd): Look into setting `_POSIX_C_SOURCE` to enable this
"qsort_r" => true,

"getrlimit" | "getrlimit64" | // non-int in 1st arg
"setrlimit" | "setrlimit64" | // non-int in 1st arg
"prlimit" | "prlimit64" | // non-int in 2nd arg
_ => false,
}
});

cfg.skip_fn_ptrcheck(move |func| {
match func {
// New symbol version present in NetBSD10, but we keep the old versions for NetBSD9
// compatibility.
"getmntinfo" | "statvfs" | "fstatvfs" | "getvfsstat" | "sigaction" => true,
_ => false,
}
});
Expand All @@ -1361,10 +1400,65 @@ fn test_netbsd(target: &str) {
("Elf64_Phdr", "p_type") => true,
// pthread_spin_t is a volatile uchar
("pthread_spinlock_t", "pts_spin") => true,

// `tcp_snd_wscale` and `tcp_rcv_wscale` are bitfields
("tcp_info", "tcp_snd_wscale") => true,
("tcp_info", "tcp_rcv_wscale") => true,

// Anonymous unions
("ifconf", "ifc_ifcu") => true,
("ifreq", "ifr_ifru") => true,
("utmpx", "ut_exit") => true,
("posix_spawn_file_actions_entry_t", "fae_data") => true,

_ => false,
}
});

// Unless otherwise noted, everything in this block was an addition in NetBS 10.
if netbsd9 {
cfg.skip_const(move |constant| match constant.ident() {
"EOWNERDEAD"
| "ENOTRECOVERABLE"
| "F_GETPATH"
| "MNT_NFS4ACLS"
| "MNT_POSIX1EACLS"
| "MNT_ACLS"
| "EVFILT_USER"
| "EVFILT_EMPTY"
| "REG_ILLSEQ"
| "PT_SET_SIGPASS"
| "PT_GET_SIGPASS"
| "EXTATTR_NAMESPACE_EMPTY" => true,
x if x.starts_with("FUTEX") => true,
x if x.starts_with("NOTE_") => true,
x if x.starts_with("PT_LWP") => true,
x if x.starts_with("TFD_") => true,
"ELAST" => true, // not version-stable
_ => false,
});

cfg.skip_struct(move |struct_| match struct_.ident() {
"sockaddr_dl" => true, // Last field increased size in 10
x if x.starts_with("ptrace_lwp") => true,
// These were packed before NetBSD 10
"arphdr" | "in_addr" | "ip_mreq" | "sockaddr_in" => true,
_ => false,
});

cfg.skip_fn(move |func| match func.ident() {
"reallocarray" | "getentropy" | "ppoll" | "getrandom" => true,
x if x.starts_with("timerfd_") => true,
_ => false,
});

cfg.skip_struct_field(|struct_, field| match (struct_.ident(), field.ident()) {
("statvfs", "f_mntfromlabel") => true, // added field
("kevent", "udata") => true, // changed type (ABI-compatible)
_ => false,
});
}

ctest::generate_test(&mut cfg, "../src/lib.rs", "ctest_output.rs").unwrap();
}

Expand Down Expand Up @@ -2179,7 +2273,21 @@ fn test_freebsd(target: &str) {
assert!(target.contains("freebsd"));
let mut cfg = ctest_cfg();

let freebsd_ver = which_freebsd();
let freebsd_ver = if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") {
let vers = version.parse().unwrap();
println!("cargo:warning=setting FreeBSD version to {vers}");
Some(vers)
} else {
match &try_command_output("freebsd-version", &[]) {
Some(s) if s.starts_with("10") => Some(10),
Some(s) if s.starts_with("11") => Some(11),
Some(s) if s.starts_with("12") => Some(12),
Some(s) if s.starts_with("13") => Some(13),
Some(s) if s.starts_with("14") => Some(14),
Some(s) if s.starts_with("15") => Some(15),
Some(_) | None => None,
}
};

match freebsd_ver {
Some(12) => cfg.cfg("freebsd12", None),
Expand Down Expand Up @@ -4744,34 +4852,6 @@ fn test_linux_like_apis(target: &str) {
}
}

fn which_freebsd() -> Option<i32> {
if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") {
let vers = version.parse().unwrap();
println!("cargo:warning=setting FreeBSD version to {vers}");
return Some(vers);
}

let output = std::process::Command::new("freebsd-version")
.output()
.ok()?;

if !output.status.success() {
return None;
}

let stdout = String::from_utf8(output.stdout).ok()?;

match &stdout {
s if s.starts_with("10") => Some(10),
s if s.starts_with("11") => Some(11),
s if s.starts_with("12") => Some(12),
s if s.starts_with("13") => Some(13),
s if s.starts_with("14") => Some(14),
s if s.starts_with("15") => Some(15),
_ => None,
}
}

fn test_haiku(target: &str) {
assert!(target.contains("haiku"));

Expand Down Expand Up @@ -5396,3 +5476,17 @@ fn test_aix(target: &str) {

ctest::generate_test(&mut cfg, "../src/lib.rs", "ctest_output.rs").unwrap();
}

/// Attempt to execute a command and collect its output, If the command fails for whatever
/// reason, return `None`.
fn try_command_output(cmd: &str, args: &[&str]) -> Option<String> {
let output = std::process::Command::new(cmd).args(args).output().ok()?;

if !output.status.success() {
return None;
}

let res = String::from_utf8(output.stdout)
.unwrap_or_else(|e| panic!("command {cmd} returned non-UTF-8 output: {e}"));
Some(res)
}
Loading
Loading