Skip to content

Commit c192a5c

Browse files
author
Xing Xue
committed
Enable libc-test for AIX and fix definitions/declarations.
1 parent 76696a2 commit c192a5c

File tree

7 files changed

+3396
-524
lines changed

7 files changed

+3396
-524
lines changed

libc-test/build.rs

Lines changed: 239 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fn do_ctest() {
6868
t if t.contains("windows") => test_windows(t),
6969
t if t.contains("vxworks") => test_vxworks(t),
7070
t if t.contains("nto-qnx") => test_neutrino(t),
71+
t if t.contains("aix") => return test_aix(t),
7172
t => panic!("unknown target {t}"),
7273
}
7374
}
@@ -95,7 +96,9 @@ fn do_semver() {
9596
// NOTE: Android doesn't include the unix file (or the Linux file) because
9697
// there are some many definitions missing it's actually easier just to
9798
// maintain a file for Android.
98-
if family != os && os != "android" {
99+
// NOTE: AIX doesn't include the unix file because there are definitions
100+
// missing on AIX. It is easier to maintain a file for AIX.
101+
if family != os && !matches!(os.as_str(), "android" | "aix") {
99102
process_semver_file(&mut output, &mut semver_root, &family);
100103
}
101104
// We don't do semver for unknown targets.
@@ -5393,3 +5396,238 @@ fn test_haiku(target: &str) {
53935396
});
53945397
cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
53955398
}
5399+
5400+
fn test_aix(target: &str) {
5401+
assert!(target.contains("aix"));
5402+
5403+
// ctest generates arguments supported only by clang, so make sure to
5404+
// run with CC=clang. While debugging, "CFLAGS=-ferror-limit=<large num>"
5405+
// is useful to get more error output.
5406+
let mut cfg = ctest_cfg();
5407+
cfg.define("_THREAD_SAFE", None);
5408+
5409+
// Avoid the error for definitions such as '{0, 0, 0, 1}' for
5410+
// 'IN6ADDR_LOOPBACK_INIT' in netinent/in.h.
5411+
cfg.flag("-Wno-missing-braces");
5412+
5413+
headers! { cfg:
5414+
"aio.h",
5415+
"ctype.h",
5416+
"dirent.h",
5417+
"dlfcn.h",
5418+
"errno.h",
5419+
"fcntl.h",
5420+
"fnmatch.h",
5421+
"glob.h",
5422+
"grp.h",
5423+
"iconv.h",
5424+
"langinfo.h",
5425+
"libgen.h",
5426+
"limits.h",
5427+
"locale.h",
5428+
"malloc.h",
5429+
"mntent.h",
5430+
"mqueue.h",
5431+
"netinet/in.h", // this needs be before net/if.h
5432+
"poll.h", // this needs be before net/if.h
5433+
"sys/pollset.h", // this needs to be before net/if.h
5434+
"net/if.h",
5435+
"net/bpf.h", // this needs to be after net/if.h
5436+
"net/if_dl.h",
5437+
"netdb.h",
5438+
"netinet/tcp.h",
5439+
"pthread.h",
5440+
"pwd.h",
5441+
"rpcsvc/mount.h",
5442+
"rpcsvc/rstat.h",
5443+
"regex.h",
5444+
"resolv.h",
5445+
"sched.h",
5446+
"search.h",
5447+
"semaphore.h",
5448+
"signal.h",
5449+
"spawn.h",
5450+
"stddef.h",
5451+
"stdint.h",
5452+
"stdio.h",
5453+
"stdlib.h",
5454+
"string.h",
5455+
"strings.h",
5456+
"sys/aacct.h",
5457+
"sys/acct.h",
5458+
"sys/dr.h",
5459+
"sys/file.h",
5460+
"sys/io.h",
5461+
"sys/ioctl.h",
5462+
"sys/ipc.h",
5463+
"sys/ldr.h",
5464+
"sys/mman.h",
5465+
"sys/msg.h",
5466+
"sys/reg.h",
5467+
"sys/resource.h",
5468+
"sys/sem.h",
5469+
"sys/shm.h",
5470+
"sys/socket.h",
5471+
"sys/stat.h",
5472+
"sys/statfs.h",
5473+
"sys/statvfs.h",
5474+
"sys/stropts.h",
5475+
"sys/termio.h",
5476+
"sys/time.h",
5477+
"sys/times.h",
5478+
"sys/types.h",
5479+
"sys/uio.h",
5480+
"sys/un.h",
5481+
"sys/user.h",
5482+
"sys/utsname.h",
5483+
"sys/vattr.h",
5484+
"sys/vminfo.h",
5485+
"sys/wait.h",
5486+
"sys/xti.h",
5487+
"syslog.h",
5488+
"termios.h",
5489+
"thread.h",
5490+
"time.h",
5491+
"ucontext.h",
5492+
"unistd.h",
5493+
"utime.h",
5494+
"utmp.h",
5495+
"utmpx.h",
5496+
"wchar.h",
5497+
}
5498+
5499+
cfg.skip_type(move |ty| match ty {
5500+
// AIX does not define type 'sighandler_t'.
5501+
"sighandler_t" => true,
5502+
5503+
// The alignment of 'double' does not agree between C and Rust for AIX.
5504+
// We are working on a resolution.
5505+
"c_double" => true,
5506+
5507+
_ => false,
5508+
});
5509+
5510+
cfg.type_name(move |ty, is_struct, is_union| match ty {
5511+
"DIR" => ty.to_string(),
5512+
"FILE" => ty.to_string(),
5513+
"ACTION" => ty.to_string(),
5514+
5515+
// 'sigval' is a struct in Rust, but a union in C.
5516+
"sigval" => format!("union sigval"),
5517+
5518+
t if t.ends_with("_t") => t.to_string(),
5519+
t if is_struct => format!("struct {}", t),
5520+
t if is_union => format!("union {}", t),
5521+
t => t.to_string(),
5522+
});
5523+
5524+
cfg.skip_const(move |name| match name {
5525+
// Skip 'sighandler_t' assignments.
5526+
"SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true,
5527+
5528+
_ => false,
5529+
});
5530+
5531+
cfg.skip_struct(move |ty| {
5532+
match ty {
5533+
// FIXME(union): actually a union.
5534+
"sigval" => true,
5535+
5536+
// '__poll_ctl_ext_u' and '__pollfd_ext_u' are for unnamed unions.
5537+
"__poll_ctl_ext_u" => true,
5538+
"__pollfd_ext_u" => true,
5539+
5540+
// 'struct fpreg_t' is not defined in AIX headers. It is created to
5541+
// allow type 'double' to be used in signal contexts.
5542+
"fpreg_t" => true,
5543+
5544+
_ => false,
5545+
}
5546+
});
5547+
5548+
cfg.skip_field_type(move |struct_, field| {
5549+
match (struct_, field) {
5550+
// AIX does not define 'sighandler_t'.
5551+
("sigaction", "sa_sigaction") => true,
5552+
5553+
// The type of 'fpr' is 'fpreg_t' which is created to allow type
5554+
// 'double' to be used in signal contexts.
5555+
("__context64", "fpr") => true,
5556+
("__tm_context_t", "fpr") => true,
5557+
5558+
_ => false,
5559+
}
5560+
});
5561+
5562+
cfg.skip_field(move |s, field| {
5563+
match s {
5564+
// The field 'u' is actually a unnamed union in the AIX header.
5565+
"poll_ctl_ext" if field == "u" => true,
5566+
5567+
// The field 'data' is actually a unnamed union in the AIX header.
5568+
"pollfd_ext" if field == "data" => true,
5569+
5570+
_ => false,
5571+
}
5572+
});
5573+
5574+
cfg.skip_fn(move |name| {
5575+
match name {
5576+
// 'sighandler_t' is not defined on AIX.
5577+
"signal" => true,
5578+
5579+
// The function is only available under macro _USE_IRS in 'netdb.h'.
5580+
"hstrerror" => true,
5581+
5582+
// _ALL_SOURCE signatures for these functions differ from POSIX's
5583+
// on AIX.
5584+
"poll" => true,
5585+
"readlinkat" => true,
5586+
"readlink" => true,
5587+
"pselect" => true,
5588+
5589+
// The AIX signature differs from POSIX's, issue opened.
5590+
"gai_strerror" => true,
5591+
5592+
// AIX implements POSIX-compliant versions of these functions
5593+
// using 'static' wrappers in the headers, which in turn call
5594+
// the corresponding system libc functions prefixed with '_posix_'
5595+
// (e.g., '_posix_aio_read' for 'aio_read').
5596+
// On the Rust side, these functions resolve directly to the
5597+
// POSIX-compliant versions in the system libc. As a result,
5598+
// function pointer comparisons between the C and Rust sides
5599+
// would fail.
5600+
"getpwuid_r" | "getpwnam_r" | "getgrgid_r" | "getgrnam_r"
5601+
| "aio_cancel" | "aio_error" | "aio_fsync" | "aio_read"
5602+
| "aio_return" | "aio_suspend" | "aio_write" | "select" => true,
5603+
5604+
// 'getdtablesize' is a constant in the AIX header but it is
5605+
// a real function in libc which the Rust side is resolved to.
5606+
// The function pointer comparison test would fail.
5607+
"getdtablesize" => true,
5608+
5609+
// FIXME(ctest): Our API is unsound. The Rust API allows aliasing
5610+
// pointers, but the C API requires pointers not to alias.
5611+
// We should probably be at least using '&'/'&mut' here, see:
5612+
// https://github.com/gnzlbg/ctest/issues/68.
5613+
"lio_listio" => true,
5614+
5615+
_ => false,
5616+
}
5617+
});
5618+
5619+
5620+
cfg.volatile_item(|i| {
5621+
use ctest::VolatileItemKind::*;
5622+
match i {
5623+
// 'aio_buf' is of type 'volatile void**' but since we cannot
5624+
// express that in Rust types, we have to explicitly tell the
5625+
// checker about it here.
5626+
StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
5627+
5628+
_ => false,
5629+
}
5630+
});
5631+
5632+
cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
5633+
}

0 commit comments

Comments
 (0)