Skip to content

Commit 640e0b2

Browse files
committed
py: Implement very simple frozen modules support.
Only modules (not packages) supported now. Source modules can be converted to frozen module structures using tools/make-frozen.py script.
1 parent 438b3d2 commit 640e0b2

7 files changed

Lines changed: 155 additions & 4 deletions

File tree

minimal/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#define MICROPY_PY_IO (0)
3333
#define MICROPY_PY_STRUCT (0)
3434
#define MICROPY_PY_SYS (0)
35+
#define MICROPY_MODULE_FROZEN (0)
3536
#define MICROPY_CPYTHON_COMPAT (0)
3637
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
3738
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)

py/builtinimport.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "py/objmodule.h"
3535
#include "py/runtime.h"
3636
#include "py/builtin.h"
37+
#include "py/frozenmod.h"
3738

3839
#if 0 // print debugging info
3940
#define DEBUG_PRINT (1)
@@ -109,17 +110,15 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
109110
#endif
110111
}
111112

112-
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
113-
// create the lexer
114-
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
113+
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) {
115114

116115
if (lex == NULL) {
117116
// we verified the file exists using stat, but lexer could still fail
118117
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
119118
nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found"));
120119
} else {
121120
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
122-
"no module named '%s'", vstr_str(file)));
121+
"no module named '%s'", fname));
123122
}
124123
}
125124

@@ -133,6 +132,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
133132
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
134133
}
135134

135+
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
136+
// create the lexer
137+
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
138+
do_load_from_lexer(module_obj, lex, vstr_str(file));
139+
}
140+
136141
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
137142
#if DEBUG_PRINT
138143
DEBUG_printf("__import__:\n");
@@ -237,6 +242,15 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
237242
}
238243
DEBUG_printf("Module not yet loaded\n");
239244

245+
#if MICROPY_MODULE_FROZEN
246+
mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len);
247+
if (lex != NULL) {
248+
module_obj = mp_obj_new_module(MP_OBJ_QSTR_VALUE(module_name));
249+
do_load_from_lexer(module_obj, lex, mod_str);
250+
return module_obj;
251+
}
252+
#endif
253+
240254
uint last = 0;
241255
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
242256
module_obj = MP_OBJ_NULL;

py/frozenmod.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2015 Paul Sokolovsky
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <string.h>
28+
#include <stdint.h>
29+
30+
#include "py/lexer.h"
31+
32+
#if MICROPY_MODULE_FROZEN
33+
34+
extern const uint16_t mp_frozen_sizes[];
35+
extern const char mp_frozen_content[];
36+
37+
mp_lexer_t *mp_find_frozen_module(const char *str, int len) {
38+
const uint16_t *sz_ptr = mp_frozen_sizes;
39+
const char *s = mp_frozen_content;
40+
41+
while (*sz_ptr) {
42+
int l = strlen(s);
43+
if (l == len && !memcmp(str, s, l)) {
44+
s += l + 1;
45+
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR_, s, *sz_ptr, 0);
46+
return lex;
47+
}
48+
s += l + 1 + *sz_ptr++;
49+
}
50+
return NULL;
51+
}
52+
53+
#endif // MICROPY_MODULE_FROZEN

py/frozenmod.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2014 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
mp_lexer_t *mp_find_frozen_module(const char *str, int len);

py/mpconfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,11 @@ typedef double mp_float_t;
328328
#define MICROPY_MODULE_WEAK_LINKS (0)
329329
#endif
330330

331+
// Whether frozen modules are supported
332+
#ifndef MICROPY_MODULE_FROZEN
333+
#define MICROPY_MODULE_FROZEN (0)
334+
#endif
335+
331336
// Whether you can override builtins in the builtins module
332337
#ifndef MICROPY_CAN_OVERRIDE_BUILTINS
333338
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)

py/py.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ PY_O_BASENAME = \
112112
smallint.o \
113113
pfenv.o \
114114
pfenv_printf.o \
115+
frozenmod.o \
115116
../extmod/moductypes.o \
116117
../extmod/modujson.o \
117118
../extmod/modure.o \

tools/make-frozen.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Create frozen modules structure for MicroPython.
4+
#
5+
# Usage:
6+
#
7+
# Have a directory with modules to be frozen (only modules, not packages
8+
# supported so far):
9+
#
10+
# frozen/foo.py
11+
# frozen/bar.py
12+
#
13+
# Run script, passing path to the directory above:
14+
#
15+
# ./make-frozen.py frozen > frozen.c
16+
#
17+
# Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN in
18+
# config.
19+
#
20+
import sys
21+
import os
22+
23+
24+
def module_name(f):
25+
return f[:-len(".py")]
26+
27+
modules = []
28+
29+
for dirpath, dirnames, filenames in os.walk(sys.argv[1]):
30+
for f in filenames:
31+
st = os.stat(dirpath + "/" + f)
32+
modules.append((f, st))
33+
34+
print("#include <stdint.h>")
35+
print("const uint16_t mp_frozen_sizes[] = {")
36+
37+
for f, st in modules:
38+
print("%d," % st.st_size)
39+
40+
print("0};")
41+
42+
print("const char mp_frozen_content[] = {")
43+
for f, st in modules:
44+
m = module_name(f)
45+
print('"%s\\0"' % m)
46+
data = open(sys.argv[1] + "/" + f).read()
47+
data = repr(data)[1:-1]
48+
data = data.replace('"', '\\"')
49+
print('"%s"' % data)
50+
print("};")

0 commit comments

Comments
 (0)