diff --git a/py/builtinevex.c b/py/builtinevex.c
index 0a928199f04dbc599d154d29317ddd773023b0a7..fc3a60182e0ca6a6c4b502f984c5fa106638085a 100644
--- a/py/builtinevex.c
+++ b/py/builtinevex.c
@@ -33,7 +33,7 @@ STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse
     }
 
     // compile the string
-    mp_obj_t module_fun = mp_compile(pn, source_name, false);
+    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
     mp_parse_node_free(pn);
 
     if (module_fun == mp_const_none) {
diff --git a/py/builtinimport.c b/py/builtinimport.c
index e2137237f96783fa29ac65c614362297d1feba67..a3ab3c9ed7fa8295d09bf7eb040509c269a40b73 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -103,7 +103,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
     }
 
     // compile the imported script
-    mp_obj_t module_fun = mp_compile(pn, source_name, false);
+    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
     mp_parse_node_free(pn);
 
     if (module_fun == mp_const_none) {
diff --git a/py/compile.c b/py/compile.c
index 6ede842397f72b4a6712b035f5d290e741990142..62c07cfd8c7d0661ea7a457bab7a7779f6a20cc8 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -36,12 +36,6 @@ typedef enum {
 #define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))
 #define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))
 
-#define EMIT_OPT_NONE           (0)
-#define EMIT_OPT_BYTE_CODE      (1)
-#define EMIT_OPT_NATIVE_PYTHON  (2)
-#define EMIT_OPT_VIPER          (3)
-#define EMIT_OPT_ASM_THUMB      (4)
-
 typedef struct _compiler_t {
     qstr source_file;
     bool is_repl;
@@ -1000,16 +994,16 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
 
     qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
     if (attr == MP_QSTR_byte_code) {
-        *emit_options = EMIT_OPT_BYTE_CODE;
+        *emit_options = MP_EMIT_OPT_BYTE_CODE;
 #if MICROPY_EMIT_NATIVE
     } else if (attr == MP_QSTR_native) {
-        *emit_options = EMIT_OPT_NATIVE_PYTHON;
+        *emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
     } else if (attr == MP_QSTR_viper) {
-        *emit_options = EMIT_OPT_VIPER;
+        *emit_options = MP_EMIT_OPT_VIPER;
 #endif
 #if MICROPY_EMIT_INLINE_THUMB
     } else if (attr == MP_QSTR_asm_thumb) {
-        *emit_options = EMIT_OPT_ASM_THUMB;
+        *emit_options = MP_EMIT_OPT_ASM_THUMB;
 #endif
     } else {
         compile_syntax_error(comp, "invalid micropython decorator");
@@ -1601,7 +1595,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
     // this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable
     // this is actually slower, but uses no heap memory
     // for viper it will be much, much faster
-    if (/*comp->scope_cur->emit_options == EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) {
+    if (/*comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER &&*/ MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_power)) {
         mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
         if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0]) 
             && MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range
@@ -3187,7 +3181,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
     }
 }
 
-mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
+mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl) {
     compiler_t *comp = m_new(compiler_t, 1);
 
     comp->source_file = source_file;
@@ -3208,7 +3202,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
     pn = fold_constants(pn);
 
     // set the outer scope
-    scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, pn, EMIT_OPT_NONE);
+    scope_t *module_scope = scope_new_and_link(comp, SCOPE_MODULE, pn, emit_opt);
 
     // compile pass 1
     comp->emit = emit_pass1_new();
@@ -3219,7 +3213,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
     for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
         if (false) {
 #if MICROPY_EMIT_INLINE_THUMB
-        } else if (s->emit_options == EMIT_OPT_ASM_THUMB) {
+        } else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) {
             compile_scope_inline_asm(comp, s, PASS_1);
 #endif
         } else {
@@ -3255,7 +3249,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
             // dummy
 
 #if MICROPY_EMIT_INLINE_THUMB
-        } else if (s->emit_options == EMIT_OPT_ASM_THUMB) {
+        } else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) {
             // inline assembly for thumb
             if (emit_inline_thumb == NULL) {
                 emit_inline_thumb = emit_inline_thumb_new(max_num_labels);
@@ -3279,8 +3273,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
             switch (s->emit_options) {
 
 #if MICROPY_EMIT_NATIVE
-                case EMIT_OPT_NATIVE_PYTHON:
-                case EMIT_OPT_VIPER:
+                case MP_EMIT_OPT_NATIVE_PYTHON:
+                case MP_EMIT_OPT_VIPER:
 #if MICROPY_EMIT_X64
                     if (emit_native == NULL) {
                         emit_native = emit_native_x64_new(max_num_labels);
@@ -3293,7 +3287,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
                     comp->emit_method_table = &emit_native_thumb_method_table;
 #endif
                     comp->emit = emit_native;
-                    comp->emit_method_table->set_native_types(comp->emit, s->emit_options == EMIT_OPT_VIPER);
+                    comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
                     break;
 #endif // MICROPY_EMIT_NATIVE
 
diff --git a/py/compile.h b/py/compile.h
index 552d36fa5a7d71f1369e84519e79e24d83b2fb12..d4a17b7a813fa22e53c7c105530a62db96f8d090 100644
--- a/py/compile.h
+++ b/py/compile.h
@@ -1 +1,9 @@
-mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl);
+enum {
+    MP_EMIT_OPT_NONE,
+    MP_EMIT_OPT_BYTE_CODE,
+    MP_EMIT_OPT_NATIVE_PYTHON,
+    MP_EMIT_OPT_VIPER,
+    MP_EMIT_OPT_ASM_THUMB,
+};
+
+mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl);
diff --git a/stm/pyexec.c b/stm/pyexec.c
index 7b4da42b0b086b2a7fed903f1a767f762267975a..f3dfd70aaba01df859a66668ac4640f0dde80082 100644
--- a/stm/pyexec.c
+++ b/stm/pyexec.c
@@ -142,7 +142,7 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo
 
     mp_lexer_free(lex);
 
-    mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
+    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, is_repl);
     mp_parse_node_free(pn);
 
     if (module_fun == mp_const_none) {
diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c
index 8bc3ec6e5e89d0fc1d2d94a16510cf4dcf6252ea..b960198ec791a61e76ca6cf517d4c655655e42fb 100644
--- a/stmhal/pyexec.c
+++ b/stmhal/pyexec.c
@@ -44,7 +44,7 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo
 
     mp_lexer_free(lex);
 
-    mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
+    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, is_repl);
     mp_parse_node_free(pn);
 
     if (module_fun == mp_const_none) {
diff --git a/teensy/main.c b/teensy/main.c
index 740d0b238aa234ad5137f1404f2caf72c57f2095..139bd886839d0e92d1caedef66847f0bc64af7e5 100644
--- a/teensy/main.c
+++ b/teensy/main.c
@@ -359,7 +359,7 @@ bool do_file(const char *filename) {
 
     mp_lexer_free(lex);
 
-    mp_obj_t module_fun = mp_compile(pn, source_name, false);
+    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
     mp_parse_node_free(pn);
 
     if (module_fun == mp_const_none) {
@@ -422,7 +422,7 @@ void do_repl(void) {
         } else {
             // parse okay
             mp_lexer_free(lex);
-            mp_obj_t module_fun = mp_compile(pn, source_name, true);
+            mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
             if (module_fun != mp_const_none) {
                 nlr_buf_t nlr;
                 uint32_t start = micros();
diff --git a/unix/main.c b/unix/main.c
index b4a1646c28d6d3a7ddb663af2e5e06dff8862b20..3ebd9ab82b56fc05cb285e660b9a4e23b2ecfda7 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -28,6 +28,9 @@
 #include <readline/history.h>
 #endif
 
+// Default emit options
+uint emit_opt = MP_EMIT_OPT_NONE;
+
 #if MICROPY_ENABLE_GC
 // Heap size of GC heap (if enabled)
 // Make it larger on a 64 bit machine, because pointers are larger.
@@ -76,7 +79,7 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind
     printf("----------------\n");
     */
 
-    mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
+    mp_obj_t module_fun = mp_compile(pn, source_name, emit_opt, is_repl);
 
     if (module_fun == mp_const_none) {
         // compile error
@@ -221,6 +224,10 @@ int usage(char **argv) {
 "Implementation specific options:\n", argv[0]
 );
     int impl_opts_cnt = 0;
+    printf(
+"  emit={bytecode,native,viper} -- set the default code emitter\n"
+);
+    impl_opts_cnt++;
 #if MICROPY_ENABLE_GC
     printf(
 "  heapsize=<n> -- set the heap size for the GC\n"
@@ -265,6 +272,12 @@ void pre_process_options(int argc, char **argv) {
                     exit(usage(argv));
                 }
                 if (0) {
+                } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
+                    emit_opt = MP_EMIT_OPT_BYTE_CODE;
+                } else if (strcmp(argv[a + 1], "emit=native") == 0) {
+                    emit_opt = MP_EMIT_OPT_NATIVE_PYTHON;
+                } else if (strcmp(argv[a + 1], "emit=viper") == 0) {
+                    emit_opt = MP_EMIT_OPT_VIPER;
 #if MICROPY_ENABLE_GC
                 } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) {
                     heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, NULL, 0);