Python to C module generator

Hi OpenMV users,

I want to share this small project that can be useful for advanced OpenMV users that want to add new C module to the system.
It allows to automatically generate micropython C module API (MicroPython external C modules — MicroPython 1.19.1 documentation ) directly from python code.
It also has interesting features that can be used for all python programmers.

The basic idea is that you can define your C module API in a simpler way in python and then use same python program to print needed C module API.
This flowchart show how it works:

The complete source is available on a jupyter here (we are in 2020!):

For example, from python function:

def foo():
    pass

You obtain the C code:

/****************************************************************************
 * File:	modfoo.c
 * Brief:		
  * Author:		
 ****************************************************************************/
/****************************************************************************
 * Private Includes.
 ****************************************************************************/
#include	"py/obj.h"
#include	"py/runtime.h"

/****************************************************************************
 * Private Defines.
 ****************************************************************************/
#define	MODULE_FOO_ENABLED	(1)
MP_REGISTER_MODULE(MP_QSTR_foo, foo_module, MODULE_FOO_ENABLED );

/****************************************************************************
 * Private Types.
 ****************************************************************************/

/****************************************************************************
 * Private Functions Declarations.
 ****************************************************************************/
STATIC mp_obj_t foo_foo();

/****************************************************************************
 * Private Variables Declarations.
 ****************************************************************************/
STATIC const mp_obj_fun_builtin_fixed_t foo_foo_obj;
const mp_map_elem_t foo_globals_table[];
STATIC const mp_obj_dict_t foo_globals;
const mp_obj_module_t foo_module;

/****************************************************************************
 * Private Variables Definitions.
 ****************************************************************************/
STATIC MP_DEFINE_CONST_FUN_OBJ_0( foo_foo_obj, foo_foo );
const mp_map_elem_t foo_globals_table[] = 
{
    { MP_OBJ_NEW_QSTR( MP_QSTR___name__ ), MP_OBJ_NEW_QSTR( MP_QSTR_foo ) },
    { MP_OBJ_NEW_QSTR( MP_QSTR_foo ), (mp_obj_t)&foo_foo_obj },
};
const mp_obj_module_t foo_module = 
{
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t*)&foo_globals,
};

/****************************************************************************
 * Public Variables Definitions.
 ****************************************************************************/
STATIC MP_DEFINE_CONST_DICT( foo_globals, foo_globals_table );

/****************************************************************************
 * Private Functions Definitions.
 ****************************************************************************/
STATIC mp_obj_t foo_foo()
{
    // ... 
    return mp_const_none;
}


/****************************************************************************
 * Public Functions Definitions.
 ****************************************************************************/

This code should compile as is, but of course you need to add your function code.

How it works??
First, uses python instrospection feature to build an Abstrac Syntax Tree from the provided python source code.
Second, traverses this AST for generated the C code.

Lets explain with more detail:
The visitor is defined here. It uses the python “ast” standart pakacge for parse the source code, directly from string.
Basically it traverses all source code from top to down and executes an user function for each element found.
Here the user function simply stores all needed info like type, name, attributes…

The next module is the module class. It is basically a container.
It stores the AST in a usable way and also have the methods for print it in a human readable way.

The FileBuilder class helps to generate C code.
This is very useful code, I created about 8 years ago and Im still using, without almost any change, in a lot of different automation generator tools that I made time to time.
Is mainly a placeholder, where you can add for example functions with their names, params and body, also variables, constants… and after that you request the C code to obtain header and source files as a string.
It generates complete files with different sections (includes, defines, global, variables, functions…) a in a way that always compile and reducing scope visibility as much as possible.

The build_module functios glues all above together.
It takes a Module object, then creates FileBuilder object and add all needed elements, “includes”, “make_new” functions, “print” functions, locals tables…as needed in C module API examples.

And that is all you need. Here is a complete example with more features:

Hope ppl can understand my “200 words” english level :wink:

Thanks

Hi jgpeiro,

You should make a github repo with a readme and then post a link to that here. You’ll get a lot more hits! Also, you should share this with the circuit python and whole micro python community.

You are right.
I will upload all my toy projects to github, for sure it can be more useful than screenshots on my linkedin profile.
About post on micropython forum, I already did half year ago, but nobody answer me… :cry:
https://forum.micropython.org/viewtopic.php?t=7427&p=42351

Yeah, the MicroPython forum doesn’t really have any activity.