diff options
-rw-r--r-- | py/bc.h | 1 | ||||
-rw-r--r-- | py/builtinimport.c | 2 | ||||
-rw-r--r-- | py/emitglue.c | 2 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objexcept.c | 43 | ||||
-rw-r--r-- | py/py.mk | 7 | ||||
-rw-r--r-- | py/showbc.c | 18 | ||||
-rw-r--r-- | py/vm.c | 46 | ||||
-rw-r--r-- | unix/file.c | 2 | ||||
-rw-r--r-- | unix/modffi.c | 34 | ||||
-rw-r--r-- | unix/modsocket.c | 8 | ||||
-rw-r--r-- | windows/README | 2 |
12 files changed, 117 insertions, 49 deletions
@@ -13,6 +13,7 @@ typedef struct _mp_exc_stack { mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret); mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, volatile mp_obj_t inject_exc); void mp_byte_code_print(const byte *code, int len); +void mp_byte_code_print2(const byte *code, int len); // Helper macros to access pointer with least significant bit holding a flag #define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1))) diff --git a/py/builtinimport.c b/py/builtinimport.c index 4a2f6510c3..07978e61d7 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -122,7 +122,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { // TODO handle compile error correctly mp_locals_set(old_locals); mp_globals_set(old_globals); - return; + nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module")); } // complied successfully, execute it diff --git a/py/emitglue.c b/py/emitglue.c index 8b1fd97021..dddeea1b57 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -159,7 +159,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp } mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) { - DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, argrs); + DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args); // make function object mp_obj_t ffun; if (n_closed_over & 0x100) { @@ -351,6 +351,7 @@ mp_obj_t mp_obj_new_float(mp_float_t val); mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); #endif mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type); +mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg); mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) diff --git a/py/objexcept.c b/py/objexcept.c index 781a00405c..160cf09fd4 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -14,11 +14,11 @@ typedef struct _mp_obj_exception_t { mp_obj_base_t base; mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now - mp_obj_tuple_t args; + mp_obj_tuple_t *args; } mp_obj_exception_t; // Instance of MemoryError exception - needed by mp_malloc_fail -const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}}; +const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, mp_const_empty_tuple}; // Local non-heap memory for allocating an exception when we run out of RAM STATIC mp_obj_exception_t mp_emergency_exception_obj; @@ -26,7 +26,7 @@ STATIC mp_obj_exception_t mp_emergency_exception_obj; // Instance of GeneratorExit exception - needed by generator.close() // This would belong to objgenerator.c, but to keep mp_obj_exception_t // definition module-private so far, have it here. -const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}}; +const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, mp_const_empty_tuple}; STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = o_in; @@ -36,15 +36,15 @@ STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ... print(env, "%s: ", qstr_str(o->base.type->name)); } if (kind == PRINT_STR || kind == PRINT_EXC) { - if (o->args.len == 0) { + if (o->args == NULL || o->args->len == 0) { print(env, ""); return; - } else if (o->args.len == 1) { - mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR); + } else if (o->args->len == 1) { + mp_obj_print_helper(print, env, o->args->items[0], PRINT_STR); return; } } - tuple_print(print, env, &o->args, kind); + tuple_print(print, env, o->args, kind); } STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -54,35 +54,35 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in))); } - mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, n_args); + mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. o = &mp_emergency_exception_obj; // We can't store any args. n_args = 0; + o->args = mp_const_empty_tuple; + } else { + o->args = mp_obj_new_tuple(n_args, args); } o->base.type = type; o->traceback = MP_OBJ_NULL; - o->args.base.type = &mp_type_tuple; - o->args.len = n_args; - memcpy(o->args.items, args, n_args * sizeof(mp_obj_t)); return o; } // Get exception "value" - that is, first argument, or None mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { mp_obj_exception_t *self = self_in; - if (self->args.len == 0) { + if (self->args->len == 0) { return mp_const_none; } else { - return self->args.items[0]; + return self->args->items[0]; } } STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_exception_t *self = self_in; if (attr == MP_QSTR_args) { - dest[0] = &self->args; + dest[0] = self->args; } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) { dest[0] = mp_obj_exception_get_value(self); } @@ -191,6 +191,11 @@ mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { return mp_obj_new_exception_args(exc_type, 0, NULL); } +// "Optimized" version for common(?) case of having 1 exception arg +mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { + return mp_obj_new_exception_args(exc_type, 1, &arg); +} + mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args) { assert(exc_type->make_new == mp_obj_exception_make_new); return exc_type->make_new((mp_obj_t)exc_type, n_args, 0, args); @@ -205,20 +210,18 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object - mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 1); + mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0); if (o == NULL) { // Couldn't allocate heap memory; use local data instead. // Unfortunately, we won't be able to format the string... o = &mp_emergency_exception_obj; o->base.type = exc_type; o->traceback = MP_OBJ_NULL; - o->args.base.type = &mp_type_tuple; - o->args.len = 0; + o->args = mp_const_empty_tuple; } else { o->base.type = exc_type; o->traceback = MP_OBJ_NULL; - o->args.base.type = &mp_type_tuple; - o->args.len = 1; + o->args = mp_obj_new_tuple(1, NULL); if (fmt == NULL) { // no message @@ -231,7 +234,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char va_start(ap, fmt); vstr_vprintf(vstr, fmt, ap); va_end(ap); - o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); + o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); vstr_free(vstr); } } @@ -7,6 +7,9 @@ HEADER_BUILD = $(BUILD)/genhdr # file containing qstr defs for the core Python bit PY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h +# some code is performance bottleneck and compiled with other optimization options +CSUPEROPT = -O3 + # py object files PY_O_BASENAME = \ nlrx86.o \ @@ -135,8 +138,8 @@ $(PY_BUILD)/emitnthumb.o: py/emitnative.c $(call compile_c) # optimising gc for speed; 5ms down to 4ms on pybv2 -$(PY_BUILD)/gc.o: CFLAGS += -O3 +$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT) # optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster) -$(PY_BUILD)/vm.o: CFLAGS += -O3 +$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT) diff --git a/py/showbc.c b/py/showbc.c index 4a8e12e68b..17cb2eadd6 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -28,6 +28,8 @@ ip += sizeof(machine_uint_t); \ } while (0) +void mp_byte_code_print2(const byte *ip, int len); + void mp_byte_code_print(const byte *ip, int len) { const byte *ip_start = ip; @@ -71,7 +73,11 @@ void mp_byte_code_print(const byte *ip, int len) { printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } + mp_byte_code_print2(ip, len - 0); +} +void mp_byte_code_print2(const byte *ip, int len) { + const byte *ip_start = ip; machine_uint_t unum; qstr qstr; while (ip - ip_start < len) { @@ -418,15 +424,19 @@ void mp_byte_code_print(const byte *ip, int len) { printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum); break; - case MP_BC_MAKE_CLOSURE: + case MP_BC_MAKE_CLOSURE: { DECODE_PTR; - printf("MAKE_CLOSURE " UINT_FMT, unum); + machine_uint_t n_closed_over = *ip++; + printf("MAKE_CLOSURE " UINT_FMT " " UINT_FMT, unum, n_closed_over); break; + } - case MP_BC_MAKE_CLOSURE_DEFARGS: + case MP_BC_MAKE_CLOSURE_DEFARGS: { DECODE_PTR; - printf("MAKE_CLOSURE_DEFARGS " UINT_FMT, unum); + machine_uint_t n_closed_over = *ip++; + printf("MAKE_CLOSURE_DEFARGS " UINT_FMT " " UINT_FMT, unum, n_closed_over); break; + } case MP_BC_CALL_FUNCTION: DECODE_UINT; @@ -13,7 +13,18 @@ #include "bc.h" #include "objgenerator.h" +// With these macros you can tune the maximum number of state slots +// that will be allocated on the stack. Any function that needs more +// than this will use the heap. +#define VM_MAX_STATE_ON_STACK (10) +#define VM_MAX_EXC_STATE_ON_STACK (4) + #define DETECT_VM_STACK_OVERFLOW (0) +#if 0 +#define TRACE(ip) mp_byte_code_print2(ip, 1); +#else +#define TRACE(ip) +#endif // Value stack grows up (this makes it incompatible with native C stack, but // makes sure that arguments to functions are in natural order arg1..argN @@ -80,20 +91,20 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, ip += 4; // allocate state for locals and stack - mp_obj_t temp_state[10]; + mp_obj_t temp_state[VM_MAX_STATE_ON_STACK]; mp_obj_t *state = &temp_state[0]; #if DETECT_VM_STACK_OVERFLOW n_state += 1; #endif - if (n_state > 10) { + if (n_state > VM_MAX_STATE_ON_STACK) { state = m_new(mp_obj_t, n_state); } mp_obj_t *sp = &state[0] - 1; // allocate state for exceptions - mp_exc_stack_t exc_state[4]; + mp_exc_stack_t exc_state[VM_MAX_EXC_STATE_ON_STACK]; mp_exc_stack_t *exc_stack = &exc_state[0]; - if (n_exc_stack > 4) { + if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) { exc_stack = m_new(mp_exc_stack_t, n_exc_stack); } mp_exc_stack_t *exc_sp = &exc_stack[0] - 1; @@ -140,19 +151,38 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, } #endif + mp_vm_return_kind_t ret_kind; switch (vm_return_kind) { case MP_VM_RETURN_NORMAL: + // return value is in *sp *ret = *sp; - return MP_VM_RETURN_NORMAL; + ret_kind = MP_VM_RETURN_NORMAL; + break; + case MP_VM_RETURN_EXCEPTION: + // return value is in state[n_state - 1] *ret = state[n_state - 1]; - return MP_VM_RETURN_EXCEPTION; + ret_kind = MP_VM_RETURN_EXCEPTION; + break; + case MP_VM_RETURN_YIELD: // byte-code shouldn't yield default: assert(0); *ret = mp_const_none; - return MP_VM_RETURN_NORMAL; + ret_kind = MP_VM_RETURN_NORMAL; } + + // free the state if it was allocated on the heap + if (n_state > VM_MAX_STATE_ON_STACK) { + m_free(state, n_state); + } + + // free the exception state if it was allocated on the heap + if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) { + m_free(exc_stack, n_exc_stack); + } + + return ret_kind; } // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) @@ -168,6 +198,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i #if MICROPY_USE_COMPUTED_GOTO #include "vmentrytable.h" #define DISPATCH() do { \ + TRACE(ip); \ save_ip = ip; \ op = *ip++; \ goto *entry_table[op]; \ @@ -223,6 +254,7 @@ dispatch_loop: #if MICROPY_USE_COMPUTED_GOTO DISPATCH(); #else + TRACE(ip); save_ip = ip; op = *ip++; diff --git a/unix/file.c b/unix/file.c index 5bda34013f..041e28e956 100644 --- a/unix/file.c +++ b/unix/file.c @@ -106,7 +106,7 @@ STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const int fd = open(fname, mode, 0644); if (fd == -1) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); } return fdfile_new(fd); } diff --git a/unix/modffi.c b/unix/modffi.c index 83bc2c5454..56ea6ed307 100644 --- a/unix/modffi.c +++ b/unix/modffi.c @@ -12,6 +12,22 @@ #include "runtime.h" #include "binary.h" +/* + * modffi uses character codes to encode a value type, based on "struct" + * module type codes, with some extensions and overridings. + * + * Extra/overridden typecodes: + * v - void, can be used only as return type + * P - const void*, pointer to read-only memory + * p - void*, meaning pointer to a writable memory (note that this + * clashes with struct's "p" as "Pascal string"). + * s - as argument, the same as "p", as return value, causes string + * to be allocated and returned, instead of pointer value. + * + * Note: all constraint specified by typecode can be not enforced at this time, + * but may be later. + */ + typedef struct _mp_obj_opaque_t { mp_obj_base_t base; void *val; @@ -63,8 +79,8 @@ STATIC ffi_type *char2ffi_type(char c) case 'L': return &ffi_type_ulong; case 'f': return &ffi_type_float; case 'd': return &ffi_type_double; - case 'p': // Deprecated - conflicts with struct module - case 'P': + case 'P': // const void* + case 'p': // void* case 's': return &ffi_type_pointer; case 'v': return &ffi_type_void; default: return NULL; @@ -83,7 +99,7 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) } // TODO: Support actual libffi type objects - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Unknown type")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "Unknown type")); } STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) @@ -129,7 +145,7 @@ STATIC mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) { void *sym = dlsym(self->handle, symname); if (sym == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); } int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(args[3])); mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type*, nparams); @@ -147,7 +163,7 @@ STATIC mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) { int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Error in ffi_prep_cif")); } return o; @@ -184,12 +200,12 @@ STATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Error in ffi_prep_cif")); } res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, func_in, o->func); if (res != FFI_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "ffi_prep_closure_loc")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ffi_prep_closure_loc")); } return o; @@ -203,7 +219,7 @@ STATIC mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symna void *sym = dlsym(self->handle, symname); if (sym == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); } mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t); o->base.type = &ffivar_type; @@ -219,7 +235,7 @@ STATIC mp_obj_t ffimod_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL); if (mod == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)errno))); } mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t); o->base.type = type_in; diff --git a/unix/modsocket.c b/unix/modsocket.c index 6a2ada91f1..b7d167c8ad 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -33,7 +33,7 @@ STATIC const mp_obj_type_t microsocket_type; // Helper functions #define RAISE_ERRNO(err_flag, error_val) \ { if (err_flag == -1) \ - { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error_val)); } } + { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)error_val))); } } STATIC mp_obj_socket_t *socket_new(int fd) { mp_obj_socket_t *o = m_new_obj(mp_obj_socket_t); @@ -269,7 +269,7 @@ STATIC mp_obj_t mod_socket_inet_aton(mp_obj_t arg) { const char *s = mp_obj_str_get_str(arg); struct in_addr addr; if (!inet_aton(s, &addr)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid IP address")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); } return mp_obj_new_int(addr.s_addr); @@ -282,7 +282,8 @@ STATIC mp_obj_t mod_socket_gethostbyname(mp_obj_t arg) { const char *s = mp_obj_str_get_str(arg); struct hostent *h = gethostbyname(s); if (h == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + // CPython: socket.herror + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT((machine_int_t)h_errno))); } assert(h->h_length == 4); return mp_obj_new_int(*(int*)*h->h_addr_list); @@ -314,6 +315,7 @@ STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { int res = getaddrinfo(host, serv, NULL/*&hints*/, &addr); if (res != 0) { + // CPython: socket.gaierror nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); } assert(addr); diff --git a/windows/README b/windows/README index 615ada2012..28940f2c3d 100644 --- a/windows/README +++ b/windows/README @@ -4,7 +4,7 @@ It is based on Unix port, and expected to remain so. To cross-compile under Debian/Ubuntu Linux system: sudo apt-get install mingw32 mingw32-binutils mingw32-runtime -make CC=i586-mingw32msvc-gcc +make CROSS_COMPILE=i586-mingw32msvc- The port requires additional testing, debugging, and patches. Please consider to contribute. |