Acceptance Tests |
System Tests |
Integration Tests |
Unit Tests |
Acceptance Tests |
System Tests |
Integration Tests |
Unit Tests |
Application |
HAL |
Application |
Python |
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
%ls micropython/
ACKNOWLEDGEMENTS docs/ lib/ pic16bit/ teensy/ zephyr/ bare-arm/ drivers/ LICENSE py/ tests/ cc3200/ esp8266/ logo/ qemu-arm/ tools/ CODECONVENTIONS.md examples/ minimal/ README.md unix/ CONTRIBUTING.md extmod/ mpy-cross/ stmhal/ windows/
%ls micropython/minimal/
frozentest.mpy main.c mpconfigport.h qstrdefsport.h stm32f405.ld frozentest.py Makefile mphalport.h README.md uart_core.c
!tail -n29 micropython/minimal/uart_core.c
// Receive single character int mp_hal_stdin_rx_chr(void) { unsigned char c = 0; #if MICROPY_MIN_USE_STDOUT int r = read(0, &c, 1); (void)r; #elif MICROPY_MIN_USE_STM32_MCU // wait for RXNE while ((USART1->SR & (1 << 5)) == 0) { } c = USART1->DR; #endif return c; } // Send string of given length void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { #if MICROPY_MIN_USE_STDOUT int r = write(1, str, len); (void)r; #elif MICROPY_MIN_USE_STM32_MCU while (len--) { // wait for TXE while ((USART1->SR & (1 << 7)) == 0) { } USART1->DR = *str++; } #endif }
!grep 'INC ' micropython/minimal/Makefile
INC += -I. INC += -I.. INC += -I../stmhal INC += -I$(BUILD)
makefile = pymake.data.Makefile('micropython/minimal')
makefile.include('Makefile')
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity.
makefile.variables.get('INC')[2]
<Expansion with elements: ['-I. -I.. -I../stmhal -I', VariableRef<Expansion of variables 'INC':1:0:1:23>(Exp<None>('BUILD'))]>
_.resolvestr(makefile, makefile.variables)
'-I. -I.. -I../stmhal -Ibuild'
def resolve_variable(makefile, name):
return makefile.variables.get(name)[2].resolvestr(makefile, makefile.variables).split()
!grep 'INC ' micropython/minimal/Makefile
INC += -I. INC += -I.. INC += -I../stmhal INC += -I$(BUILD)
resolve_variable(makefile, 'INC')
['-I.', '-I..', '-I../stmhal', '-Ibuild']
include_options = resolve_variable(makefile, 'INC') + ['-I../extmod']
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
%cd -q micropython/minimal
!grep -A7 'SRC_C ' Makefile
SRC_C = \ main.c \ uart_core.c \ lib/utils/stdout_helpers.c \ lib/utils/pyexec.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ $(BUILD)/_frozen_mpy.c \
resolve_variable(makefile, 'SRC_C')
['main.c', 'uart_core.c', 'lib/utils/stdout_helpers.c', 'lib/utils/pyexec.c', 'lib/libc/string0.c', 'lib/mp-readline/readline.c', 'build/_frozen_mpy.c']
source_files = set(x.replace('lib/', '../lib/') for x in resolve_variable(makefile, 'SRC_C'))
object_files = resolve_variable(makefile, 'PY_O_BASENAME')
source_files |= {
os.path.join('..', 'py', x.replace('.o', '.c')) for x in object_files
}
source_files.remove('uart_core.c')
source_files.remove('../lib/libc/string0.c')
!grep -m2 -B1 USART1- uart_core.c
// wait for RXNE while ((USART1->SR & (1 << 5)) == 0) { } c = USART1->DR;
resolve_variable(makefile, 'SRC_C')
['main.c', 'uart_core.c', 'lib/utils/stdout_helpers.c', 'lib/utils/pyexec.c', 'lib/libc/string0.c', 'lib/mp-readline/readline.c', 'build/_frozen_mpy.c']
!LANG=C ls build/_frozen_mpy.c
ls: cannot access 'build/_frozen_mpy.c': No such file or directory
subprocess.run(['make', 'build/_frozen_mpy.c'], check=True);
source_content = ''.join(
open(f).read() for f in sorted(source_files) if os.path.exists(f)
)
source_content = source_content.replace('int main(', 'int mpmain(')
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
header_files = {os.path.join('..', 'py', 'mphal.h')}
header_content = '#define __attribute__(x)\n#define mp_hal_pin_obj_t void*\n'
header_content += ''.join(open(f).read() for f in header_files)
header_content = preprocess(header_content)
def preprocess(source):
return subprocess.check_output(['gcc'] + include_options + ['-E', '-P', '-'], input=source, universal_newlines=True)
sorted(header_content.split('\n'))[-3:]
['void mp_hal_stdout_tx_str(const char *str);', 'void mp_hal_stdout_tx_strn(const char *str, size_t len);', 'void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len);']
extern "Python+C" void mp_hal_stdout_tx_str(const char *str);
class HeaderGenerator(pycparser.c_generator.CGenerator):
functions = set()
def visit_Decl(self, n, *args, **kwargs):
result = super().visit_Decl(n, *args, **kwargs)
if isinstance(n.type, pycparser.c_ast.FuncDecl):
if n.name in self.functions or result in source_content:
return ''
self.functions.add(n.name)
return 'extern "Python+C" ' + result
return result
def visit_FuncDef(self, n, *args, **kwargs):
self.functions.add(n.decl.name)
return ''
ast = pycparser.CParser().parse(header_content)
header_content = HeaderGenerator().visit(ast)
sorted(header_content.split('\n'))[8:11]
['extern "Python+C" mp_uint_t mp_hal_ticks_us(void);', 'extern "Python+C" void mp_hal_delay_ms(mp_uint_t ms);', 'extern "Python+C" void mp_hal_delay_us(mp_uint_t us);']
header_content += 'int mpmain(int argc, char **argv);'
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
ffibuilder = cffi.FFI()
ffibuilder.cdef(header_content)
ffibuilder.set_source('mpsim', source_content, include_dirs=[x.replace('-I', '') for x in include_options])
ffibuilder.compile();
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
import mpsim
@mpsim.ffi.def_extern()
def mp_hal_stdin_rx_chr():
return ord(sys.stdin.read(1))
@mpsim.ffi.def_extern()
def mp_hal_stdout_tx_strn(data, length):
print(bytes(mpsim.ffi.buffer(data, length)).decode(), end='', flush=True)
cat application/*.c |
||||||
→ | CFFI | → | gcc | → | python | |
cat hal/*.h |
$ ls -l bad/ -rw-r--r-- 1 user user 397789 1. Jan 1970 main.c
$ ls -l good/ drwxr-xr-x 2 user user 4096 1. Jan 1970 application drwxr-xr-x 2 user user 4096 1. Jan 1970 hal
$ cat application/file1.c static void do_something(void) { ... } $ cat application/file2.c static void do_something(void) { ... }
$ cat application/file1.c static void file1_do_something(void) { ... } $ cat application/file2.c static void file2_do_something(void) { ... }
struct { unsigned short major_version; unsigned int minor_version; } data; version.major = 1234; version.minor = 567890; checksum = sha256(&data, sizeof(data));
struct { uint16_t major_version; uint32_t minor_version; } __attribute__((packed)) data; version.major = htons(1234); version.minor = htonl(567890); checksum = sha256(&data, sizeof(data));
Application | Application | |
HAL | Python | |
Hardware | Code Network |
ffibuilder.set_source('mpsim', source_content, extra_compile_args=['-fsanitize-address'], libraries=['asan'])
os.environ['CC'] = 'afl-gcc'
import afl
stdin = sys.stdin.detach()
while afl.loop(10000):
application.lib.run(stdin.read())