blob: e4c4104c64d9443c159a9619e3276bb0377c5c30 [file] [log] [blame]
Damien George56f76b82016-02-11 22:37:26 +00001/*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013-2016 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#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <unistd.h>
Damien George56f76b82016-02-11 22:37:26 +000031
Damien George56f76b82016-02-11 22:37:26 +000032#include "py/compile.h"
Damien George85ae17c2016-11-16 20:25:36 +110033#include "py/persistentcode.h"
Damien George56f76b82016-02-11 22:37:26 +000034#include "py/runtime.h"
35#include "py/gc.h"
36#include "py/stackctrl.h"
Damien George7e90e222019-05-02 09:59:21 +100037#include "genhdr/mpversion.h"
stijn9bdb82e2016-07-22 11:54:26 +020038#ifdef _WIN32
Damien George4a938012017-09-06 14:09:13 +100039#include "ports/windows/fmode.h"
stijn9bdb82e2016-07-22 11:54:26 +020040#endif
Damien George56f76b82016-02-11 22:37:26 +000041
42// Command line options, with their defaults
43STATIC uint emit_opt = MP_EMIT_OPT_NONE;
44mp_uint_t mp_verbose_flag = 0;
45
46// Heap size of GC heap (if enabled)
47// Make it larger on a 64 bit machine, because pointers are larger.
Damien George69661f32020-02-27 15:36:53 +110048long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
Damien George56f76b82016-02-11 22:37:26 +000049
50STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) {
51 (void)env;
52 ssize_t dummy = write(STDERR_FILENO, str, len);
53 (void)dummy;
54}
55
56STATIC const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
57
Damien George74fb4e72016-05-23 13:25:54 +010058STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) {
Damien George56f76b82016-02-11 22:37:26 +000059 nlr_buf_t nlr;
60 if (nlr_push(&nlr) == 0) {
Damien George97142002017-03-14 11:43:28 +110061 mp_lexer_t *lex = mp_lexer_new_from_file(file);
62
Damien George74fb4e72016-05-23 13:25:54 +010063 qstr source_name;
64 if (source_file == NULL) {
65 source_name = lex->source_name;
66 } else {
67 source_name = qstr_from_str(source_file);
68 }
Damien George56f76b82016-02-11 22:37:26 +000069
70 #if MICROPY_PY___FILE__
Damien George1556af12019-03-26 18:19:21 +110071 mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
Damien George56f76b82016-02-11 22:37:26 +000072 #endif
73
74 mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
Damien Georgeaf20c2e2019-08-23 11:20:50 +100075 mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false);
Damien George56f76b82016-02-11 22:37:26 +000076
77 vstr_t vstr;
78 vstr_init(&vstr, 16);
79 if (output_file == NULL) {
80 vstr_add_str(&vstr, file);
81 vstr_cut_tail_bytes(&vstr, 2);
82 vstr_add_str(&vstr, "mpy");
83 } else {
84 vstr_add_str(&vstr, output_file);
85 }
86 mp_raw_code_save_file(rc, vstr_null_terminated_str(&vstr));
87 vstr_clear(&vstr);
88
89 nlr_pop();
90 return 0;
91 } else {
92 // uncaught exception
93 mp_obj_print_exception(&mp_stderr_print, (mp_obj_t)nlr.ret_val);
94 return 1;
95 }
96}
97
98STATIC int usage(char **argv) {
99 printf(
Damien George69661f32020-02-27 15:36:53 +1100100 "usage: %s [<opts>] [-X <implopt>] <input filename>\n"
101 "Options:\n"
102 "--version : show version information\n"
103 "-o : output file for compiled bytecode (defaults to input with .mpy extension)\n"
104 "-s : source filename to embed in the compiled bytecode (defaults to input file)\n"
105 "-v : verbose (trace various operations); can be multiple\n"
106 "-O[N] : apply bytecode optimizations of level N\n"
107 "\n"
108 "Target specific options:\n"
109 "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
110 "-mno-unicode : don't support unicode in compiled strings\n"
111 "-mcache-lookup-bc : cache map lookups in the bytecode\n"
112 "-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
113 "\n"
114 "Implementation specific options:\n", argv[0]
115 );
Damien George56f76b82016-02-11 22:37:26 +0000116 int impl_opts_cnt = 0;
117 printf(
Damien George69661f32020-02-27 15:36:53 +1100118 #if MICROPY_EMIT_NATIVE
119 " emit={bytecode,native,viper} -- set the default code emitter\n"
120 #else
121 " emit=bytecode -- set the default code emitter\n"
122 #endif
123 );
Damien George56f76b82016-02-11 22:37:26 +0000124 impl_opts_cnt++;
125 printf(
Damien George69661f32020-02-27 15:36:53 +1100126 " heapsize=<n> -- set the heap size for the GC (default %ld)\n"
127 , heap_size);
Damien George56f76b82016-02-11 22:37:26 +0000128 impl_opts_cnt++;
129
130 if (impl_opts_cnt == 0) {
131 printf(" (none)\n");
132 }
133
134 return 1;
135}
136
137// Process options which set interpreter init options
138STATIC void pre_process_options(int argc, char **argv) {
139 for (int a = 1; a < argc; a++) {
140 if (argv[a][0] == '-') {
141 if (strcmp(argv[a], "-X") == 0) {
142 if (a + 1 >= argc) {
143 exit(usage(argv));
144 }
145 if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
146 emit_opt = MP_EMIT_OPT_BYTECODE;
Damien George8e3e0572019-08-23 11:09:34 +1000147 #if MICROPY_EMIT_NATIVE
Damien George56f76b82016-02-11 22:37:26 +0000148 } else if (strcmp(argv[a + 1], "emit=native") == 0) {
149 emit_opt = MP_EMIT_OPT_NATIVE_PYTHON;
150 } else if (strcmp(argv[a + 1], "emit=viper") == 0) {
151 emit_opt = MP_EMIT_OPT_VIPER;
Damien George8e3e0572019-08-23 11:09:34 +1000152 #endif
Damien George56f76b82016-02-11 22:37:26 +0000153 } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) {
154 char *end;
155 heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0);
156 // Don't bring unneeded libc dependencies like tolower()
157 // If there's 'w' immediately after number, adjust it for
158 // target word size. Note that it should be *before* size
159 // suffix like K or M, to avoid confusion with kilowords,
160 // etc. the size is still in bytes, just can be adjusted
161 // for word size (taking 32bit as baseline).
162 bool word_adjust = false;
163 if ((*end | 0x20) == 'w') {
164 word_adjust = true;
165 end++;
166 }
167 if ((*end | 0x20) == 'k') {
168 heap_size *= 1024;
169 } else if ((*end | 0x20) == 'm') {
170 heap_size *= 1024 * 1024;
171 }
172 if (word_adjust) {
173 heap_size = heap_size * BYTES_PER_WORD / 4;
174 }
175 } else {
176 exit(usage(argv));
177 }
178 a++;
179 }
180 }
181 }
182}
183
184MP_NOINLINE int main_(int argc, char **argv) {
185 mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4));
186
187 pre_process_options(argc, argv);
188
189 char *heap = malloc(heap_size);
190 gc_init(heap, heap + heap_size);
191
192 mp_init();
Damien George69661f32020-02-27 15:36:53 +1100193 #ifdef _WIN32
stijn9bdb82e2016-07-22 11:54:26 +0200194 set_fmode_binary();
Damien George69661f32020-02-27 15:36:53 +1100195 #endif
Damien George56f76b82016-02-11 22:37:26 +0000196 mp_obj_list_init(mp_sys_path, 0);
197 mp_obj_list_init(mp_sys_argv, 0);
198
Damien Georgeaf20c2e2019-08-23 11:20:50 +1000199 #if MICROPY_EMIT_NATIVE
200 // Set default emitter options
201 MP_STATE_VM(default_emit_opt) = emit_opt;
202 #else
203 (void)emit_opt;
204 #endif
205
Damien George56f76b82016-02-11 22:37:26 +0000206 // set default compiler configuration
207 mp_dynamic_compiler.small_int_bits = 31;
208 mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
209 mp_dynamic_compiler.py_builtins_str_unicode = 1;
Damien George9c9bc652019-03-09 10:59:57 +1100210 #if defined(__i386__)
211 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
Damien Georgeb5966382019-09-18 13:45:20 +1000212 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
Damien George9c9bc652019-03-09 10:59:57 +1100213 #elif defined(__x86_64__)
214 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
Damien Georgeb5966382019-09-18 13:45:20 +1000215 mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
Damien Georgee70c4382019-05-01 15:31:00 +1000216 #elif defined(__arm__) && !defined(__thumb2__)
217 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
Damien Georgeb5966382019-09-18 13:45:20 +1000218 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
Damien George9c9bc652019-03-09 10:59:57 +1100219 #else
220 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE;
Damien Georgeb5966382019-09-18 13:45:20 +1000221 mp_dynamic_compiler.nlr_buf_num_regs = 0;
Damien George9c9bc652019-03-09 10:59:57 +1100222 #endif
Damien George56f76b82016-02-11 22:37:26 +0000223
224 const char *input_file = NULL;
225 const char *output_file = NULL;
Damien George74fb4e72016-05-23 13:25:54 +0100226 const char *source_file = NULL;
Damien George56f76b82016-02-11 22:37:26 +0000227
228 // parse main options
229 for (int a = 1; a < argc; a++) {
230 if (argv[a][0] == '-') {
231 if (strcmp(argv[a], "-X") == 0) {
232 a += 1;
Damien George7e90e222019-05-02 09:59:21 +1000233 } else if (strcmp(argv[a], "--version") == 0) {
234 printf("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE
235 "; mpy-cross emitting mpy v" MP_STRINGIFY(MPY_VERSION) "\n");
236 return 0;
Damien George56f76b82016-02-11 22:37:26 +0000237 } else if (strcmp(argv[a], "-v") == 0) {
238 mp_verbose_flag++;
239 } else if (strncmp(argv[a], "-O", 2) == 0) {
240 if (unichar_isdigit(argv[a][2])) {
241 MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf;
242 } else {
243 MP_STATE_VM(mp_optimise_value) = 0;
Damien George69661f32020-02-27 15:36:53 +1100244 for (char *p = argv[a] + 1; *p && *p == 'O'; p++, MP_STATE_VM(mp_optimise_value)++) {;
245 }
Damien George56f76b82016-02-11 22:37:26 +0000246 }
247 } else if (strcmp(argv[a], "-o") == 0) {
248 if (a + 1 >= argc) {
249 exit(usage(argv));
250 }
251 a += 1;
252 output_file = argv[a];
Damien George74fb4e72016-05-23 13:25:54 +0100253 } else if (strcmp(argv[a], "-s") == 0) {
254 if (a + 1 >= argc) {
255 exit(usage(argv));
256 }
257 a += 1;
258 source_file = argv[a];
Damien George56f76b82016-02-11 22:37:26 +0000259 } else if (strncmp(argv[a], "-msmall-int-bits=", sizeof("-msmall-int-bits=") - 1) == 0) {
260 char *end;
261 mp_dynamic_compiler.small_int_bits =
262 strtol(argv[a] + sizeof("-msmall-int-bits=") - 1, &end, 0);
263 if (*end) {
264 return usage(argv);
265 }
266 // TODO check that small_int_bits is within range of host's capabilities
267 } else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) {
268 mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
269 } else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) {
270 mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1;
271 } else if (strcmp(argv[a], "-mno-unicode") == 0) {
272 mp_dynamic_compiler.py_builtins_str_unicode = 0;
273 } else if (strcmp(argv[a], "-municode") == 0) {
274 mp_dynamic_compiler.py_builtins_str_unicode = 1;
Damien George9c9bc652019-03-09 10:59:57 +1100275 } else if (strncmp(argv[a], "-march=", sizeof("-march=") - 1) == 0) {
276 const char *arch = argv[a] + sizeof("-march=") - 1;
277 if (strcmp(arch, "x86") == 0) {
278 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
Damien Georgeb5966382019-09-18 13:45:20 +1000279 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
Damien George9c9bc652019-03-09 10:59:57 +1100280 } else if (strcmp(arch, "x64") == 0) {
281 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
Damien Georgeb5966382019-09-18 13:45:20 +1000282 mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
Damien George9c9bc652019-03-09 10:59:57 +1100283 } else if (strcmp(arch, "armv6") == 0) {
284 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
Damien Georgeb5966382019-09-18 13:45:20 +1000285 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
Damien George9c9bc652019-03-09 10:59:57 +1100286 } else if (strcmp(arch, "armv7m") == 0) {
287 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M;
Damien Georgeb5966382019-09-18 13:45:20 +1000288 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
Damien George82a19cb2019-12-03 12:32:29 +1100289 } else if (strcmp(arch, "armv7em") == 0) {
290 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EM;
291 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
292 } else if (strcmp(arch, "armv7emsp") == 0) {
293 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMSP;
294 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
295 } else if (strcmp(arch, "armv7emdp") == 0) {
296 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7EMDP;
297 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
Damien George9c9bc652019-03-09 10:59:57 +1100298 } else if (strcmp(arch, "xtensa") == 0) {
299 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA;
Damien Georgeb5966382019-09-18 13:45:20 +1000300 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA;
Damien George1d21b4e2019-09-13 13:16:00 +1000301 } else if (strcmp(arch, "xtensawin") == 0) {
302 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN;
303 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN;
Damien George9c9bc652019-03-09 10:59:57 +1100304 } else {
305 return usage(argv);
306 }
Damien George56f76b82016-02-11 22:37:26 +0000307 } else {
308 return usage(argv);
309 }
310 } else {
311 if (input_file != NULL) {
312 mp_printf(&mp_stderr_print, "multiple input files\n");
313 exit(1);
314 }
315 input_file = argv[a];
316 }
317 }
318
319 if (input_file == NULL) {
320 mp_printf(&mp_stderr_print, "no input file\n");
321 exit(1);
322 }
323
Damien George74fb4e72016-05-23 13:25:54 +0100324 int ret = compile_and_save(input_file, output_file, source_file);
Damien George56f76b82016-02-11 22:37:26 +0000325
326 #if MICROPY_PY_MICROPYTHON_MEM_INFO
327 if (mp_verbose_flag) {
328 mp_micropython_mem_info(0, NULL);
329 }
330 #endif
331
332 mp_deinit();
333
334 return ret & 0xff;
335}
336
337int main(int argc, char **argv) {
338 mp_stack_ctrl_init();
339 return main_(argc, argv);
340}
341
342uint mp_import_stat(const char *path) {
343 (void)path;
344 return MP_IMPORT_STAT_NO_EXIST;
345}
346
347void nlr_jump_fail(void *val) {
348 printf("FATAL: uncaught NLR %p\n", val);
349 exit(1);
350}