Yes, agreed on Ada.Interfaces and the FFI, it's one of the best. The only thing "missing" is auto-import of the definitions in C header files (but there be different dragons). gcc -fdump-ada-specs works fine, but it's effectively a duplication of (non-authoritative) information. That's fine if you're targeting one system, but when targeting multiple systems a single "with Interfaces.C.Syscall_H" quickly becomes a maze of alternative package bodies and accompanying conditional compilation logic.
> The best way to use Ada, IMO, is type-first: you define your problem-space in the type-system, then use that to solve your problem
I guess that goes to the core of the argument I was trying to make: not that Ada is bad, but that the low-level abstractions in Ada's stdlib are a case of premature optimization. Luckily, I take much less issue with the Numerics and Container parts of the standard library.
> To use the posix-flags, you use the Form parameter
Do you have any examples/documentation on the use of the Form parameter? According to the RM, it's a String argument so I wouldn't have expected it to support flags.
(Also, to correct myself on the signalfd issue: there is GNAT.Signals.Block_Signal to mask signals on the Interrupt_Manager thread)
Ok, so the Form parameter is implementation defined; this was to allow the implementations the 'wriggle room' to interface with the host-system.
For GNAT, these two pieces of documentation are instructive: https://docs.adacore.com/live/wave/gnat_rm/html/gnat_rm/gnat... https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gnat_rm/FORM-String... (This second one is older documentation, but illustrates how platform-specific Form parameters could be used.)
The "maze of alternative package bodies and accompanying conditional compilation logic" is an artifact of C's approach to 'portability' using the preprocessor. Typically, the conditionality should be stable once you abstract it (using the compiler's project-management to select the correct body for a particular configuration) -- As a stupidly trivial example, consider the path separator, for the specification you could have: Then in your the rest of your program, you program against the abstraction of DEPENDENCY.OS (and whatever other dependencies you have, likewise), and thus separate out the implementation dependency.