[Openmcl-devel] interface translator and anonymous unions and structs

R. Matthew Emerson rme at clozure.com
Mon Jul 29 22:16:28 PDT 2024


[TL;DR: probably you should skip this message, but I want to get this written down.]


For a long time now, it’s 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’ve 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’t 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 

(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’t see the ru_maxrss field anywhere.

On other systems that don’t 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.







More information about the Openmcl-devel mailing list