Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2cb3892
ci: Add a job to ensure documentation succeeds
tgross35 Apr 3, 2025
6b1c04c
cleanup: Also use `s_no_extra_traits!` for private structs
tgross35 Nov 2, 2025
0dd9097
ci: Make clippy a required job
tgross35 Nov 4, 2025
54e9ea6
ci: Add testing for NetBSD
tgross35 Oct 27, 2025
2852a12
Add `core::cfg` to the prelude
tgross35 Nov 3, 2025
954f922
test: Factor out a fallible command runner
tgross35 Nov 2, 2025
daa0137
NetBSD: Delete items from the semver file that don't exist
tgross35 Oct 28, 2025
cd8d023
NetBSD: riscv64: Fix the mcontext types
tgross35 Nov 2, 2025
4d702f4
NetBSD: Update test headers and skips
tgross35 Oct 28, 2025
7ef85c2
NetBSD: Skip tests on 9.x for network structs with alignment mismatches
tgross35 Nov 3, 2025
19aa077
NetBSD: Remove IFF_NOTRAILERS
tgross35 Oct 28, 2025
d8ceb4f
NetBSD: Remove `*_MAXID` constants and `AT_SUN_LDPGSIZE`
tgross35 Oct 29, 2025
213f4b0
NetBSD: Remove `vm_size_t`
tgross35 Oct 28, 2025
ba7b810
NetBSD: Remove BPF constants
tgross35 Oct 29, 2025
d1143f5
NetBSD: Replace REG_ENOSYS with REG_ILLSEQ
tgross35 Oct 28, 2025
84c1b75
NetBSD: Fix `uucred.cr_ngroups` from `int` to `short`
tgross35 Oct 28, 2025
04cd0d2
NetBSD: Fix the type of `kevent.udata`
tgross35 Oct 28, 2025
423d634
NetBSD: Fix the value of `PT_SUSPEND`
tgross35 Oct 29, 2025
e5958b8
NetBSD: Fix the values of FNM_* constants
tgross35 Oct 28, 2025
9f34749
NetBSD: Fix the type of `mcontext_t.__fpregs`
tgross35 Oct 28, 2025
8490147
NetBSD: Increase the size of `sockaddr_dl.sdl_data` from 12 to 24
tgross35 Oct 28, 2025
ac8cd41
NetBSD: Make `_cpuset` an extern type
tgross35 Oct 28, 2025
980cd40
NetBSD: Account for upstream changes to ptrace with LWP
tgross35 Oct 28, 2025
18ec731
NetBSD: Introduce `statvfs.rs`
tgross35 Oct 29, 2025
381d494
NetBSD: Make `statvfs.f_spare` non-public
tgross35 Oct 28, 2025
4c66897
NetBSD: Skip tests for structvfs on NetBSD10
tgross35 Nov 3, 2025
ea09f15
NetBSD: Correct `ipc_perm`, split from OpenBSD as `ipc.rs`
tgross35 Oct 29, 2025
e8ba00e
NetBSD: Introduce `utmp_.rs`, correct the definition of `lastlog`
tgross35 Oct 29, 2025
a9c8fc9
NetBSD: Introduce `utmpx_.rs`, correct utmpx definitions
tgross35 Oct 29, 2025
4ad7970
NetBSD: Introduce `types.rs`, correct the definition of `lwpid_t`
tgross35 Oct 29, 2025
00a0290
NetBSD: Introduce `timex.rs`
tgross35 Oct 29, 2025
b3d3fa1
NetBSD: Introduce `time.rs`, fix the values of `CLOCK_*_CPUTIME_ID`
tgross35 Oct 29, 2025
0eb105b
NetBSD: Introduce `if_.rs`, fix the definition of `ifreq`
tgross35 Oct 29, 2025
0e964d8
NetBSD: Correct a number of symbol link names
tgross35 Oct 29, 2025
83f3c38
Add missing constants from `unistd.h`
Nov 3, 2025
893d417
ci: Check process output in create-artifacts
tgross35 Nov 4, 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
35 changes: 34 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ jobs:
matrix:
include:
- target: x86_64-pc-solaris
- target: x86_64-unknown-netbsd
timeout-minutes: 25
steps:
- uses: actions/checkout@v5
Expand All @@ -281,6 +282,37 @@ 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 }}

docs:
name: Ensure docs build
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@master
- name: Install Rust
run: rustup update nightly --no-self-update && rustup default nightly
- uses: Swatinem/rust-cache@v2
- run: cargo doc --workspace --no-deps

# One job that "summarizes" the success state of this pipeline. This can then be added to branch
# protection, rather than having to add each job separately.
success:
Expand All @@ -292,8 +324,9 @@ jobs:
- test_tier2
- test_tier2_vm
- verify_build
- docs
- clippy
# GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency
# Github branch protection is exceedingly silly and treats "jobs skipped because a dependency
# failed" as success. So we have to do some contortions to ensure the job fails if any of its
# dependencies fails.
if: always() # make sure this is never "skipped"
Expand Down
11 changes: 9 additions & 2 deletions ci/create-artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ def main():
archive_name = f"archive-{now}"
archive_path = f"{archive_name}.tar.gz"

sp.run(["tar", "czvf", archive_path, "-C", build_dir, "-T-"], input=file_list)
sp.run(
["tar", "czvf", archive_path, "-C", build_dir, "-T-"],
input=file_list,
check=True,
)

# If we are in GHA, set these env vars for future use
gh_env = os.getenv("GITHUB_ENV")
Expand All @@ -42,6 +46,7 @@ def main():


if __name__ == "__main__":
print("Starting script...") # For debugging CI failures
# FIXME(ci): remove after the bump to windoes-2025 GHA images
# Python <= 3.9 does not support the very helpful `root_dir` argument,
# and that is the version used by the Windows GHA images. Rather than
Expand All @@ -55,10 +60,12 @@ def main():
sys.exit(1)

# Find the next 3.1x Python version
dirs = sorted(list(Path(r"C:\hostedtoolcache\windows\Python").iterdir()))
dirs = sorted(Path(r"C:\hostedtoolcache\windows\Python").iterdir())
usepy = next(x for x in dirs if r"\3.1" in str(x))
py = usepy.joinpath(r"x64\python.exe")
print(f"relaunching with {py}")
os.execvp(py, [__file__] + sys.argv)

main()
else:
print("not invoked as main, exiting") # For debugging CI failures
162 changes: 128 additions & 34 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,6 +1254,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 @@ -1280,10 +1286,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 @@ -1302,25 +1310,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 @@ -1343,6 +1356,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 @@ -1375,10 +1390,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 @@ -1390,6 +1409,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 @@ -1409,28 +1436,40 @@ 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
// FIXME(netbsd): https://github.com/rust-lang/libc/issues/1272
"execv" | "execve" | "execvp" => true,
"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 @@ -1453,10 +1492,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 @@ -2286,7 +2380,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 @@ -4905,34 +5013,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 @@ -5573,3 +5653,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