Rant about NDK includes – types of library bases in definitions of variadic API functions

Online Status

While testing my "GCC-Pack" (easy to deploy m68k-amigaos native GCC 2.95.3 compiler with tools and Installer script), I have encountered some unexpected behaviour. A simple code like this:

Printf("Hello world!\n");

generated warning about passing argument 1 of ___Printf from incompatible pointer type. Looks weird, like problem with char signedness, or some const. But no, the key is that the string is not the first argument of ___Printf(), the first argument is library base, DOSBase in this case. And it is typed in inline/dos.h as struct DosLibrary* instead of just struct Library*. In my code it is declared as struct Library* obviously. Why I consider it wrong:

  • code backward compatibility is broken, at least comparing to older style inlines for GCC.
  • typed library bases are just historical artifact, in theory they should be black boxes.
  • most programs use them exactly like that, just for calling API functions.
  • C type of library base is irrelevant when making a call, see inlines for non-variadic functions, where library bases are typecasted to char*.

This problem exists for all API functions which:

  • are variadic.
  • are from a library, which has dedicated type for its base structure.

How to fix it? My proposal is to add a typecast to macros like Printf(). In inline/dos.h it is defined as follows:

#define Printf(format...) ___Printf(DOS_BASE_NAME, format)

I would change it to:

#define Printf(format...) ___Printf((struct DosLibrary*)DOS_BASE_NAME, format)

This way it does not matter if one has DOSBase defined as struct Library*, or (auto)defined as struct DosLibrary*.

Online Status

Another, unrelated to the above, NDK include problem, <graphics/gels.h> this time.

LONG (* __STDARGS__ collPtrs[16]) __CLIB_PROTOTYPE((struct VSprite*, struct VSprite*));

This line produces warning about ignored __stkparm__ attribute. Seems the expression is too complex for GCC 2.95.3. Similar expression eariler in the same file, where a single function pointer is declared, is OK. Array of such pointers pose a problem. It can be mitigated by defining a type for these functions:

typedef LONG (* __STDARGS__ collfunc) __CLIB_PROTOTYPE((struct VSprite*, struct VSprite*));

and then simplifying array definition like this:

collfunc collPtrs[16];

Online Status

Thank you for diving into the header files, they are what they are, I'm afraid. We have to support not just GCC, there is also vbcc (which has its own specific inline header files) and the handful of C90 compilers (SAS/C and Aztec 'C' among them, for example) which play by their own rules. The bottom line is that the interface files tilt towards the compiler generation which was used to build the operating system in the late 1980'ies and 1990'ies. This is how we build the operating system today.

From what I learned during the past few NDK 3.2 revisions, there is no straightforward way to make GCC and vbcc play nice unless you are very strict in how your data structure pointer types for both libraries and devices are declared. The inline header files declare these types if you let them do it for you. If you follow their direction, the number of hundreds of mostly pointless compiler warnings will collapse to mere tens of pointless compiler warnings which, however, will be very annoying indeed.

While not intended as such, this is the price you have to pay if you do not use a C90 compiler. Another update to the NDK 3.2 is currently in the works, and while it already has taken more than a year to make it happen, there is hope that we'll be able to release it this year. The header files have been reworked again, which also includes changes to the interface files.

While this may sound like it could shape up to be something useful, I suspect that the constraints which apply to the header files (numerous antique C90 compilers supported, C++ support not particularly developed, C99 and beyond still somewhat experimental), I hope you'll be around to review what we cooked up and suggest practical changes which cater for the weirdness of the header files. We've come a long way since the AmigaOS NDK 3.9 already. We need to travel further, though.

Online Status

I understand. Currently the installation script of my pack informs user that he is expected to download the NDK from the official site manually and place it somewhere on a disk. Then user selects the NDK archive in the script. Script extracts needed includes and copies them to destination.

I can patch the above problems from the script before copying. I could also distribute patched version inside my pack. I assume however that redistribution of (modified) parts of NDK is not allowed, so extracting from archive and patching is the way to go.

It should be also noted that <inline/_libraryname_.h> files are used by GCC only. Modifying them has no influence on other compilers.