Modular C
Interfacing with platform specific libraries

Synopsis:
#pragma CMOD mimic <header.h>
#pragma CMOD typedef [ abbrev = ] external_name
#pragma CMOD define [ abbrev = ] external_name
#pragma CMOD alias [ abbrev = ] external_name
#pragma CMOD defexp abbrev = expression
#pragma CMOD defstruct abbrev = [ struct ] external_name member0 member1 ...
#pragma CMOD defreg expr = regexp
#pragma CMOD defrex expr = regexp
#pragma CMOD link linker_option

Interfacing libraries and platforms can be a tedious task. Therefore Modular C proposes this set of directives to lift external interfaces into modules.

Targeting a specific platform interface.

The mimic directive receives a C header specification as its argument. Features of this header can then be detected by using the other directives from this set.

#pragma CMOD module proj∷lib
#pragma CMOD mimic <stdlib.h>
#pragma CMOD typedef size = size_t
#pragma CMOD define FAILURE = EXIT_FAILURE
#pragma CMOD define SUCCESS = EXIT_SUCCESS
#pragma CMOD alias allocate= malloc
#pragma CMOD declaration
void* allocate(size s);

This creates an additional interface to features of the standard C library. Namely it mirrors the type size_t as proj∷lib∷size, two macros proj∷lib∷FAILURE and proj∷lib∷SUCCESS, and a function proj∷lib∷allocate. For the latter we give a conventional prototype and an alias directive. This directive ensures that all calls to proj∷lib∷allocate are resolved with the symbol malloc of the standard C library. The define directives extract the macros from the target platform as they are, that is without evaluating the macro on the target platform.

Extracting more complex features of the target platform.

In contrast to a constant directive, all that is described here is done before the module itself is compiled. So the result of all evaluations is available for all code of the module.

  • defexp allows to evaluate an expression as conventional C code during compilation. The result of that evaluation is then place into a macro with macro name abbrev.
  • A defstruct directive extracts the definition of a structure external_name from the target. The known field names are given in the list. The result is a struct declaration with the listed fields at the correct offsets. Gaps that occur, because some field is not known to the programmer or because the structure has padding are filled with spare bytes.
  • defreg and defrex extract a whole pattern that corresponds to a regular expression, where defreg generalizes a define directive and defrex a defexp directive.
#pragma CMOD defreg \2=\(LC_\([a-zA-Z_0-9]*\)\)

extracts all macros that start with LC_ and are followed by alpha-numerics and imports them to a #define without LC_ prefix.

#pragma CMOD defrex \2=\(E\([a-zA-Z][a-zA-Z0-9_]*\)\)

extracts all macros that start with LC_ and are followed by alpha-numerics and imports them to a #define without E prefix. In contrast to the previous, here all E macros are evaluated and the new macro is defined with the numerical value that results from this.