interface translator and anonymous unions and structs
"R. Matthew Emerson" <[email protected]> Mon, 29 Jul 2024 22:16:28 -0700
| Newsgroups | gmane.lisp.openmcl.devel |
|---|---|
| Message-ID | <[email protected]> |
[TL;DR: probably you should skip this message, but I want to get this =
written down.]
For a long time now, it=E2=80=99s been a goal to stop using the =
interface translator based on a patched GCC 4.0.0.
https://github.com/Clozure/ccl/issues/13
With the help of some others, we=E2=80=99ve made some progress towards =
this. The FreeBSD and Solaris-style platforms can use the new =
translator, and they seem to work fine.
Linux is proving difficult because the header files there frequently use =
anonymous unions and structs.
For example
struct anontest {
int foo;
union {
long int f1;
long int __f1;
};
struct {
long int f2;
long int __f2;
};
};
C11 compilers let you write this. You can refer to the fields of the =
anonymous union and struct directly, like so:
structure anontest a;
a.f1
a.__f1
a.f2
a.__f2
When the translator tool processes this, it outputs
(union ("" 0)
"31_foo.h"
(("f1" (field (long ()) 0 8))
("__f1" (field (long ()) 0 8))))
(struct ("" 0)
"32_foo.h"
(("f2" (field (long ()) 0 8))
("__f2" (field (long ()) 8 8))))
(struct ("" 0)
"anontest"
(("foo" (field (int ()) 0 4))
("" (field (union-ref "31_foo.h") 8 8))
("" (field (struct-ref "32_foo.h") 16 16))))
The numbers at the end of each field spec are offset and size.
However, ccl::parse-standard-ffi-files doesn=E2=80=99t really know what =
to do with this. Maybe we want the translator to generate something like
(struct ("" 0)
"anontest"
(("foo" (field (int ()) 0 4))
("f1" (field (long ()) 8 8))
("__f1" (field (long ()) 8 8))
("f2" (field (long ()) 16 8))
("__f2" (field (long ()) 24 8))))
where we sort of inline the anonymous unions and structs.
This came up when trying to deal with struct rusage on Linux.
The translator produces this
(struct ("" 0)
"rusage"
(("ru_utime" (field (struct-ref "timeval") 0 16))
("ru_stime" (field (struct-ref "timeval") 16 16))
("" (field (union-ref "40_struct_rusage.h") 32 8))
("" (field (union-ref "47_struct_rusage.h") 40 8))
("" (field (union-ref "53_struct_rusage.h") 48 8))
("" (field (union-ref "59_struct_rusage.h") 56 8))
("" (field (union-ref "66_struct_rusage.h") 64 8))
("" (field (union-ref "72_struct_rusage.h") 72 8))
("" (field (union-ref "78_struct_rusage.h") 80 8))
("" (field (union-ref "85_struct_rusage.h") 88 8))
("" (field (union-ref "91_struct_rusage.h") 96 8))
("" (field (union-ref "97_struct_rusage.h") 104 8))
("" (field (union-ref "103_struct_rusage.h") 112 8))
("" (field (union-ref "109_struct_rusage.h") 120 8))
("" (field (union-ref "117_struct_rusage.h") 128 8))
("" (field (union-ref "124_struct_rusage.h") 136 8))
))
where all the union-ref fields look more or less like=20
(union ("" 0)
"40_struct_rusage.h"
(("ru_maxrss" (field (long ()) 0 8))
("__ru_maxrss_word" (field (typedef "__syscall_slong_t") 0 8))
))
The problem is that if we try to write (pref p :rusage.ru_maxrss), we =
don=E2=80=99t see the ru_maxrss field anywhere.
On other systems that don=E2=80=99t do the weird unions, we see =
something like
(struct ("" 0)
"rusage"
(("ru_utime" (field (struct-ref "timeval") 0 16))
("ru_stime" (field (struct-ref "timeval") 16 16))
("ru_maxrss" (field (long ()) 32 8))
("ru_ixrss" (field (long ()) 40 8))
("ru_idrss" (field (long ()) 48 8))
("ru_isrss" (field (long ()) 56 8))
("ru_minflt" (field (long ()) 64 8))
("ru_majflt" (field (long ()) 72 8))
("ru_nswap" (field (long ()) 80 8))
("ru_inblock" (field (long ()) 88 8))
("ru_oublock" (field (long ()) 96 8))
("ru_msgsnd" (field (long ()) 104 8))
("ru_msgrcv" (field (long ()) 112 8))
("ru_nsignals" (field (long ()) 120 8))
("ru_nvcsw" (field (long ()) 128 8))
("ru_nivcsw" (field (long ()) 136 8))
))
which is a lot more straightforward.