Page 1 of 1

Writing C modules

Posted: Thu Jun 25, 2015 7:13 pm
by Turbinenreiter
It would be nice to have a small Tutorial on how to write C modules for MicroPython.

I'm trying to write on for the Unix port, just to figure out how. I started from the modos.c module.

So far I have modified mymod.c

Code: Select all

#include "py/nlr.h"
#include "py/runtime.h"
#include "py/binary.h"

STATIC mp_obj_t mod_mymod_test(mp_obj_t path_in) {
    return "test";
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_mymod_test_obj, mod_mymod_test);

STATIC const mp_map_elem_t mp_module_mymod_globals_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__mymod) },
    { MP_OBJ_NEW_QSTR(MP_QSTR_test), (mp_obj_t)&mod_mymod_test_obj },
};

STATIC MP_DEFINE_CONST_DICT(mp_module_mymod_globals, mp_module_mymod_globals_table);

const mp_obj_module_t mp_module_mymod = {
    .base = { &mp_type_module },
    .name = MP_QSTR__mymod,
    .globals = (mp_obj_dict_t*)&mp_module_mymod_globals,
};
I added the strings to qstrdefsport.h

Code: Select all

Q(mymod)
Q(test)
I added the source file to the Makefile:

Code: Select all

# source files
SRC_C = \
	main.c \
	gccollect.c \
	unix_mphal.c \
	input.c \
	file.c \
	modos.c \
	alloc.c \
	coverage.c \
	$(SRC_MOD) \
	mymod.c \
I added it to mpconfigport:

Code: Select all

#define MICROPY_PY_MYMOD            (1)

extern const struct _mp_obj_module_t mp_module_mymod;

#if MICROPY_PY_MYMOD
#define MICROPY_PY_MYMOD_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_mymod), (mp_obj_t)&mp_module_mymod },
#else
#define MICROPY_PY_MYMOD_DEF
#endif

#define MICROPY_PORT_BUILTIN_MODULES \
    MICROPY_PY_MYMOD_DEF \
The error I get when compiling:

Code: Select all

CC mymod.c
In file included from ../py/mpstate.h:34:0,
                 from ../py/runtime.h:29,
                 from mymod.c:29:
mymod.c:38:58: error: ‘MP_QSTR__mymod’ undeclared here (not in a function)
     { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__mymod) },
                                                          ^
../py/obj.h:84:56: note: in definition of macro ‘MP_OBJ_NEW_QSTR’
 #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2))
                                                        ^
mymod.c:46:5: error: initializer element is not constant
     .name = MP_QSTR__mymod,
     ^
mymod.c:46:5: error: (near initialization for ‘mp_module_mymod.name’)
../py/mkrules.mk:47: recipe for target 'build/mymod.o' failed
make: *** [build/mymod.o] Error 1
Any ideas welcome, thanks.

Re: Writing C modules

Posted: Thu Jun 25, 2015 7:24 pm
by pfalcon
Well, that one should be obvious after staring at the error message for a second - in

Code: Select all

MP_QSTR__mymod
you have 2 underscores in row, why?

Re: Writing C modules

Posted: Thu Jun 25, 2015 7:31 pm
by Turbinenreiter

Code: Select all

you have 2 underscores in row, why?
Because I was modifying the os module, which is named _os.
Thanks! I were sure I had forgotten to add something some place else.

Re: Writing C modules

Posted: Fri Jun 26, 2015 8:53 am
by Turbinenreiter
So I have this function:

Code: Select all

STATIC mp_obj_t mod_mymod_test(mp_int_t a, mp_int_t b) {
    mp_int_t x = a + b;
    return mp_obj_new_int(x);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_mymod_test_obj, mod_mymod_test);
And this result:

Code: Select all

Micro Python v1.4.4-39-g59fba2d-dirty on 2015-06-26; linux version
>>> import mymod
>>> mymod.test(1,1)
6
>>> mymod.test(2,2)
10
>>> mymod.test(10,5)
32
Now when I do:

Code: Select all

mp_int_t x = a/2 + b/2;
the results are correct.
Is there an explanation to that?
mp_int_t is the integer stuffed into the pointer, right? Does me being on a 64bit machine influence that?

Re: Writing C modules

Posted: Fri Jun 26, 2015 9:48 am
by pfalcon

Code: Select all

STATIC mp_obj_t mod_mymod_test(mp_int_t a, mp_int_t b) {
Implementations of Python function never receive mp_ini_t or anything else, they always receive only mp_obj_t, a generic dynamically typed Python value. You need to test its type wrt to what you expect, then extract value of specific type.

The best way to deal with that is still to find existing code which does close to what you want to do and modify it, instead of writing from scratch. Granted, you won't know how to do it all after modifying just one function, but after doing that dozen of times you'll know good deal of it. And you will be upheld by feeling of progress on each step. Doing it from scratch, you'll be frustrated by "dumb" errors on each step instead ;-).