Skip to content

Commit 05cc796

Browse files
committed
Auto merge of #2034 - nielx:haiku-native, r=JohnTitor
Haiku: add definitions for the Haiku's native sytem API. On the Haiku platform, the POSIX (and BSD) API coexists with the native API, that has its origins on the BeOS platform. Unlike other UNIX-like platforms, the native API is not an extension of the POSIX API, but instead exists sui generis, and many of the POSIX concepts have their own native variety, with relatively limited interoperability. Nonetheless, the native API coexists in the same library as the standard C and POSIX functions, namely libroot.so, and therefore this crate is a good place to add bindings to it. This commit implements most of Haiku's support kit, the most important parts of the kernel kit, and a part of the storage kit.
2 parents b43486f + 813d7d8 commit 05cc796

File tree

5 files changed

+1543
-65
lines changed

5 files changed

+1543
-65
lines changed

libc-test/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ default-features = false
1111
[build-dependencies]
1212
cc = "1.0.61"
1313
# FIXME: Use fork ctest until the maintainer gets back.
14-
ctest2 = "0.3"
14+
ctest2 = "0.4"
1515

1616
[features]
1717
default = [ "std" ]

libc-test/build.rs

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fn do_ctest() {
3232
t if t.contains("dragonfly") => return test_dragonflybsd(t),
3333
t if t.contains("emscripten") => return test_emscripten(t),
3434
t if t.contains("freebsd") => return test_freebsd(t),
35+
t if t.contains("haiku") => return test_haiku(t),
3536
t if t.contains("linux") => return test_linux(t),
3637
t if t.contains("netbsd") => return test_netbsd(t),
3738
t if t.contains("openbsd") => return test_openbsd(t),
@@ -2946,3 +2947,283 @@ fn which_freebsd() -> Option<i32> {
29462947
_ => None,
29472948
}
29482949
}
2950+
2951+
fn test_haiku(target: &str) {
2952+
assert!(target.contains("haiku"));
2953+
2954+
let mut cfg = ctest_cfg();
2955+
cfg.flag("-Wno-deprecated-declarations");
2956+
cfg.define("__USE_GNU", Some("1"));
2957+
2958+
// POSIX API
2959+
headers! { cfg:
2960+
"alloca.h",
2961+
"arpa/inet.h",
2962+
"arpa/nameser.h",
2963+
"arpa/nameser_compat.h",
2964+
"assert.h",
2965+
"bsd_mem.h",
2966+
"complex.h",
2967+
"ctype.h",
2968+
"dirent.h",
2969+
"div_t.h",
2970+
"dlfcn.h",
2971+
"endian.h",
2972+
"errno.h",
2973+
"fcntl.h",
2974+
"fenv.h",
2975+
"fnmatch.h",
2976+
"fts.h",
2977+
"ftw.h",
2978+
"getopt.h",
2979+
"glob.h",
2980+
"grp.h",
2981+
"inttypes.h",
2982+
"iovec.h",
2983+
"langinfo.h",
2984+
"libgen.h",
2985+
"libio.h",
2986+
"limits.h",
2987+
"locale.h",
2988+
"malloc.h",
2989+
"malloc_debug.h",
2990+
"math.h",
2991+
"memory.h",
2992+
"monetary.h",
2993+
"net/if.h",
2994+
"net/if_dl.h",
2995+
"net/if_media.h",
2996+
"net/if_tun.h",
2997+
"net/if_types.h",
2998+
"net/route.h",
2999+
"netdb.h",
3000+
"netinet/icmp6.h",
3001+
"netinet/in.h",
3002+
"netinet/ip.h",
3003+
"netinet/ip6.h",
3004+
"netinet/ip_icmp.h",
3005+
"netinet/ip_var.h",
3006+
"netinet/tcp.h",
3007+
"netinet/udp.h",
3008+
"netinet6/in6.h",
3009+
"nl_types.h",
3010+
"null.h",
3011+
"poll.h",
3012+
"pthread.h",
3013+
"pwd.h",
3014+
"regex.h",
3015+
"resolv.h",
3016+
"sched.h",
3017+
"search.h",
3018+
"semaphore.h",
3019+
"setjmp.h",
3020+
"shadow.h",
3021+
"signal.h",
3022+
"size_t.h",
3023+
"spawn.h",
3024+
"stdint.h",
3025+
"stdio.h",
3026+
"stdlib.h",
3027+
"string.h",
3028+
"strings.h",
3029+
"sys/cdefs.h",
3030+
"sys/file.h",
3031+
"sys/ioctl.h",
3032+
"sys/ipc.h",
3033+
"sys/mman.h",
3034+
"sys/msg.h",
3035+
"sys/param.h",
3036+
"sys/poll.h",
3037+
"sys/resource.h",
3038+
"sys/select.h",
3039+
"sys/sem.h",
3040+
"sys/socket.h",
3041+
"sys/sockio.h",
3042+
"sys/stat.h",
3043+
"sys/statvfs.h",
3044+
"sys/time.h",
3045+
"sys/timeb.h",
3046+
"sys/times.h",
3047+
"sys/types.h",
3048+
"sys/uio.h",
3049+
"sys/un.h",
3050+
"sys/utsname.h",
3051+
"sys/wait.h",
3052+
"syslog.h",
3053+
"tar.h",
3054+
"termios.h",
3055+
"time.h",
3056+
"uchar.h",
3057+
"unistd.h",
3058+
"utime.h",
3059+
"wchar.h",
3060+
"wchar_t.h",
3061+
"wctype.h"
3062+
}
3063+
3064+
// BSD Extensions
3065+
headers! { cfg:
3066+
"pty.h",
3067+
}
3068+
3069+
// Native API
3070+
headers! { cfg:
3071+
"kernel/OS.h",
3072+
"kernel/fs_attr.h",
3073+
"kernel/fs_index.h",
3074+
"kernel/fs_info.h",
3075+
"kernel/fs_query.h",
3076+
"kernel/fs_volume.h",
3077+
"kernel/image.h",
3078+
"storage/StorageDefs.h",
3079+
"support/Errors.h",
3080+
"support/SupportDefs.h",
3081+
"support/TypeConstants.h"
3082+
}
3083+
3084+
cfg.skip_struct(move |ty| {
3085+
match ty {
3086+
// FIXME: actually a union
3087+
"sigval" => true,
3088+
// FIXME: locale_t does not exist on Haiku
3089+
"locale_t" => true,
3090+
// FIXME: rusage has a different layout on Haiku
3091+
"rusage" => true,
3092+
// FIXME?: complains that rust aligns on 4 byte boundary, but
3093+
// Haiku does not align it at all.
3094+
"in6_addr" => true,
3095+
// The d_name attribute is an array of 1 on Haiku, with the
3096+
// intention that the developer allocates a larger or smaller
3097+
// piece of memory depending on the expected/actual size of the name.
3098+
// Other platforms have sensible defaults. In Rust, the d_name field
3099+
// is sized as the _POSIX_MAX_PATH, so that path names will fit in
3100+
// newly allocated dirent objects. This breaks the automated tests.
3101+
"dirent" => true,
3102+
3103+
_ => false,
3104+
}
3105+
});
3106+
3107+
cfg.skip_type(move |ty| {
3108+
match ty {
3109+
// FIXME: locale_t does not exist on Haiku
3110+
"locale_t" => true,
3111+
// These cause errors, to be reviewed in the future
3112+
"sighandler_t" => true,
3113+
"pthread_t" => true,
3114+
"pthread_condattr_t" => true,
3115+
"pthread_mutexattr_t" => true,
3116+
"pthread_rwlockattr_t" => true,
3117+
_ => false,
3118+
}
3119+
});
3120+
3121+
cfg.skip_fn(move |name| {
3122+
// skip those that are manually verified
3123+
match name {
3124+
// FIXME: https://github.com/rust-lang/libc/issues/1272
3125+
"execv" | "execve" | "execvp" | "execvpe" => true,
3126+
// FIXME: does not exist on haiku
3127+
"open_wmemstream" => true,
3128+
"mlockall" | "munlockall" => true,
3129+
"tcgetsid" => true,
3130+
"cfsetspeed" => true,
3131+
// ignore for now, will be part of Haiku R1 beta 3
3132+
"mlock" | "munlock" => true,
3133+
// returns const char * on Haiku
3134+
"strsignal" => true,
3135+
3136+
_ => false,
3137+
}
3138+
});
3139+
3140+
cfg.skip_const(move |name| {
3141+
match name {
3142+
// FIXME: these constants do not exist on Haiku
3143+
"DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK"
3144+
| "DT_REG" | "DT_LNK" | "DT_SOCK" => true,
3145+
"USRQUOTA" | "GRPQUOTA" => true,
3146+
"SIGIOT" => true,
3147+
"ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM"
3148+
| "ATF_PUBL" | "ATF_USETRAILERS" => true,
3149+
// Haiku does not have MAP_FILE, but rustc requires it
3150+
"MAP_FILE" => true,
3151+
// The following does not exist on Haiku but is required by
3152+
// several crates
3153+
"FIOCLEX" => true,
3154+
// just skip this one, it is not defined on Haiku beta 2 but
3155+
// since it is meant as a mask and not a parameter it can exist
3156+
// here
3157+
"LOG_PRIMASK" => true,
3158+
// not defined on Haiku, but [get|set]priority is, so they are
3159+
// useful
3160+
"PRIO_MIN" | "PRIO_MAX" => true,
3161+
//
3162+
_ => false,
3163+
}
3164+
});
3165+
3166+
cfg.skip_field(move |struct_, field| {
3167+
match (struct_, field) {
3168+
// FIXME: the stat struct actually has timespec members, whereas
3169+
// the current representation has these unpacked.
3170+
("stat", "st_atime") => true,
3171+
("stat", "st_atime_nsec") => true,
3172+
("stat", "st_mtime") => true,
3173+
("stat", "st_mtime_nsec") => true,
3174+
("stat", "st_ctime") => true,
3175+
("stat", "st_ctime_nsec") => true,
3176+
("stat", "st_crtime") => true,
3177+
("stat", "st_crtime_nsec") => true,
3178+
3179+
// these are actually unions, but we cannot represent it well
3180+
("siginfo_t", "sigval") => true,
3181+
("sem_t", "named_sem_id") => true,
3182+
("sigaction", "sa_sigaction") => true,
3183+
("sigevent", "sigev_value") => true,
3184+
3185+
// skip these enum-type fields
3186+
("thread_info", "state") => true,
3187+
("image_info", "image_type") => true,
3188+
_ => false,
3189+
}
3190+
});
3191+
3192+
cfg.skip_roundtrip(move |s| match s {
3193+
// FIXME: for some reason the roundtrip check fails for cpu_info
3194+
"cpu_info" => true,
3195+
_ => false,
3196+
});
3197+
3198+
cfg.type_name(move |ty, is_struct, is_union| {
3199+
match ty {
3200+
// Just pass all these through, no need for a "struct" prefix
3201+
"area_info" | "port_info" | "port_message_info" | "team_info"
3202+
| "sem_info" | "team_usage_info" | "thread_info" | "cpu_info"
3203+
| "system_info" | "object_wait_info" | "image_info"
3204+
| "attr_info" | "index_info" | "fs_info" | "FILE" | "DIR"
3205+
| "Dl_info" => ty.to_string(),
3206+
3207+
// is actually a union
3208+
"sigval" => format!("union sigval"),
3209+
t if is_union => format!("union {}", t),
3210+
t if t.ends_with("_t") => t.to_string(),
3211+
t if is_struct => format!("struct {}", t),
3212+
t => t.to_string(),
3213+
}
3214+
});
3215+
3216+
cfg.field_name(move |struct_, field| {
3217+
match field {
3218+
// Field is named `type` in C but that is a Rust keyword,
3219+
// so these fields are translated to `type_` in the bindings.
3220+
"type_" if struct_ == "object_wait_info" => "type".to_string(),
3221+
"type_" if struct_ == "sem_t" => "type".to_string(),
3222+
"type_" if struct_ == "attr_info" => "type".to_string(),
3223+
"type_" if struct_ == "index_info" => "type".to_string(),
3224+
"image_type" if struct_ == "image_info" => "type".to_string(),
3225+
s => s.to_string(),
3226+
}
3227+
});
3228+
cfg.generate("../src/lib.rs", "main.rs");
3229+
}

0 commit comments

Comments
 (0)