1/*
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>
31
32#include "py/compile.h"
33#include "py/persistentcode.h"
34#include "py/runtime.h"
35#include "py/gc.h"
36#include "py/stackctrl.h"
37#include "genhdr/mpversion.h"
38#ifdef _WIN32
39#include "ports/windows/fmode.h"
40#endif
41
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.
48long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
49
50STATIC void stderr_print_strn(void *env, const char *str, size_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
58STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) {
59 nlr_buf_t nlr;
60 if (nlr_push(&nlr) == 0) {
61 mp_lexer_t *lex = mp_lexer_new_from_file(file);
62
63 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 }
69
70 #if MICROPY_PY___FILE__
71 mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
72 #endif
73
74 mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
75 mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false);
76
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(
100 "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 );
116 int impl_opts_cnt = 0;
117 printf(
118 #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 );
124 impl_opts_cnt++;
125 printf(
126 " heapsize=<n> -- set the heap size for the GC (default %ld)\n"
127 , heap_size);
128 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;
147 #if MICROPY_EMIT_NATIVE
148 } 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;
152 #endif
153 } 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 * MP_BYTES_PER_OBJ_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 * (sizeof(void *) / 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();
193 #ifdef _WIN32
194 set_fmode_binary();
195 #endif
196 mp_obj_list_init(mp_sys_path, 0);
197 mp_obj_list_init(mp_sys_argv, 0);
198
199 #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
206 // 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;
210 #if defined(__i386__)
211 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
212 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
213 #elif defined(__x86_64__)
214 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
215 mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
216 #elif defined(__arm__) && !defined(__thumb2__)
217 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
218 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
219 #else
220 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE;
221 mp_dynamic_compiler.nlr_buf_num_regs = 0;
222 #endif
223
224 const char *input_file = NULL;
225 const char *output_file = NULL;
226 const char *source_file = NULL;
227
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;
233 } 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;
237 } 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;
244 for (char *p = argv[a] + 1; *p && *p == 'O'; p++, MP_STATE_VM(mp_optimise_value)++) {;
245 }
246 }
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];
253 } 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];
259 } 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;
275 } 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;
279 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
280 } else if (strcmp(arch, "x64") == 0) {
281 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
282 mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
283 } else if (strcmp(arch, "armv6") == 0) {
284 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
285 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
286 } else if (strcmp(arch, "armv7m") == 0) {
287 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV7M;
288 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
289 } 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;
298 } else if (strcmp(arch, "xtensa") == 0) {
299 mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA;
300 mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA;
301 } 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;
304 } else {
305 return usage(argv);
306 }
307 } 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
324 int ret = compile_and_save(input_file, output_file, source_file);
325
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 fprintf(stderr, "FATAL: uncaught NLR %p\n", val);
349 exit(1);
350}
351