Modular C
Execution directives

#pragma CMOD entry identifier
#pragma CMOD init identifier
#pragma CMOD atexit identifier
#pragma CMOD at_quick_exit identifier

Modular C has four different directives to specify functions that will be executed at well specified moments during a program run.

The most important of these is the entry directive. Similar to standard C's main, it specifies a ``user'' function that will be executed at the startup of the program and that can receive arguments from the command line. The other three assure that the functions in question are run once before or after all user code that uses the module is executed.

Program entry

A function name that is presented to an entry directive must have one of the following prototypes:

// prototypes that return an exit code
int identifier(void);
int identifier(int, char**);
int identifier(int, char const**);
int identifier(int*, char***);
// prototypes that don't return an exit code
void identifier(void);
void identifier(int, char**);
void identifier(int, char const**);
void identifier(int*, char***);
// for POSIX systems
extern char** environ;
int identifier(int, char**, char**);
void identifier(int, char**, char**);

The first two correspond to those prototypes that are usually allowed for main. The semantic of the others is derived from that.

  • For the prototypes that have a void return type, the function doesn't need to terminate by returning an exit code. In cases of a normal termination (without calling ::C∷lib∷exit) an exit code corresponding to C∷lib∷SUCCESS is returned to the run time environment.
  • The prototypes that have triple pointers can be used to change the whole argument vector.

A Modular C program is not limited to a single entry point. This can be useful for libraries that need to process command line arguments in a certain way before proceeding to execute the user's application:

#pragma CMOD module proj∷run
#pragma CMOD entry toto∷helper∷getops
#pragma CMOD entry processOpts
#pragma CMOD entry enter
void processOpts(int* argcp, char* (*argvp)[*argcp+1]) {
if (*argcp > 1 && !C∷str∷cmp((*argv)[1], "--special")) {
// shift remaning comandline to the left
for (C∷size i = 1; i < *argcp; ++i) {
(*argvp)[i] = (*argvp)[i+1];
// can never fail
int enter(int argc, char const* argv[argc+1]) {
// ... here we go ...

This code has three entry points, two that are defined here and one that comes from another module toto∷helper. These three entries are assembled by modular C to something that is equivalent to the following C code:

int toto∷helper∷getops(int* argcp, char* (*argvp)[*argcp+1]);
void proj∷run∷processOpts(int* argcp, char* (*argvp)[*argcp+1]);
int proj∷run∷(int argc, char const* argv[argc+1]);
int main(int argc, char* argv[argc+1]) {
int ret = toto∷helper∷getops(&argc, &argv);
if (ret) return ret;
proj∷run∷processOpts(&argc, &argv);
return proj∷run∷enter(argc, argv);
Any entry function that returns an exit code that is not C∷lib∷SUCCESS terminates the current program execution.
If a module has several entry directives, the functions are executed in the order in which the directives appear.
The argument count and argument vector are passed on from one entry to the next.