diff --git a/src/Makefile b/src/Makefile index b1197f3b..d40a4927 100644 --- a/src/Makefile +++ b/src/Makefile @@ -328,7 +328,7 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \ lj_opt_dce.o lj_opt_loop.o \ lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \ lj_asm.o lj_trace.o lj_gdbjit.o \ - lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_cparse.o \ + lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_clib.o lj_cparse.o \ lj_lib.o lj_alloc.o lib_aux.o \ $(LJLIB_O) lib_init.o diff --git a/src/Makefile.dep b/src/Makefile.dep index 8481b9f0..ba31804c 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -22,7 +22,8 @@ lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \ - lj_cdata.h lj_cconv.h lj_ccall.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h + lj_cdata.h lj_cconv.h lj_ccall.h lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h \ + lj_libdef.h lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ @@ -63,6 +64,9 @@ lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h +lj_clib.o: lj_clib.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ + lj_err.h lj_errmsg.h lj_tab.h lj_str.h lj_udata.h lj_ctype.h lj_cconv.h \ + lj_cdata.h lj_clib.h lj_cparse.o: lj_cparse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h lj_frame.h \ lj_bc.h lj_vm.h lj_char.h @@ -156,13 +160,13 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \ lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h lj_alloc.h \ lj_dispatch.c lj_ff.h lj_ffdef.h luajit.h lj_vmevent.c lj_vmevent.h \ lj_api.c lj_parse.h lj_lex.c lualib.h lj_parse.c lj_ctype.c lj_cdata.c \ - lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_cparse.c lj_cparse.h \ - lj_lib.c lj_lib.h lj_ir.c lj_iropt.h lj_opt_mem.c lj_opt_fold.c \ - lj_folddef.h lj_opt_narrow.c lj_opt_dce.c lj_opt_loop.c lj_snap.h \ - lj_mcode.c lj_mcode.h lj_snap.c lj_target.h lj_target_*.h lj_record.c \ - lj_record.h lj_ffrecord.h lj_crecord.c lj_crecord.h lj_ffrecord.c \ - lj_recdef.h lj_asm.c lj_asm.h lj_trace.c lj_gdbjit.h lj_gdbjit.c \ - lj_alloc.c lib_aux.c lib_base.c lj_libdef.h lib_math.c lib_string.c \ - lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_bit.c \ - lib_jit.c lib_ffi.c lib_init.c + lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_clib.c lj_clib.h \ + lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_iropt.h \ + lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \ + lj_opt_loop.c lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c lj_target.h \ + lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \ + lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_trace.c \ + lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \ + lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \ + lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h diff --git a/src/lib_ffi.c b/src/lib_ffi.c index 3c52f7f8..2b895ed5 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c @@ -22,6 +22,7 @@ #include "lj_cdata.h" #include "lj_cconv.h" #include "lj_ccall.h" +#include "lj_clib.h" #include "lj_ff.h" #include "lj_lib.h" @@ -357,6 +358,77 @@ checkgc: #include "lj_libdef.h" +/* -- C library metamethods ----------------------------------------------- */ + +#define LJLIB_MODULE_ffi_clib + +/* Index C library by a name. */ +static TValue *ffi_clib_index(lua_State *L) +{ + TValue *o = L->base; + CLibrary *cl; + if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)) + lj_err_argt(L, 1, LUA_TUSERDATA); + cl = (CLibrary *)uddata(udataV(o)); + if (!(o+1 < L->top && tvisstr(o+1))) + lj_err_argt(L, 2, LUA_TSTRING); + return lj_clib_index(L, cl, strV(o+1)); +} + +LJLIB_CF(ffi_clib___index) +{ + TValue *tv = ffi_clib_index(L); + if (tviscdata(tv)) { + CTState *cts = ctype_cts(L); + GCcdata *cd = cdataV(tv); + CType *s = ctype_get(cts, cd->typeid); + if (ctype_isextern(s->info)) { + CTypeID sid = ctype_cid(s->info); + void *sp = *(void **)cdataptr(cd); + if (lj_cconv_tv_ct(cts, ctype_raw(cts, sid), sid, L->top-1, sp)) + lj_gc_check(L); + return 1; + } + } + copyTV(L, L->top-1, tv); + return 1; +} + +LJLIB_CF(ffi_clib___newindex) +{ + TValue *tv = ffi_clib_index(L); + TValue *o = L->base+2; + if (o < L->top && tviscdata(tv)) { + CTState *cts = ctype_cts(L); + GCcdata *cd = cdataV(tv); + CType *d = ctype_get(cts, cd->typeid); + if (ctype_isextern(d->info)) { + CTInfo qual = 0; + for (;;) { /* Skip attributes and collect qualifiers. */ + d = ctype_child(cts, d); + if (!ctype_isattrib(d->info)) break; + if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size; + } + if (!((d->info|qual) & CTF_CONST)) { + lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0); + return 0; + } + } + } + lj_err_caller(L, LJ_ERR_FFI_WRCONST); + return 0; /* unreachable */ +} + +LJLIB_CF(ffi_clib___gc) +{ + TValue *o = L->base; + if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB) + lj_clib_unload((CLibrary *)uddata(udataV(o))); + return 0; +} + +#include "lj_libdef.h" + /* -- FFI library functions ----------------------------------------------- */ #define LJLIB_MODULE_ffi @@ -567,6 +639,17 @@ LJLIB_CF(ffi_abi) #undef H_ +LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */ + +LJLIB_CF(ffi_load) +{ + GCstr *name = lj_lib_checkstr(L, 1); + int global = (L->base+1 < L->top && tvistruecond(L->base+1)); + lj_clib_load(L, tabref(curr_func(L)->c.env), name, global); + return 1; +} + +LJLIB_PUSH(top-4) LJLIB_SET(C) LJLIB_PUSH(top-3) LJLIB_SET(os) LJLIB_PUSH(top-2) LJLIB_SET(arch) @@ -579,8 +662,9 @@ LUALIB_API int luaopen_ffi(lua_State *L) lj_ctype_init(L); LJ_LIB_REG_(L, NULL, ffi_meta); /* NOBARRIER: basemt is a GC root. */ - L->top--; - setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top))); + setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1))); + LJ_LIB_REG_(L, NULL, ffi_clib); + lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */ lua_pushliteral(L, LJ_OS_NAME); lua_pushliteral(L, LJ_ARCH_NAME); LJ_LIB_REG_(L, NULL, ffi); /* Note: no global "ffi" created! */ diff --git a/src/lj_cdata.c b/src/lj_cdata.c index fd16c86c..5bd55237 100644 --- a/src/lj_cdata.c +++ b/src/lj_cdata.c @@ -55,7 +55,8 @@ void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd) if (LJ_LIKELY(!cdataisv(cd))) { CType *ct = ctype_raw(ctype_ctsG(g), cd->typeid); CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR; - lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info)); + lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) || + ctype_isextern(ct->info)); lj_mem_free(g, cd, sizeof(GCcdata) + sz); } else { lj_mem_free(g, memcdatav(cd), sizecdatav(cd)); diff --git a/src/lj_cdata.h b/src/lj_cdata.h index f1ab2153..5b6bd17b 100644 --- a/src/lj_cdata.h +++ b/src/lj_cdata.h @@ -38,7 +38,10 @@ static LJ_AINLINE void cdata_setptr(void *p, CTSize sz, const void *v) static LJ_AINLINE GCcdata *lj_cdata_new(CTState *cts, CTypeID id, CTSize sz) { GCcdata *cd; - lua_assert(lj_ctype_size(cts, id) == sz); +#ifdef LUA_USE_ASSERT + CType *ct = ctype_raw(cts, id); + lua_assert((ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR) == sz); +#endif cd = (GCcdata *)lj_mem_newgco(cts->L, sizeof(GCcdata) + sz); cd->gct = ~LJ_TCDATA; cd->typeid = ctype_check(cts, id); diff --git a/src/lj_clib.c b/src/lj_clib.c new file mode 100644 index 00000000..91309eb2 --- /dev/null +++ b/src/lj_clib.c @@ -0,0 +1,294 @@ +/* +** FFI C library loader. +** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h +*/ + +#include "lj_obj.h" + +#if LJ_HASFFI + +#include "lj_gc.h" +#include "lj_err.h" +#include "lj_tab.h" +#include "lj_str.h" +#include "lj_udata.h" +#include "lj_ctype.h" +#include "lj_cconv.h" +#include "lj_cdata.h" +#include "lj_clib.h" + +/* -- OS-specific functions ----------------------------------------------- */ + +#if LJ_TARGET_DLOPEN + +#include + +#if defined(RTLD_DEFAULT) +#define CLIB_DEFHANDLE RTLD_DEFAULT +#elif LJ_TARGET_OSX || LJ_TARGET_BSD +#define CLIB_DEFHANDLE ((void *)-2) +#else +#define CLIB_DEFHANDLE NULL +#endif + +LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L) +{ + lj_err_callermsg(L, dlerror()); +} + +#if LJ_TARGET_OSX +#define CLIB_SOEXT "%s.dylib" +#else +#define CLIB_SOEXT "%s.so" +#endif + +static const char *clib_extname(lua_State *L, GCstr *name) +{ + const char *s = strdata(name); + if (!strchr(s, '/')) { + if (!strchr(s, '.')) { + s = lj_str_pushf(L, CLIB_SOEXT, s); + L->top--; + } + if (!(s[0] == 'l' && s[1] == 'i' && s[2] == 'b')) { + s = lj_str_pushf(L, "lib%s", s); + L->top--; + } + } + return s; +} + +static void *clib_loadlib(lua_State *L, GCstr *name, int global) +{ + void *h = dlopen(clib_extname(L, name), + RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); + if (!h) clib_error(L); + return h; +} + +static void clib_unloadlib(CLibrary *cl) +{ + if (!cl->handle && cl->handle != CLIB_DEFHANDLE) + dlclose(cl->handle); +} + +static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) +{ + void *p = dlsym(cl->handle, strdata(name)); + if (!p) clib_error(L); + return p; +} + +#elif LJ_TARGET_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#ifndef WINVER +#define WINVER 0x0500 +#endif +#include + +#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS +#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 +BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); +#endif + +#define CLIB_DEFHANDLE ((void *)-1) + +/* Default libraries. */ +enum { + CLIB_HANDLE_EXE, + CLIB_HANDLE_DLL, + CLIB_HANDLE_CRT, + CLIB_HANDLE_KERNEL32, + CLIB_HANDLE_USER32, + CLIB_HANDLE_GDI32, + CLIB_HANDLE_MAX +}; + +static void *clib_def_handle[CLIB_HANDLE_MAX]; + +LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, + const char *name) +{ + DWORD err = GetLastError(); + char buf[128]; + if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, buf, sizeof(buf), NULL)) + buf[0] = '\0'; + lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf)); +} + +static int clib_needext(const char *s) +{ + while (*s) { + if (*s == '/' || *s == '\\' || *s == '.') return 0; + s++; + } + return 1; +} + +static const char *clib_extname(lua_State *L, GCstr *name) +{ + const char *s = strdata(name); + if (clib_needext(s)) { + s = lj_str_pushf(L, "%s.dll", s); + L->top--; + } + return s; +} + +static void *clib_loadlib(lua_State *L, GCstr *name, int global) +{ + void *h = (void *)LoadLibraryA(clib_extname(L, name)); + if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", strdata(name)); + UNUSED(global); + return h; +} + +static void clib_unloadlib(CLibrary *cl) +{ + if (cl->handle == CLIB_DEFHANDLE) { + MSize i; + for (i = 0; i < CLIB_HANDLE_MAX; i++) + if (clib_def_handle[i]) + FreeLibrary((HINSTANCE)clib_def_handle[i]); + } else if (!cl->handle) { + FreeLibrary((HINSTANCE)cl->handle); + } +} + +static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) +{ + const char *sym = strdata(name); + void *p; + if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ + MSize i; + for (i = 0; i < CLIB_HANDLE_MAX; i++) { + HINSTANCE h = (HINSTANCE)clib_def_handle[i]; + if (!(void *)h) { /* Resolve default library handles (once). */ + switch (i) { + case CLIB_HANDLE_EXE: GetModuleHandleExA(0, NULL, &h); break; + case CLIB_HANDLE_DLL: + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (const char *)clib_def_handle, &h); + break; + case CLIB_HANDLE_CRT: + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (const char *)&_fmode, &h); + break; + case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break; + case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break; + case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break; + } + if (!h) continue; + clib_def_handle[i] = (void *)h; + } + p = (void *)GetProcAddress(h, sym); + if (p) break; + } + } else { + p = (void *)GetProcAddress((HINSTANCE)cl->handle, sym); + } + if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); + return p; +} + +#else + +#define CLIB_DEFHANDLE NULL + +static void *clib_loadlib(lua_State *L, GCstr *name, int global) +{ + lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); + UNUSED(name); UNUSED(global); + return NULL; +} + +static void clib_unloadlib(CLibrary *cl) +{ + UNUSED(cl); +} + +static void *clib_getsym(lua_State *L, CLibrary *cl, GCstr *name) +{ + lj_err_callermsg(L, "no support for resolving symbols for this OS"); + UNUSED(cl); UNUSED(name); + return NULL; +} + +#endif + +/* -- C library indexing -------------------------------------------------- */ + +/* Namespace for C library indexing. */ +#define CLNS_INDEX \ + ((1u<cache, name); + if (LJ_UNLIKELY(tvisnil(tv))) { + CTState *cts = ctype_cts(L); + CType *ct; + CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); + if (!id) + lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); + if (ctype_isconstval(ct->info)) { + CType *ctt = ctype_child(cts, ct); + lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4); + if ((ctt->info & CTF_UNSIGNED) && ctt->size == 4) + setnumV(tv, (lua_Number)(uint32_t)ct->size); + else + setnumV(tv, (lua_Number)(int32_t)ct->size); + } else { + void *p = clib_getsym(L, cl, name); + GCcdata *cd; + lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info)); + cd = lj_cdata_new(cts, id, CTSIZE_PTR); + *(void **)cdataptr(cd) = p; + setcdataV(L, tv, cd); + } + } + return tv; +} + +/* -- C library management ------------------------------------------------ */ + +/* Create a new CLibrary object and push it on the stack. */ +static CLibrary *clib_new(lua_State *L, GCtab *mt) +{ + GCtab *t = lj_tab_new(L, 0, 0); + GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t); + CLibrary *cl = (CLibrary *)uddata(ud); + cl->cache = t; + ud->udtype = UDTYPE_FFI_CLIB; + /* NOBARRIER: The GCudata is new (marked white). */ + setgcref(ud->metatable, obj2gco(mt)); + setudataV(L, L->top++, ud); + return cl; +} + +/* Load a C library. */ +void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) +{ + void *handle = clib_loadlib(L, name, global); + CLibrary *cl = clib_new(L, mt); + cl->handle = handle; +} + +/* Unload a C library. */ +void lj_clib_unload(CLibrary *cl) +{ + clib_unloadlib(cl); + cl->handle = NULL; +} + +/* Create the default C library object. */ +void lj_clib_default(lua_State *L, GCtab *mt) +{ + CLibrary *cl = clib_new(L, mt); + cl->handle = CLIB_DEFHANDLE; +} + +#endif diff --git a/src/lj_clib.h b/src/lj_clib.h new file mode 100644 index 00000000..86045d24 --- /dev/null +++ b/src/lj_clib.h @@ -0,0 +1,26 @@ +/* +** FFI C library loader. +** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h +*/ + +#ifndef _LJ_CLIB_H +#define _LJ_CLIB_H + +#include "lj_obj.h" + +#if LJ_HASFFI + +/* C library namespace. */ +typedef struct CLibrary { + void *handle; /* Opaque handle for dynamic library loader. */ + GCtab *cache; /* Cache for resolved symbols. Anchored in ud->env. */ +} CLibrary; + +LJ_FUNC TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name); +LJ_FUNC void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global); +LJ_FUNC void lj_clib_unload(CLibrary *cl); +LJ_FUNC void lj_clib_default(lua_State *L, GCtab *mt); + +#endif + +#endif diff --git a/src/lj_ctype.h b/src/lj_ctype.h index 0c581370..c804b706 100644 --- a/src/lj_ctype.h +++ b/src/lj_ctype.h @@ -187,6 +187,7 @@ typedef struct CTState { #define ctype_isfield(info) (ctype_type((info)) == CT_FIELD) #define ctype_isbitfield(info) (ctype_type((info)) == CT_BITFIELD) #define ctype_isconstval(info) (ctype_type((info)) == CT_CONSTVAL) +#define ctype_isextern(info) (ctype_type((info)) == CT_EXTERN) #define ctype_hassize(info) (ctype_type((info)) <= CT_HASSIZE) /* Combined type and flag checks. */ diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index 2d54d1e9..b139fa8d 100644 --- a/src/lj_errmsg.h +++ b/src/lj_errmsg.h @@ -153,6 +153,7 @@ ERRDEF(FFI_NUMARG, "wrong number of arguments for function call") ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS) ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed") ERRDEF(FFI_WRCONST, "attempt to write to constant location") +ERRDEF(FFI_NODECL, "missing declaration for symbol " LUA_QS) ERRDEF(FFI_NYIPACKBIT, "NYI: packed bit fields") ERRDEF(FFI_NYICALL, "NYI: cannot call this C function (yet)") #endif diff --git a/src/lj_obj.h b/src/lj_obj.h index f40ef706..f49b12f9 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h @@ -247,6 +247,7 @@ typedef struct GCudata { enum { UDTYPE_USERDATA, /* Regular userdata. */ UDTYPE_IO_FILE, /* I/O library FILE. */ + UDTYPE_FFI_CLIB, /* FFI C library namespace. */ UDTYPE__MAX }; diff --git a/src/ljamalg.c b/src/ljamalg.c index 5dafc1b5..d273753a 100644 --- a/src/ljamalg.c +++ b/src/ljamalg.c @@ -21,6 +21,10 @@ #define _GNU_SOURCE #endif +#ifndef WINVER +#define WINVER 0x0500 +#endif + #include "lua.h" #include "lauxlib.h" @@ -44,6 +48,7 @@ #include "lj_cdata.c" #include "lj_cconv.c" #include "lj_ccall.c" +#include "lj_clib.c" #include "lj_cparse.c" #include "lj_lib.c" #include "lj_ir.c"