Implementing C-Extensions for GMI

This section describes how to program C-Extensions for the GMI VM.

C-Extensions for GMI

With C-Extensions for GMI, you can address specific needs on iOS platforms, that are not available by default in the Genero language. For example, implement functions to interface with mobile specific hardware like sensors, card readers, scanners, bluetooth, etc.

The runtime system virtual machine build in the GMI for iOS platforms can be extended with the C-Extension technology. The basics to implement C-Extensions are the same for iOS as for Unix/Windows platforms, but there are some differences, explained in this section.

The main difference is that user libraries cannot be loaded dynamically on iOS and thus require a re-link of the GMI binary with the user-defined C-Extension library.

Writing C-Extension sources for GMI

C-Extension source files can be organized in several .c or .m files, but the final library name must be userextension.

For a first test, we recommend that you group all your C-Extension functions in a single sources file called userextension.m.

In the Objective C source file, you should add the following lines, to include typical iOS header files:
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
The Genero runtime system header file must be included as well:
#include "f2c/fglExt.h"
The C-Extension functions must be registered as usual, in a UsrFunction array, defining the number of input and output parameters:
UsrFunction usrFunctions[]={
  {"get_user_info",get_user_info,1,1},
  ...
  {NULL,NULL,0,0}
};

Using iOS C-Extensions in your program

The application code needs to be compiled on the development platform before it is deployed on the iOS device or simulator, by using the C-Extension library build for the development platform.

In your Genero program, import the C-Extension module with IMPORT userextension. You can also omit this IMPORT instruction, because the runtime system tries to find and load the userextension library by default. Note also that C-Extension function have a global scope, so you can omit to prefix the function name with the lib/module name:
IMPORT userextension
MAIN
   DEFINE info STRING
   LET info = get_user_info()
   ...
END MAIN

Compiler behavior regarding IMPORT userextension usage:

Compiling and linking with C-Extensions on the development platform

On the development machine, if you link 42r programs, or if you want the compiler to check for missing symbols (with the -r option), the userextension library must exist in the development environment.

Note: At runtime, on the development machine, the extension library will be loaded at first extension function call. But when the application is deployed on the iOS device, the extension library will be part of the GMI/VM binary (because it is statically linked).

To create the userextension library for the development environment, you must build an Objective-C shared library.

If the C-Extension contains iOS API calls, it will not be possible to compile the extension library as is on the development machine: Write conditional pre-processor macros to hide the iOS specific code, and simulate the function behavior for the development platform:

#ifndef EMULATE_IOS
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
#endif
...
int get_user_info(int pc)
{
    char prop[101];
    char value[101];
    int z = (int) sizeof(prop);
    assert(pc==1);
    popvchar(prop, z);
#ifndef EMULATE_IOS
    ... here goes the iOS specific code ...
#else
    value[0] = '\0';
#endif
    pushvchar(value, (int) strlen(value));
    return 1;
}
Command line example to create a shared library with the XCode environment (note that we define the NOT_IOS_IMPL constant to compile the code without iOS specific API calls):
$ cc -shared -o userextension.dylib userextension.c \
      -D EMULATE_IOS -I $FGLDIR/include -L $FGLDIR/lib -lfgl

Building the iOS app with C extensions

Regular mobile iOS apps are created with the gmibuildtool command-line tool. However, if you want to build an iOS app using C extensions, you must setup a Makefile calling the FGLDIR/lib/Makefile-gmi generic makefile.

For more details, see Building iOS apps with Genero