Skip to content

Commit 6c81afa

Browse files
author
Xing Xue
committed
Enable libc-test for AIX and fix definitions/declarations.
1 parent 181b043 commit 6c81afa

File tree

7 files changed

+3402
-524
lines changed

7 files changed

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

0 commit comments

Comments
 (0)