Kompilasi Lua lib untuk Android - sukses, tetapi segfault aneh

Aristarhys 09/06/2012. 3 answers, 7.098 views
android android c android-ndk android-ndk lua

Maaf untuk pertanyaan panjang. Jika Anda mau, lewati bagian tentang kompilasi Lua (yang hampir oke) dan langsung ke pertanyaan terakhir.

Mari kompilasi perpustakaan Lua seperti perpustakaan statis untuk Android.

Unduh sumber terbaru dan lihat doc / readme.html - Building Lua on other systems bagian Building Lua on other systems untuk daftar file yang akan dikompilasi.

Dan tentu saja melihat makefiles - lihatlah dengan cara biasa kita harus mengatur bendera platform seperti linux, bsd dll. Tetapi tentu saja tidak ada platform Android, jadi kita punya pilihan untuk mengatur platform ke ANSI, Linux, Posix atau Generic.

First question: itu membangun ok (dengan satu pengecualian tentang llex.c yang akan saya jelaskan di bawah) bahkan tanpa bendera platform, jadi mungkin ini tidak perlu?

Saya mengatur bendera 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 

Dan mendapat kesalahan tentu saja

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 

Fixing it in the most cheap way

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

Ada beberapa batasan tentang locale.h di Android NDK, jadi kesalahan ini bukan yang mengejutkan.

Juga mendapat kesalahan tentang size_t, UCHAR_MAX, INT_MAX - menambahkan llimits.h include ke llex.c dan semua kesalahan hilang sekarang.

Hanya peringatan sekarang ada tentang "missing break at the end of case" dan "tidak ada pengembalian fungsi kembali non-kekosongan" di static int llex , tapi kami tidak mengacaukan kode sumber Lua lagi karena itu bukan yang penting.

Second Question: apakah saya akan ke neraka programmer untuk perbaikan cepat seperti itu?

Ambil LuaLib yang baru dipanggang di direktori obj/armeabi dan mari kita uji. Tentu saja untuk memuat skrip dari sistem file android, kita perlu menulis beberapa file loader dengan menggunakan kelas AssetManager di Java, jadi mari kita lakukan jauh sederhana dengan mendorong dan membaca lua vars global.

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

Result

Ini juga berfungsi jika kita membaca file skrip dengan AssetManager dan memasukkannya ke string yang dimasukkan ke lual_dostring() . Jadi ya, kami membangun lua untuk Android (kecuali fungsi lua i / o, yang tidak akan berfungsi, karena stdio seperti printf tidak berfungsi di Android NDK).

Namun, build ini memiliki kesalahan aneh, misalnya - fps skrip memperbarui setiap bingkai, tetapi dapat jatuh kapan saja dengan kesalahan berikutnya pada fungsi pembaruan fps dengan waktu delta bingkai

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

Dan dapatkan pesan kesalahan berikutnya dengan seluruh aplikasi macet secara acak (1 menit - 3 menit)
Pesan kesalahan

Pertanyaan terakhir (yay, Anda berhasil / melewati bagian membosankan)
Mengapa saya mendapatkan segfault, mengapa pada waktu acak? Skrip FPS hanyalah contoh, paling-paling setiap skrip lua saya memiliki kesempatan untuk menabrak seluruh aplikasi (lebih banyak panggilan == kesempatan lebih baik). Jadi beberapa skrip pemain yang mengubah dirnya pada crash pos baru kadang-kadang juga.

Saya pikir itu karena konflik pembersih sampah Android / Java dan pembersih sampah Lua, jadi ada yang mencoba untuk membebaskan memori yang sudah bebas.

EDIT - DARI SANA POINTER GANDA DATANG DAN MENGAPA:

#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 

In onInit() function

init_time_manager(&TM); 

In onDraw() function

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

Mengapa saya menggunakan pointer untuk menggandakan bukan hanya dua kali lipat? Yah itu menghemat 4 byte menyalin (setiap pointer memiliki ukuran 4, ganda memiliki ukuran 8) param frame_delta_time untuk setiap fungsi seperti update_ui (), saya melakukan hal yang sama untuk setiap struct / jenis lebih besar dari 4 byte, const pointer bukan hanya struct x untuk akses read-only. Apakah ini buruk?

4 Comments
Michal Kottman 09/06/2012
Lebih dari masalah Lua, sepertinya Anda melewatkan sesuatu yang aneh dalam penunjuk frame_delta_time . Bagaimana Anda memanggil fungsi ini? Dari mana datangnya pointer?
Aristarhys 09/07/2012
Ditambahkan suntingan baru tentang hal itu pada akhirnya.
Michal Kottman 09/07/2012
Satu hal lagi - dari mana TM berasal? Apakah ini variabel global? Apakah itu variabel lokal di onInit ? (nah, itu tidak akan berhasil di onDraw )
Aristarhys 09/07/2012
Global static in render.c, sama di mana onInit () dan onDraw ()

3 Answers


Michael Anderson 09/06/2012.

Perubahan Anda terlihat baik dan sesuai untuk sistem Anda. Milis lua menunjukkan bahwa Anda membuat perubahan ke luaconf.h daripada llex.c ( http://lua-users.org/lists/lua-l/2012-08/msg00100.html ) tetapi seharusnya tidak masalah. banyak. (Jadi singkatnya Anda tidak akan masuk neraka untuk perubahan ini ...).

Saya menduga bahwa segfault terjadi karena beberapa jembatan C-lua Anda melakukan sesuatu yang "buruk". Tebakan saya akan menjadi semacam lua stack over / under flow, atau mengakses di luar lua stack dengan menggunakan indeks yang tidak valid. Anda mungkin dapat melacak ini jika Anda dapat membangun bagian jembatan di linux / os x dan menggunakan valgrind. (Alat serupa juga ada untuk windows, tapi saya tidak yakin tentang native to android)

3 comments
Jonas Wielicki 09/06/2012
valgrind untuk windows terdengar menarik, karena beberapa orang cenderung bertanya kepada saya apa yang harus digunakan untuk itu. Bisakah Anda memberikan tautan, bahkan jika OT?
Michael Anderson 09/07/2012
AFAIK tidak ada "valgrind for windows" - maka "alat-alat serupa ada" komentar. Alat-alat serupa adalah hal-hal seperti rational purify dan parasoft insure++ , tetapi keduanya komersial dan saya gaven't digunakan baik dalam beberapa tahun.
Jonas Wielicki 09/07/2012
Itu yang saya maksud, terima kasih.

Suge 09/05/2013.

Lihatlah ini: 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);
  }
} 

Martin Gerhardy 08/05/2015.

Terkadang membantu mengkompilasi lua dengan -DLUA_USE_APICHECK . Ini akan menghasilkan beberapa pesan kesalahan, bukan segfault.

Related questions

Hot questions

Language

Popular Tags