Компиляция Lua lib для Android – успех, но странные segfaults

Извините за длинный вопрос. Если вы хотите, пропустите часть компиляции Lua (что почти нормально) и получите прямой вопрос.

Давайте собираем библиотеку Lua, как статическую библиотеку для Android.

Загрузите последний источник и посмотрите в doc / readme.html – Создайте Lua в разделе других систем для списка файлов для компиляции.

И, конечно, посмотрите на make-файлы – посмотрите, каким образом мы должны установить флаг платформы, например linux, bsd и т. Д. Но, конечно, Android-платформы нет, поэтому у нас есть выбор, чтобы установить платформу для ANSI, Linux, Posix или Generic.

Первый вопрос: он строит нормально (с одним исключением из llex.c, о котором я расскажу ниже) даже без флага платформы, так что, возможно, это лишний?

Я установил флаг 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 

И получили ошибки, конечно

 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 

Фиксация его самым дешевым способом

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

Есть некоторые ограничения относительно locale.h в Android NDK, поэтому эта ошибка не является чем-то удивительным.

Также получили ошибки о size_t, UCHAR_MAX, INT_MAX – добавление llimits.h включается в llex.c, и теперь все ошибки исчезли.

В настоящее время существуют только предупреждения о «отсутствующем перерыве в конце дела» и «нет возврата в функции, возвращающем не-void» в статическом int llex , но мы больше не связываемся с исходным кодом Lua, потому что это не так важно.

Второй вопрос: я собираюсь программировать ад для таких быстрых исправлений?

Захватите наш свежий испеченный LuaLib в каталоге obj / armeabi и проверите его. Конечно, чтобы загружать скрипты из файловой системы Android, нам нужно написать некоторый загрузчик файлов с использованием класса AssetManager в Java, поэтому давайте сделаем это очень просто, нажав и прочитав 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); } 

результат

Он также работает, если мы читаем файл сценария с AssetManager и помещаем его в строку, которая подается в lual_dostring () . Итак, да, мы создаем lua для Android (кроме функций lua i / o, которые не будут работать, потому что stdio, как printf, не работает в Android NDK).

Однако эта сборка имеет странные ошибки, например – fps-скрипт обновляет каждый кадр, но он может упасть в любой момент со следующей ошибкой в ​​функции, которая обновляет fps с дельта-временем кадра

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); } 

И получите следующее сообщение об ошибке со всей катастрофой приложения в случайное время (1 мин – 3 мин)
Ошибка сообщения

Последний вопрос (yay, вы сделали это / пропустите скучную часть)
Почему я получаю segfaults, почему в случайное время? Скрипт FPS – это просто пример, в большинстве случаев каждый скрипт lua имеет шанс разбивать все приложение (больше вызовов == лучший шанс). Таким образом, некоторые сценарии игрока, которые иногда меняют свой каталог при новом столкновении с pos.

Я думаю, что это потому, что конфликт с мусором для Android / Java и уборщик мусора Lua, поэтому попробуйте освободить уже освобожденную память.

РЕДАКТИРОВАТЬ – ОТ ДВОЙНОГО ПУНКТА ПРИХОДИТЕ И ПОЧЕМУ:

  #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 

В функции onInit ()

  init_time_manager(&TM); 

В функции 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); 

Почему я использую указатель для двойного, а не двойного? Ну, это экономит 4 байта копирования (каждый указатель имеет размер 4, double имеет размер 8) frame_delta_time param для каждой функции, такой как update_ui (), я делаю то же самое для каждой структуры / типа больше 4 байтов, указатели константы, а не просто Struct x для доступа только для чтения. Это плохо?

Ваши изменения выглядят нормально и подходят для вашей системы. Список рассылки lua предлагает внести изменения в luaconf.h а не llex.c ( http://lua-users.org/lists/lua-l/2012-08/msg00100.html ), но это не имеет значения много. (Итак, короче говоря, вы не собираетесь в ад для этих изменений …).

Я предполагаю, что segfaults происходят, потому что некоторые из вашего моста C-lua делают что-то «плохое». Мое предположение было бы какой-то lua stack over / under flow, или доступ за пределами стека lua, используя недопустимый индекс. Вы можете отслеживать это, если вы можете построить часть моста на linux / os x и использовать valgrind. (Аналогичные инструменты существуют и для окон, но я не уверен в том,

Посмотрите на это: 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); } } 

Иногда это помогает скомпилировать lua с -DLUA_USE_APICHECK . Он будет генерировать некоторые сообщения об ошибках вместо segfaults.