android c android-ndk lua

Compilando Lua lib para Android: éxito, pero segfeults extraños



android-ndk (3)

Sus cambios se ven bien y son apropiados para su sistema. La lista de correo lua sugiere que realice los cambios en luaconf.h lugar de llex.c ( http://lua-users.org/lists/lua-l/2012-08/msg00100.html ) pero no debería importar mucho. (Entonces, en resumen, no vas a ir al infierno por estos cambios ...).

Supongo que los segfeults están sucediendo porque parte de tu puente C-lua está haciendo algo "malo". Mi suposición sería algún tipo de lua stack over / under flow, o acceder fuera de la pila lua utilizando un índice no válido. Puede rastrear esto si puede construir la parte puente en linux / os x y usar valgrind. (Existen herramientas similares para Windows también, pero no estoy seguro acerca de nativo de Android)

Perdón por una pregunta larga. Si lo desea, omita la parte sobre la compilación de Lua (que casi está bien) y pase directamente a la última pregunta.

Compilemos la biblioteca de Lua como una biblioteca estática para Android.

Descargue la última fuente y mire en doc / readme.html - Creando Lua en otra sección de sistemas para obtener una lista de archivos para compilar.

Y, por supuesto, mire en makefiles, vea qué manera casual debemos establecer como indicador de plataforma, como linux, bsd, etc. Pero, por supuesto, no hay una plataforma Android, por lo que tenemos la opción de configurar la plataforma para ANSI, Linux, Posix o Generic.

Primera pregunta: construye bien (con una excepción sobre llex.c, que describiré a continuación), incluso sin una bandera de plataforma, así que quizás esto sea innecesario.

Configuro la bandera de ANSI.

Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := lua LOCAL_CFLAGS := -DLUA_ANSI LOCAL_SRC_FILES := lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c include $(BUILD_STATIC_LIBRARY)

Application.mk

APP_MODULES := lua APP_PLATFORM := android-8 APP_OPTIM := release APP_ABI := armeabi

Y obtuve errores por supuesto

Compile thumb : lua <= llex.c jni/llex.c: In function ''trydecpoint'': jni/llex.c:214:18: error: ''struct lconv'' has no member named ''decimal_point'' #if !defined(getlocaledecpoint) #define getlocaledecpoint() (localeconv()->decimal_point[0]) //Missing struct member #endif

Reparándolo de la manera más económica

#if !defined(getlocaledecpoint) #define getlocaledecpoint() (''.'') //Code-monkey style #endif

Existen algunas limitaciones sobre locale.h en Android NDK, por lo que este error no es sorprendente.

También obtuve errores sobre size_t, UCHAR_MAX, INT_MAX, agregando llimits.h include into llex.c y todos los errores desaparecieron.

Ahora solo existen advertencias sobre "falta de corte al final del caso" y "no retorno en la función que devuelve no válido " en int llex estático , pero ya no interferimos con el código fuente de Lua porque no es vital.

Segunda pregunta: ¿voy a ir al infierno de programadores por soluciones tan rápidas?

Tome nuestro LuaLib recién horneado en el directorio obj / armeabi y permítanos probarlo. Por supuesto, para cargar guiones del sistema de archivos de Android, necesitamos escribir algún cargador de archivos con el uso de la clase AssetManager en Java, así que hagámoslo muy simple presionando y leyendo lua global vars.

TestLua - Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := lua LOCAL_SRC_FILES := liblua.a LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/lua-inc //Where .h files from lua src stored include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := LuaLibTest LOCAL_STATIC_LIBRARIES:= lua LOCAL_SRC_FILES := LuaLibTest.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)

LuaLibTest.c

#include "LuaLibTest.h" #include "lua-inc/lua.h" #include "lua-inc/lauxlib.h" #include <android/log.h> #define INFO_TAG "[INFO]" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, INFO_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_com_lualib_test_NativeLib_testLua(JNIEnv* env, jclass _class) { LOGI("HI FROM C"); lua_State* L = luaL_newstate(); luaL_openlibs(L); lua_pushstring(L, "Some string from Android C" ); lua_setglobal(L, "TEST" ); lua_getglobal(L, "TEST" ); const char* res = lua_tostring(L, lua_gettop(L)); LOGI("LUA TEST VAL: %s", res); lua_pop(L, 1); lua_close(L); }

También funciona si leemos el archivo de script con AssetManager y ponemos su contenido en la cadena que se ingresa en lual_dostring () . Así que sí, creamos lua para Android (excepto las funciones lua i / o, que no funcionarán, porque stdio como printf no funciona en Android NDK).

Sin embargo, esta compilación tiene errores extraños, por ejemplo, la actualización del script fps en cada cuadro, pero puede caer en cualquier momento con el próximo error en la función, lo que actualiza los fps con el tiempo delta del marco.

FPS.lua

FPS = {} function initFPS() FPS.fps = 0 FPS.last_fps = 0 FPS.frames_count = 0 FPS.frames_time = 0.0 local fps_msg = "FPS: " .. FPS.fps c_set_fps(fps_msg);//Set some label in app - c function end function updateFPS(frameDeltaTime) FPS.frames_count = FPS.frames_count + 1 FPS.frames_time = FPS.frames_time + frameDeltaTime if FPS.frames_time >= 1000.0 then FPS.frames_time = 0.0; FPS.fps = FPS.frames_count; FPS.frames_count = 0; if FPS.last_fps ~= FPS.fps then local fps_msg = "FPS: " .. FPS.fps c_set_fps(fps_msg); FPS.last_fps = FPS.fps end end end

FPS.c

void update_fps(const double* frame_delta_time) //SEGFAULT at this, at random time { lua_State* l = get_lua(); lua_getglobal(l, "updateFPS"); lua_pushnumber(l, *frame_delta_time); lua_call(l, 1, 0); }

Y obtenga el siguiente mensaje de error con bloqueo de la aplicación completa en un momento aleatorio (1 min - 3 min)

Última pregunta (yay, lo hiciste / omite parte aburrida)
¿Por qué obtengo segfaults, por qué al azar? El script FPS es solo un ejemplo, como mucho, cada script de lua tiene la posibilidad de bloquear toda la aplicación (más llamadas == mejor oportunidad). Entonces, algunas secuencias de comandos de jugadores que cambian su directorio en una nueva posición de bloqueo a veces también.

Creo que es porque hay un conflicto entre el limpiador de basura Android / Java y el limpiador de basura Lua, así que intenta liberar la memoria ya liberada.

EDITAR - DESDE ALLÍ DOBLE PUNTERO VEN Y POR QUÉ:

#define MS_1_SEC 1000.0 typedef struct time_manager { double _time; double delta_time; }time_manager; static double get_ms(s_time* time)//get time in ms { return MS_1_SEC * time->tv_sec + (double) time->tv_nsec / NS_1_SEC; } double get_time_now() { s_time time_now; clock_gettime(CLOCK_REALTIME, &time_now); return get_ms(&time_now); } void init_time_manager(time_manager* tm) { tm->_time = get_time_now(); tm->delta_time = 0.0; } void update_time_manager(time_manager* tm) { double time_now = get_time_now(); tm->delta_time = time_now - tm->_time; tm->_time = time_now; } static time_manager TM;//Global static var for whole render module

En la función onInit ()

init_time_manager(&TM);

En la función onDraw ()

double* frame_time = &TM.delta_time;//get pointer to delta time update_ui(frame_time);//Pass it every function update_sprites(frame_time); update_fps(frame_time); ... draw_fps(); update_time_manager(&TM);

¿Por qué uso el puntero para duplicar en lugar de solo el doble? Bueno, ahorra 4 bytes de copia (cada puntero tiene un tamaño de 4, el doble tiene un tamaño de 8) frame_delta_time param para cada función como update_ui (), hago lo mismo para cada estructura / tipo de más de 4 bytes, const punteros en lugar de solo struct x para acceso de solo lectura. ¿Es esto malo?


Mira esto: http://comments.gmane.org/gmane.comp.security.nmap.devel/14966

static void trydecpoint (LexState *ls, SemInfo *seminfo) { char old = ls->decpoint; ls->decpoint = ''.''; //ls->decpoint = getlocaledecpoint(); // try to fix error: ''struct lconv'' has no member named ''decimal_point'' -------- look at here buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (!buff2d(ls->buff, &seminfo->r)) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, ''.''); /* undo change (for error message) */ lexerror(ls, "malformed number", TK_NUMBER); } }


Algunas veces es -DLUA_USE_APICHECK compilar lua con -DLUA_USE_APICHECK . Generará algunos mensajes de error en lugar de segfaults.