From 95f5050b632c7fb2f3fd458379cd8d8fc8bd632b Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Thu, 4 Jul 2019 20:52:06 +0200
Subject: [PATCH] feat(pycardium): Enable frozen-module support

Closes #4.

Signed-off-by: Rahix <rahix@rahix.de>
---
 lib/micropython/gen-frozen.sh       | 18 +++++++++++++++++
 lib/micropython/gen-mpy-cross.sh    |  9 +++++++++
 lib/micropython/meson.build         | 30 +++++++++++++++++++++++++++++
 lib/micropython/mpy-cross-wrapper.c | 14 ++++++++++++++
 pycardium/meson.build               | 15 +++++++++++++++
 pycardium/modules/py/foo.py         |  8 ++++++++
 pycardium/modules/py/meson.build    |  5 +++++
 pycardium/mpconfigport.h            | 11 +++++------
 pycardium/mphalport.c               |  5 +++++
 9 files changed, 109 insertions(+), 6 deletions(-)
 create mode 100755 lib/micropython/gen-frozen.sh
 create mode 100755 lib/micropython/gen-mpy-cross.sh
 create mode 100644 lib/micropython/mpy-cross-wrapper.c
 create mode 100644 pycardium/modules/py/foo.py
 create mode 100644 pycardium/modules/py/meson.build

diff --git a/lib/micropython/gen-frozen.sh b/lib/micropython/gen-frozen.sh
new file mode 100755
index 00000000..3bf9c4ea
--- /dev/null
+++ b/lib/micropython/gen-frozen.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -e
+
+PYTHON="$1"
+SOURCE_DIR="$2"
+OUTPUT="$3"
+QSTR_HEADER="$4"
+
+shift 4
+
+# We need the defs header, not the generated
+QSTR_HEADER="$(dirname "$QSTR_HEADER")/qstrdefs.preprocessed.h"
+
+"$PYTHON" "$SOURCE_DIR"/micropython/tools/mpy-tool.py \
+    --freeze \
+    --qstr-header "$QSTR_HEADER" \
+    -mlongint-impl longlong \
+    "$@" >"$OUTPUT"
diff --git a/lib/micropython/gen-mpy-cross.sh b/lib/micropython/gen-mpy-cross.sh
new file mode 100755
index 00000000..56f10a23
--- /dev/null
+++ b/lib/micropython/gen-mpy-cross.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+
+SOURCE_DIR="$1"
+OUTPUT="$(realpath "$2")"
+
+cd "$SOURCE_DIR"/micropython/mpy-cross
+make -j "$(nproc)" >/dev/null
+cp mpy-cross "$OUTPUT"
diff --git a/lib/micropython/meson.build b/lib/micropython/meson.build
index c6a16cca..5922396a 100644
--- a/lib/micropython/meson.build
+++ b/lib/micropython/meson.build
@@ -17,6 +17,36 @@ micropython_gen_qstr = [
   meson.current_source_dir(),
 ]
 
+# mpy-cross
+mpy_cross_bin = custom_target(
+  'mpy-cross',
+  output: 'mpy-cross',
+  build_by_default: true,
+  command: [files('gen-mpy-cross.sh'), meson.current_source_dir(), '@OUTPUT@'],
+)
+
+# seriously meson, this is retarded
+mpy_cross_wrapper = executable(
+  'mpy-cross-wrapper',
+  'mpy-cross-wrapper.c',
+  link_depends: mpy_cross_bin,
+  native: true,
+  c_args: ['-DMPY_CROSS_PATH="' + meson.current_build_dir() + '"'],
+)
+
+mpy_cross = generator(
+  mpy_cross_wrapper,
+  output: '@BASENAME@.mpy',
+  arguments: ['-o', '@OUTPUT@', '-s', '@PLAINNAME@', '-march=armv7m', '@INPUT@'],
+)
+
+micropython_gen_frozen = [
+  files('gen-frozen.sh'),
+  python3,
+  meson.current_source_dir(),
+]
+
+
 # Sources
 micropython_includes = include_directories(
   './micropython/',
diff --git a/lib/micropython/mpy-cross-wrapper.c b/lib/micropython/mpy-cross-wrapper.c
new file mode 100644
index 00000000..6e333c23
--- /dev/null
+++ b/lib/micropython/mpy-cross-wrapper.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef MPY_CROSS_PATH
+#error "You need to define MPY_CROSS_PATH to compile this wrapper."
+#endif
+
+int main(int argc, char**argv)
+{
+	char path[] = MPY_CROSS_PATH "/mpy-cross";
+	argv[0] = "mpy-cross";
+	execv(path, argv);
+	fprintf(stderr, "Failed to run '%s'!\n", path);
+}
diff --git a/pycardium/meson.build b/pycardium/meson.build
index 0c839aaa..833a9e0e 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -36,6 +36,20 @@ qstr_h = custom_target(
 
 mp_headers = [version_h, modules_h, qstr_h]
 
+#################################
+#    Python Frozen Modules      #
+#################################
+
+subdir('modules/py')
+
+frozen_source = custom_target(
+  'frozen.c',
+  output: 'frozen.c',
+  input: [qstr_h, frozen_modules],
+  build_by_default: true,
+  command: [micropython_gen_frozen, '@OUTPUT@', '@INPUT@'],
+)
+
 ###################
 # MicroPython Lib #
 ###################
@@ -52,6 +66,7 @@ elf = executable(
   name + '.elf',
   'main.c',
   'mphalport.c',
+  frozen_source,
   modsrc,
   mp_headers,
   include_directories: micropython_includes,
diff --git a/pycardium/modules/py/foo.py b/pycardium/modules/py/foo.py
new file mode 100644
index 00000000..e95c53d1
--- /dev/null
+++ b/pycardium/modules/py/foo.py
@@ -0,0 +1,8 @@
+# Foo Module
+
+
+def bar():
+    print("Hello from foo!")
+
+
+X = 3.14
diff --git a/pycardium/modules/py/meson.build b/pycardium/modules/py/meson.build
new file mode 100644
index 00000000..29795f41
--- /dev/null
+++ b/pycardium/modules/py/meson.build
@@ -0,0 +1,5 @@
+python_modules = files(
+  'foo.py',
+)
+
+frozen_modules = mpy_cross.process(python_modules)
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index c4e6a6cb..c4199e63 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -4,16 +4,15 @@
 
 /* MicroPython Config Options */
 
-/*
- * Right now, we do not support importing external modules
- * though this might change in the future.
- */
-#define MICROPY_ENABLE_EXTERNAL_IMPORT      (0)
-
 /* We raise asynchronously from an interrupt handler */
 #define MICROPY_ASYNC_KBD_INTR              (1)
 #define MICROPY_KBD_EXCEPTION               (1)
 
+/* Enable precompiled frozen modules */
+#define MICROPY_MODULE_FROZEN_MPY           (1)
+#define MICROPY_MODULE_FROZEN               (1)
+#define MICROPY_QSTR_EXTRA_POOL             mp_qstr_frozen_const_pool
+
 #define MICROPY_ENABLE_DOC_STRING           (1)
 #define MICROPY_ENABLE_GC                   (1)
 #define MICROPY_FLOAT_IMPL                  (MICROPY_FLOAT_IMPL_FLOAT)
diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c
index 9852fd85..3c5aa445 100644
--- a/pycardium/mphalport.c
+++ b/pycardium/mphalport.c
@@ -108,6 +108,11 @@ mp_lexer_t* mp_lexer_new_from_file(const char* filename)
 	mp_raise_OSError(MP_ENOENT);
 }
 
+mp_import_stat_t mp_import_stat(const char* path)
+{
+	return MP_IMPORT_STAT_NO_EXIST;
+}
+
 mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t* args, mp_map_t* kwargs)
 {
 	/* TODO: Once fs is implemented, get this working as well */
-- 
GitLab