hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

MPY C Extension - Cannot do division or modulo

Mon Sep 27, 2021 2:21 pm

There is a problem with building Native C Extension Modules for MicroPython for the Pico and RP2040. Using addition, subtraction and multiplication works but division and modulo produce linking errors, prevent the '.mpy' file being created -

Code: Select all

#include "py/dynruntime.h"

STATIC mp_obj_t div(mp_obj_t lhs_obj, mp_obj_t rhs_obj) {
    mp_int_t lhs = mp_obj_get_int(lhs_obj);
    mp_int_t rhs = mp_obj_get_int(rhs_obj);
    mp_int_t res = lhs / rhs;                                      // <---
    return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(div_obj, div);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
    MP_DYNRUNTIME_INIT_ENTRY
    mp_store_global(MP_QSTR_div, MP_OBJ_FROM_PTR(&div_obj));
    MP_DYNRUNTIME_INIT_EXIT
}

Code: Select all

pi@Pi3B:~/pico/micropython/ports/rp2/modules-c/divbug $ make
GEN build/divbug.config.h
CC divbug.c
LINK build/divbug.o
LinkError: build/divbug.o: undefined symbol: __aeabi_idiv
make: *** [/home/pi/pico/micropython/py/dynruntime.mk:154: build/divbug.native.mpy] Error 1
Googling reveals this is a fairly common problem and down to not specifying an appropriate library to be linked. Seems reasonable and the resolution appears obvious. Unfortunately I have no idea what the library would be, where it would be found, or how to specify it when building a Native C Extension Module for the RP2040.

I couldn't find any examples out there which would show me what needs to be done.

I tried providing a local '__aeabi_idiv' function ( altually '__aeabi_uidiv' and '__aeabi_uidivmod' for what I am actually doing ) which compiles, but hangs my Pico when called, so I guess not correctly implemented.

I have asked on the MicroPython forum - https://forum.micropython.org/viewtopic ... 21&t=11182 - but no replies so far.

If anyone here has solved this problem, or can help, I would be grateful for such assistance.

User avatar
jahboater
Posts: 7375
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: MPY C Extension - Cannot do division or modulo

Mon Sep 27, 2021 3:36 pm

May be all different on the Pico, but in case it helps ...
ldd on a pi1 for a tiny program with division yields:

Code: Select all

$ ldd try
	/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v6l.so (0xb6f4a000)
	libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6dfc000)
	/lib/ld-linux-armhf.so.3 (0xb6f5d000)
I think the division routines are in a GCC internal library of some sort.
The signed integer division function is called like this:

Code: Select all

  54                    @ try.c:36:     printf("%d\n", i/j );
  55 002c 0610A0E1              mov     r1, r6  @, j
  56 0030 0500A0E1              mov     r0, r5  @, i
  57 0034 FEFFFFEB              bl      __aeabi_idiv            
  58 0038 0010A0E1              mov     r1, r0  @ tmp131,
  59 003c 0700A0E1              mov     r0, r7  @ tmp127 "%\n"
  60 0040 FEFFFFEB              bl      printf          

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Mon Sep 27, 2021 5:45 pm

jahboater wrote:
Mon Sep 27, 2021 3:36 pm
The signed integer division function is called like this:
Many thanks for that. It prompted me to look at exactly what code was being generated.

Most importantly it revealed my earlier attempt hadn't hung; that was MicroPython caching imports which meant it was running code other than I though it was. I had been on the right track all along.

Ignoring repeated subtraction as merely being a poor choice of algorithm I have arrived at this -

Code: Select all

#include "py/dynruntime.h"

int __aeabi_idiv(int lhs, int rhs) {
    int res = 0;
    while (lhs >= rhs) {
        lhs -= rhs;
        res += 1;
    }
    return res;
}

int __aeabi_idivmod(int lhs, int rhs) {
    while (lhs >= rhs) {
       lhs -= rhs;
    }
    __asm("mov r1, r0" "\n");'
    return lhs;
}

uint __aeabi_uidiv(uint lhs, uint rhs) {
    uint res = 0;
    while (lhs >= rhs) {
        lhs -= rhs;
        res += 1;
    }
    return res;
}

uint __aeabi_uidivmod(uint lhs, uint rhs) {
    while (lhs >= rhs) {
       lhs -= rhs;
    }
    __asm("mov r1, r0" "\n");'
    return lhs;
}

STATIC mp_obj_t div(mp_obj_t lhs_obj, mp_obj_t rhs_obj) {
    int lhs = mp_obj_get_int(lhs_obj);
    int rhs = mp_obj_get_int(rhs_obj);
    int res = lhs / rhs;
    return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(div_obj, div);

STATIC mp_obj_t mod(mp_obj_t lhs_obj, mp_obj_t rhs_obj) {
    int lhs = mp_obj_get_int(lhs_obj);
    int rhs = mp_obj_get_int(rhs_obj);
    int res = lhs % rhs;
    return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_obj, mod);

STATIC mp_obj_t udiv(mp_obj_t lhs_obj, mp_obj_t rhs_obj) {
    uint lhs = mp_obj_get_int(lhs_obj);
    uint rhs = mp_obj_get_int(rhs_obj);
    uint res = lhs / rhs;
    return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(udiv_obj, udiv);

STATIC mp_obj_t umod(mp_obj_t lhs_obj, mp_obj_t rhs_obj) {
    uint lhs = mp_obj_get_int(lhs_obj);
    uint rhs = mp_obj_get_int(rhs_obj);
    uint res = lhs % rhs;
    return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(umod_obj, umod);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
    MP_DYNRUNTIME_INIT_ENTRY
    mp_store_global(MP_QSTR_div,  MP_OBJ_FROM_PTR(&div_obj));
    mp_store_global(MP_QSTR_mod,  MP_OBJ_FROM_PTR(&mod_obj));
    mp_store_global(MP_QSTR_udiv, MP_OBJ_FROM_PTR(&udiv_obj));
    mp_store_global(MP_QSTR_umod, MP_OBJ_FROM_PTR(&umod_obj));
    MP_DYNRUNTIME_INIT_EXIT
}
The __asm("mov r1, r0" "\n");' before the modulo returns are because GCC expects the result in r1 and it's actually in r0. I'm not sure how appropriate, reliable, safe or risky that is but it works -

Code: Select all

000000e0 <__aeabi_idivmod>:
  e0:	4288      	cmp	r0, r1
  e2:	da01      	bge.n	e8 <__aeabi_idivmod+0x8>
  e4:	1c01      	adds	r1, r0, #0               <-- Fix to return in r1
  e6:	4770      	bx	lr
  e8:	1a40      	subs	r0, r0, r1
  ea:	e7f9      	b.n	e0 <__aeabi_idivmod>

00000034 <mod>:
  ... snip ...
  4e:	0001      	movs	r1, r0
  50:	0038      	movs	r0, r7
  52:	f7ff fffe 	bl	e0 <__aeabi_idivmod>
  56:	6923      	ldr	r3, [r4, #16]
  58:	0008      	movs	r0, r1                   <-- Wants return in r1
  5a:	2102      	movs	r1, #2
  5c:	4798      	blx	r3
So sort of solved, and more so if I can find an efficient division algorithm which handles negatives, division by zero etc. Would still be nice if I didn't have to provide my own implementation, could solve it by linking.

User avatar
jahboater
Posts: 7375
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: MPY C Extension - Cannot do division or modulo

Mon Sep 27, 2021 8:03 pm

There should be plenty of division code around on the net for handwriting these functions, the source of GCC might be a place to look.

Can I suggest

Code: Select all

__asm("mov r1, r0" "\n");
should be changed to

Code: Select all

__asm("mov r1, r0" ::: "r1");
to tell the compiler that R1 has been altered?
Otherwise it may fail at random times in the future!
The complete absence of colons might make GCC assume all registers are updated which would be very slow, but that's not decided upon as far as I know.

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Mon Sep 27, 2021 10:12 pm

jahboater wrote:
Mon Sep 27, 2021 8:03 pm
There should be plenty of division code around on the net for handwriting these functions, the source of GCC might be a place to look.
I would have thought so but I didn't find much, but I didn't really have the time for a comprehensive search. Most library code seems to be heavily optimised and obtuse Assembler though I presume that should be easy enough if ARM-based, though as you noticed this isn't my area of expertise ...
jahboater wrote:
Mon Sep 27, 2021 8:03 pm
Can I suggest

Code: Select all

__asm("mov r1, r0" ::: "r1");
to tell the compiler that R1 has been altered?
Otherwise it may fail at random times in the future!
Thanks again.

vikK4yHabbe7L
Posts: 24
Joined: Sun Jan 31, 2021 3:33 pm

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 1:37 am

The routine is part of 'libgcc.a' under arm-none-eabi-gcc/9-2019q4/lib/gcc/arm-none-eabi/9.2.1 (yeah, I have an old version).

Code: Select all

$ arm-none-eabi-nm libgcc.a | grep idiv
         U __aeabi_idiv0
00000000 T __aeabi_uidiv
000000f4 T __aeabi_uidivmod
00000000 T __aeabi_idiv                <<< that's it
         U __aeabi_idiv0
00000128 T __aeabi_idivmod
         U __aeabi_idiv0
         U __aeabi_idiv0
00000000 W __aeabi_idiv0
         U __aeabi_idiv
         U __aeabi_idiv
         U __aeabi_idiv
         U __aeabi_uidiv
         U __aeabi_uidiv
         U __aeabi_idiv
         U __aeabi_uidiv
So the question is... why isn't cmake telling make to get things from libgcc.a ?
Mike /

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 2:11 pm

vikK4yHabbe7L wrote:
Tue Sep 28, 2021 1:37 am
So the question is... why isn't cmake telling make to get things from libgcc.a ?
It's not a 'cmake' issue. That builds MicroPython perfectly well, handles divisions and modulos in its source and links to the required '__aeabi_idivmod' and friends as required and expected. Actually it seems to link to '__wrap__aeabi_idivmod' etc, but it all works as one would expect.

The issue here is building Native C Extension Modules which are built outside of the 'cmake' MicroPython build. These use 'make' and a 'Makefile' to take C source and create a '.mpy' file which can be copied to the Pico file system which can be imported as if they were '.py' modules. In theory, as easy as '.py' with the benefit of native execution and not having to touch or even build the MicroPython source code.

To allow the importing of a '.mpy' file that file has to conform with what MicroPython allows, and that means a limited set of functions which are defined and usable for the C source. So things like 'mp_obj_str_get_str' are defined, available and usable, but 'strlen' isn't. If one wants to use 'strlen' one has to provide it in the source. Its no good using #include "strings.h" because, while that will allow the code to compile, a 'strlen' implementation won't be found when it comes to linking.

The problem here is that when 'make' is run and a division or modulo is performed, GCC emits calls to '__aeabi_idivmod' etc but the MicroPython provided linker used to create the final '.mpy' file has no clue what they are. They are not catered for by MicroPython when imported, so are reported as functions the user needs to define in their C code but hasn't. That's fair enough for things like 'strlen' but it's a PITA when division and modulo requires doing that.

I expect the solution is to make MicroPython aware of needing to provide and support ''__aeabi_idivmod' etc for the Pico but I have no idea of how to do that and it would be something which really needs to be done by the MicroPython team. Until then the only option is to provide the missing routines oneself in the C source or an include file.

I believe I have achieved that because it works when tested from a module wrapper and are a lot quicker than MicroPython's in-built division and modulo operators which need to be a lot more generic. But, for some reason, not in more involved code where I would like them to work and I haven't got to the bottom of that.

I am also struggling with negative values where MicroPython has -10 // 3 giving -4 and -10 % 3 giving 2, when I was expecting -3 and -1. Not sure if that's my C mod operator which is wrong or my implementation of my MicroPython mod equivalent. It never ends :(

mpylib.h

Code: Select all

uint __aeabi_uidivmod(uint arg_lhs, uint arg_rhs) {
    uint lhs = arg_lhs;
    uint rhs = arg_rhs;
    uint res = 0;
    uint rem = 0;
    for (int i = 0; i < 32; i++) {
        res = res << 1;
        rem = rem << 1;

        rem |= (lhs >> 31) & 1;
        lhs = lhs << 1;

        if (rhs <= rem) {
            rem = rem - rhs;
            res = res | 1;
        }
    }
    __asm("mov r1, %0" : : "r" (rem) : "r1");
    return res;
}

uint __aeabi_uidiv(uint arg_lhs, uint arg_rhs) {
    return __aeabi_uidivmod(arg_lhs, arg_rhs);
}

int __aeabi_idiv(int lhs, int rhs) {
    if (rhs == 0) {
      return 0;
    }
    if (lhs >= 0) {
        if (rhs >= 0) {              	   // + +
           uint uint_lhs = lhs;
           uint uint_rhs = rhs;
           return uint_lhs / uint_rhs;
        } else {                           // + -
           uint uint_lhs = lhs;
           uint uint_rhs = -rhs;
           return -(uint_lhs / uint_rhs);
        }
    } else {
        if (rhs >= 0) {                    // - +
           uint uint_lhs = -lhs;
           uint uint_rhs = rhs;
           return -(uint_lhs / uint_rhs);
        } else {                           // - -
           uint uint_lhs = -lhs;
           uint uint_rhs = -rhs;
           return uint_lhs / uint_rhs;
        }
    }
}

int __aeabi_idivmod(int lhs, int rhs) {
    uint uint_lhs = 0;
    uint uint_rhs = 0;
    uint uint_res = 0;
    int  int__res = 0;
    if (rhs == 0) {
        int_res = lhs;
    }
    else if (lhs >= 0) {
        if (rhs >= 0) {                    // + +
           uint_lhs = lhs;
           uint_rhs = rhs;
        } else {                           // + -
           uint_lhs = lhs;
           uint_rhs = -rhs;
        }
        uint_res = uint_lhs % uint_rhs;
        int__res = uint_res;
    } else {
        if (rhs >= 0) {                    // - +
           uint_lhs = -lhs;
           uint_rhs = rhs;
        } else {                           // - -
           uint_lhs = -lhs;
           uint_rhs = -rhs;
        }
        uint_res = uint_lhs % uint_rhs;
        int__res = -uint_res;
    }
    __asm("mov r1, %0" : : "r" (int__res) : "r1");
    return int__res;
}

ejolson
Posts: 8254
Joined: Tue Mar 18, 2014 11:47 am

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 3:10 pm

hippy wrote:
Tue Sep 28, 2021 2:11 pm
vikK4yHabbe7L wrote:
Tue Sep 28, 2021 1:37 am
So the question is... why isn't cmake telling make to get things from libgcc.a ?
It's not a 'cmake' issue. That builds MicroPython perfectly well, handles divisions and modulos in its source and links to the required '__aeabi_idivmod' and friends as required and expected. Actually it seems to link to '__wrap__aeabi_idivmod' etc, but it all works as one would expect.

The issue here is building Native C Extension Modules which are built outside of the 'cmake' MicroPython build. These use 'make' and a 'Makefile' to take C source and create a '.mpy' file which can be copied to the Pico file system which can be imported as if they were '.py' modules. In theory, as easy as '.py' with the benefit of native execution and not having to touch or even build the MicroPython source code.

To allow the importing of a '.mpy' file that file has to conform with what MicroPython allows, and that means a limited set of functions which are defined and usable for the C source. So things like 'mp_obj_str_get_str' are defined, available and usable, but 'strlen' isn't. If one wants to use 'strlen' one has to provide it in the source. Its no good using #include "strings.h" because, while that will allow the code to compile, a 'strlen' implementation won't be found when it comes to linking.

The problem here is that when 'make' is run and a division or modulo is performed, GCC emits calls to '__aeabi_idivmod' etc but the MicroPython provided linker used to create the final '.mpy' file has no clue what they are. They are not catered for by MicroPython when imported, so are reported as functions the user needs to define in their C code but hasn't. That's fair enough for things like 'strlen' but it's a PITA when division and modulo requires doing that.

I expect the solution is to make MicroPython aware of needing to provide and support ''__aeabi_idivmod' etc for the Pico but I have no idea of how to do that and it would be something which really needs to be done by the MicroPython team. Until then the only option is to provide the missing routines oneself in the C source or an include file.

I believe I have achieved that because it works when tested from a module wrapper and are a lot quicker than MicroPython's in-built division and modulo operators which need to be a lot more generic. But, for some reason, not in more involved code where I would like them to work and I haven't got to the bottom of that.

I am also struggling with negative values where MicroPython has -10 // 3 giving -4 and -10 % 3 giving 2, when I was expecting -3 and -1. Not sure if that's my C mod operator which is wrong or my implementation of my MicroPython mod equivalent. It never ends :(

mpylib.h

Code: Select all

uint __aeabi_uidivmod(uint arg_lhs, uint arg_rhs) {
    uint lhs = arg_lhs;
    uint rhs = arg_rhs;
    uint res = 0;
    uint rem = 0;
    for (int i = 0; i < 32; i++) {
        res = res << 1;
        rem = rem << 1;

        rem |= (lhs >> 31) & 1;
        lhs = lhs << 1;

        if (rhs <= rem) {
            rem = rem - rhs;
            res = res | 1;
        }
    }
    __asm("mov r1, %0" : : "r" (rem) : "r1");
    return res;
}

uint __aeabi_uidiv(uint arg_lhs, uint arg_rhs) {
    return __aeabi_uidivmod(arg_lhs, arg_rhs);
}

int __aeabi_idiv(int lhs, int rhs) {
    if (rhs == 0) {
      return 0;
    }
    if (lhs >= 0) {
        if (rhs >= 0) {              	   // + +
           uint uint_lhs = lhs;
           uint uint_rhs = rhs;
           return uint_lhs / uint_rhs;
        } else {                           // + -
           uint uint_lhs = lhs;
           uint uint_rhs = -rhs;
           return -(uint_lhs / uint_rhs);
        }
    } else {
        if (rhs >= 0) {                    // - +
           uint uint_lhs = -lhs;
           uint uint_rhs = rhs;
           return -(uint_lhs / uint_rhs);
        } else {                           // - -
           uint uint_lhs = -lhs;
           uint uint_rhs = -rhs;
           return uint_lhs / uint_rhs;
        }
    }
}

int __aeabi_idivmod(int lhs, int rhs) {
    uint uint_lhs = 0;
    uint uint_rhs = 0;
    uint uint_res = 0;
    int  int__res = 0;
    if (rhs == 0) {
        int_res = lhs;
    }
    else if (lhs >= 0) {
        if (rhs >= 0) {                    // + +
           uint_lhs = lhs;
           uint_rhs = rhs;
        } else {                           // + -
           uint_lhs = lhs;
           uint_rhs = -rhs;
        }
        uint_res = uint_lhs % uint_rhs;
        int__res = uint_res;
    } else {
        if (rhs >= 0) {                    // - +
           uint_lhs = -lhs;
           uint_rhs = rhs;
        } else {                           // - -
           uint_lhs = -lhs;
           uint_rhs = -rhs;
        }
        uint_res = uint_lhs % uint_rhs;
        int__res = -uint_res;
    }
    __asm("mov r1, %0" : : "r" (int__res) : "r1");
    return int__res;
}
I don't understand the hesitancy to link to the gcc runtime support library. There are going to be many calls to that library that the compiler issues behind the scenes. Not linking to libgcc.a just breaks things.

Can you just place it on the command line along with all your source files? Note you may need to do similar for the wrapper call back to the Pico SDK with the actual code for the hardware divider.
Last edited by ejolson on Tue Sep 28, 2021 3:20 pm, edited 1 time in total.

User avatar
jahboater
Posts: 7375
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 3:20 pm

hippy wrote:
Tue Sep 28, 2021 2:11 pm
I am also struggling with negative values where MicroPython has -10 // 3 giving -4 and -10 % 3 giving 2, when I was expecting -3 and -1. Not sure if that's my C mod operator which is wrong or my implementation of my MicroPython mod equivalent. It never ends :(
Is this simply the fact that Python uses floor division (truncates towards negative infinity), not "truncate towards zero" as C, and the hardware, do ?

Perhaps check your division code returns the same as the SDIV instruction on an ARMv7 or later Pi.
Last edited by jahboater on Tue Sep 28, 2021 3:40 pm, edited 1 time in total.

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 3:40 pm

ejolson wrote:
Tue Sep 28, 2021 3:10 pm
I don't understand the hesitancy to link to the gcc runtime support library. There are going to be many calls to that library that the compiler issues behind the scenes. Not linking to libgcc.a just breaks things.
Because of the way MicroPython is implemented, and how the MicroPython provided toolchain for creating '.mpy' files works, I do not believe there is any way to link gcc runtime support or use anything which Micropython or its toolchain is not aware of.

Effectively there is one runtime library which Native C Modules can be linked to and, if what you want isn't in that, you are out of luck.
ejolson wrote:
Tue Sep 28, 2021 3:10 pm
Can you just place it on the command line along with all your source files?
Not that I can tell.

The only two solutions I can see are to update MicroPython and its toolchain for '.mpy' creation so it is aware of what is needed and then things should just work, or provide an implementation for what's missing within the C source of the Native C Module.

If there is any other way I am not aware of it.

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Tue Sep 28, 2021 4:05 pm

jahboater wrote:
Tue Sep 28, 2021 3:20 pm
hippy wrote:
Tue Sep 28, 2021 2:11 pm
I am also struggling with negative values where MicroPython has -10 // 3 giving -4 and -10 % 3 giving 2, when I was expecting -3 and -1. Not sure if that's my C mod operator which is wrong or my implementation of my MicroPython mod equivalent. It never ends :(
Is this simply the fact that Python uses floor division (truncates towards negative infinity), not "truncate towards zero" like C, and the hardware, do ?

Perhaps check your division code returns the same as the SDIV instruction on an ARMv7 or later Pi.
It does seem it is something funky with MicroPython -- and Python for that matter. A Pi C program and a Pico SDK C program delivers what I was expecting, -10 / 3 = -3, -10 % 3 = -1.

Python isn't incorrect per se, (-4*3)+(2)=-10 is the same as (-3*3)+(-1)=-10, just not what I was expecting. As this effort is purely directed at allowing C code to run I am going to consider what I have correct. Making any implementation via C code work exactly as MicroPython's in-builts do isn't much of a concern for me.

kilograham
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 962
Joined: Fri Apr 12, 2019 11:00 am
Location: austin tx

Re: MPY C Extension - Cannot do division or modulo

Thu Oct 14, 2021 12:46 am

you should use the included micropython support for building c-modules with cmake, then you will pick up all the right dependencies

https://github.com/micropython/micropyt ... odules.rst

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Thu Oct 14, 2021 1:38 pm

kilograham wrote:
Thu Oct 14, 2021 12:46 am
you should use the included micropython support for building c-modules with cmake, then you will pick up all the right dependencies

https://github.com/micropython/micropyt ... odules.rst
That is for building C Extension Modules which become an integral part of the MicroPython firmware.

That does not cover Native C Modules which are compiled to '.mpy' files - which is where the problem occurs.

hippy
Posts: 10741
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: MPY C Extension - Cannot do division or modulo

Thu Oct 14, 2021 4:29 pm

hippy wrote:
Thu Oct 14, 2021 1:38 pm
That is for building C Extension Modules which become an integral part of the MicroPython firmware.
And I am not even convinced those instructions are correct. I have tried it before - whatever variant it was back when - and it never worked, and isn't working now.

The problem appears to be it is providing "USER_C_MODULES=../../examples/usercmodule" to 'make' when it's 'cmake' which determines what user modules will be built when 'make' is run.

Maybe it's just me, my configuration. It does as expected if I hack my 'CMakeLists.txt' to force the extension module directories to be built and run 'cmake' then 'make'. Which is what I would do anyway to avoid having to type anything more than 'cmake ..' and 'make'. I could create shell scripts but it's more work, more files, and I'll probably forget I should be running those and not 'cmake' and 'make' directly. Everything I have done so far has worked just by adding the C Extension file to the build list so 'USER_C_MODULES' just seems excess for what needs to be done.

In fact everything with Native C Modules had also worked until I needed one to do a division which isn't a power-of-two.

Return to “MicroPython”