examples: Add example code for user C modules, both C and C++.

Add working example code to provide a starting point for users with files
that they can just copy, and include the modules in the coverage test to
verify the complete user C module build functionality.  The cexample module
uses the code originally found in cmodules.rst, which has been updated to
reflect this and partially rewritten with more complete information.
This commit is contained in:
stijn
2020-10-21 11:13:47 +02:00
committed by Damien George
parent fad4079778
commit 25c4563f26
10 changed files with 205 additions and 99 deletions

View File

@@ -0,0 +1,34 @@
// Include MicroPython API.
#include "py/runtime.h"
// This is the function which will be called from Python as cexample.add_ints(a, b).
STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// Extract the ints from the micropython input objects.
int a = mp_obj_get_int(a_obj);
int b = mp_obj_get_int(b_obj);
// Calculate the addition and convert to MicroPython object.
return mp_obj_new_int(a + b);
}
// Define a Python reference to the function above.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
// Define module object.
const mp_obj_module_t example_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&example_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);

View File

@@ -0,0 +1,9 @@
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)

View File

@@ -0,0 +1,17 @@
extern "C" {
#include <examplemodule.h>
// Here we implement the function using C++ code, but since it's
// declaration has to be compatible with C everything goes in extern "C" scope.
mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj) {
// Prove we have (at least) C++11 features.
const auto a = mp_obj_get_int(a_obj);
const auto b = mp_obj_get_int(b_obj);
const auto sum = [&]() {
return mp_obj_new_int(a + b);
} ();
// Prove we're being scanned for QSTRs.
mp_obj_t tup[] = {sum, MP_ROM_QSTR(MP_QSTR_hellocpp)};
return mp_obj_new_tuple(2, tup);
}
}

View File

@@ -0,0 +1,25 @@
#include <examplemodule.h>
// Define a Python reference to the function we'll make available.
// See example.cpp for the definition.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t cppexample_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cppexample) },
{ MP_ROM_QSTR(MP_QSTR_cppfunc), MP_ROM_PTR(&cppfunc_obj) },
};
STATIC MP_DEFINE_CONST_DICT(cppexample_module_globals, cppexample_module_globals_table);
// Define module object.
const mp_obj_module_t cppexample_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&cppexample_module_globals,
};
// Register the module to make it available in Python.
MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, MODULE_CPPEXAMPLE_ENABLED);

View File

@@ -0,0 +1,5 @@
// Include MicroPython API.
#include "py/runtime.h"
// Declare the function we'll make available in Python as cppexample.cppfunc().
extern mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj);

View File

@@ -0,0 +1,12 @@
CPPEXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add our source files to the respective variables.
SRC_USERMOD += $(CPPEXAMPLE_MOD_DIR)/examplemodule.c
SRC_USERMOD_CXX += $(CPPEXAMPLE_MOD_DIR)/example.cpp
# Add our module directory to the include path.
CFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
# We use C++ features so have to link against the standard library.
LDFLAGS_USERMOD += -lstdc++