-
Notifications
You must be signed in to change notification settings - Fork 23
Description
proposal 1 would allow CT sizeof for specified importc types
proposal 2 is just cleanup (related to proposal 1)
proposal 4 would fix $ and repr for importc types
proposal 5 would avoid having to hardcode macro constants defined in C headers (which is brittle and not cross platform), and make them available at CT in a reliable way
proposal 3 is just sugar
proposal 1: introduce {.sizeof.} for importc types
- introduce
{.sizeof.}pragma for importc types, with following meaning:
type Foo1 {.importc.} = object
x1: cint
const s1 = sizeof(Foo1) # CT error: Foo1 is importc and either incomplete or needs to be annotated with sizeof
type Foo2 {.importc, sizeof.} = object
x1: cint # all fields are specicied
c2: cstring
const s2 = sizeof(Foo2) # works
type Foo3 {.importc, sizeof: s2 .} = object
x1: cint # some fields may be missing but sizeof is specified
static: doAssert sizeof(Foo3) == s2-
Note: there should be zero additional code to compute CT sizeof for importc types, it's just the regular CT sizeof except that we remove a CT error depending on presence of
{.sizeof.} -
we add a CT check in codegen to check for errors (eg if some header is updated and fields are added), using
NIM_STATIC_ASSERTC/C++ macro introduced in fix some codegen bugs: NIM_BOOL, NIM_STATIC_ASSERT, --passc:-std=... (etc) Nim#13798:
codegen insertsNIM_STATIC_ASSERT(sizeof(Foo1) == computedSizeofFoo1)right after the header where it's define (or right after its declaration if no header).
proposal 2: deprecate incompleteStruct
[EDIT: this needs to be double checked]
deprecate {.incompleteStruct.} (introduced in 2012), it's the wrong default, it's not observed (AFAIK) as evidenced by face only few structs are annotated with it. It's also un-safe as a lack of annotation would mean a struct is complete, which is often wrong.
proposal 3: {.importc.} for ref/ptr object types
introduce type Foo {.importc.} = ref object, with the meaning that the importc applies to the object, not the ref, to avoid the common boilerplate:
type TFoo {.importc.} = object
x1: cint
c2: cstring
type Foo = ref TFoowhere TFoo doesn't need to be declared.
ditto with ptr.
I don't think there's any use case otherwise for {.importc.} applying to the ref or ptr directly, since a pointer is just a pointer.
proposal 4: {.hidden.} for importc fields that shouldn't be referenced by name in codegen
(previous version of this proposal called it {.importc:"?".})
this is an alternative approach to nim-lang/Nim#13783 for cases where some field names (eg pad, reserved etc) are un-reliable because they're OS-specific, and not part of stable ABI. eg:
# /usr/include/x86_64-linux-gnu/bits/stat.h
struct stat
{
...
#ifdef __x86_64__
__syscall_slong_t __glibc_reserved[3];
#else
# ifndef __USE_FILE_OFFSET64
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
# else
__ino64_t st_ino; /* File serial number. */
# endif
#endif
};
type stat {.importc: "stat", header = "<stat.h>".} =
foo1: cint
reserved {.hidden}: array[4, byte]
foo2: cstring$implementation can query whether a field has a pragma{.hidden.}(and either skip it or refer to it in codegen viaoffsetof)reprshould probably not skip it but useoffsetofto dump its value- keeps coming up, eg https://github.com/nim-lang/Nim/pull/14170/files#r419437649
proposal 5: const CVAR {.importc.}: int
the idea is to replace hardcoded values obtained from reading header files (which may be unreliable, not cross platform, and even wrong if user passes some other --passc option affecting some symbols) by simply calling preprocessor:
const
DARWIN_MAXPATHLEN = 1024by:
const
DARWIN_MAXPATHLEN {.importc: "__DARWIN_MAXPATHLEN", header: "<dirent.h>".}: int
static: doAssert DARWIN_MAXPATHLEN == 1024 # this would passI've implemented this in a POC and it seems to work, but no PR yet.
It is efficient since I'm caching header files and preprocessor output.
EDIT: yet another example use case: nim-lang/Nim#16459 (comment)
Note: regardless of whether we use const CVAR {.importc.}: int, codegen could validate the value we get via NIM_STATIC_ASSERT
Note: this doesn't require libffi