@@ -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