android - 为 Android 编译 Lua lib - 成功,但奇怪的段错误

标签 android c android-ndk lua

很抱歉这个问题很长。如果您愿意,请跳过有关编译 Lua 的部分(这几乎没问题)并直接进入最后一个问题。

让我们像编译 Android 静态库一样编译 Lua 库。

下载最新的源代码并查看 doc/readme.html - 在其他系统上构建 Lua 部分以获取要编译的文件列表。

当然还要查看 makefile——看看我们必须以随意的方式设置平台标志,例如 linux、bsd 等。但是当然没有Android平台,所以我们可以选择将平台设置为ANSI、Linux、Posix或Generic。

第一个问题:即使没有任何平台标志,它也可以正常构建(关于 llex.c 的一个异常(exception),我将在下面描述),所以这可能是不必要的?

我设置了 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

Android NDK 中的locale.h 有一些限制,所以这个错误并不奇怪。

还有关于 size_t、UCHAR_MAX、INT_MAX 的错误 - 添加 llimits.h 包含到 llex.c 中,现在所有错误都消失了。

static int llex< 中现在只存在关于“在 case 末尾缺少中断”“函数返回非 void 时没有返回” 的警告/strong>,但我们不会再弄乱 Lua 源代码,因为它不是最重要的。

第二个问题:我会因为这种快速修复而让程序员下 hell 吗?

obj/armeabi 目录中获取我们新鲜出炉的 LuaLib 并进行测试。 当然,要从 android 文件系统加载脚本,我们需要使用 Java 中的 AssetManager 类编写一些文件加载​​器,所以让我们通过推送和读取 lua 全局变量来实现这一点。

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

Result

如果我们使用 AssetManager 读取脚本文件并将其内容放入字符串中,然后输入 lual_dostring(),它也会起作用。所以是的,我们为 Android 构建了 lua(lua i/o 函数除外,它不起作用,因为像 printf 这样的 stdio 在 Android NDK 中不起作用)。

但是这个构建有奇怪的错误,例如 - fps 脚本更新每一帧,但它可能随时下降,下一个错误发生在函数 what updates fps with frame delta time

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 分钟)获取整个应用崩溃的下一条错误消息
Error msg

最后一个问题(耶,你答对了/跳过无聊的部分)
为什么我会出现段错误,为什么是随机的? FPS 脚本只是示例,至多我的每个 lua 脚本都有机会使整个应用程序崩溃(更多调用==更好的机会)。因此,某些在新位置更改其目录的播放器脚本有时也会崩溃。

我认为这是因为 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);

为什么我使用指向 double 而不是 double 的指针?好吧,它节省了 4 个字节的复制(每个指针的大小为 4,double 的大小为 8)frame_delta_time 参数到每个函数,如 update_ui(),我对每个大于 4 字节的结构/类型做同样的事情,const 指针而不是仅仅struct x 用于只读访问。这是坏事吗?

最佳答案

您的更改看起来不错并且适合您的系统。 lua 邮件列表建议您对 luaconf.h 而不是 llex.c ( http://lua-users.org/lists/lua-l/2012-08/msg00100.html ) 进行更改,但这应该无关紧要。 (所以简而言之,你不会因为这些变化而下 hell ......)。

我猜测段错误的发生是因为您的某些 C-lua 桥正在做一些“坏事”。我的猜测是某种 lua 堆栈溢出/欠流,或者通过使用无效索引访问 lua 堆栈外部。如果您可以在 linux/os x 上构建桥接部分并使用 valgrind,则您可能能够追踪到这一点。 (windows 也有类似的工具,但我不确定 android 是否原生)

关于android - 为 Android 编译 Lua lib - 成功,但奇怪的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12299659/

相关文章:

java - 如何通过 NDK 在 Android 上使用 C 函数

android - 如何用 c++_static 重建 OpenCv?

android - 如果手动迁移失败则删除 Realm

android - 屏幕和 Activity 之间的区别

android - seeking时如何隐藏SeekBar的tickmark?

C 到 MIPS - 指令引用未定义 QTSpim

c - 在 C 中合并字节数组的最有效方法是什么?

c - 在两个 channel 上播放单声道 WAV

android - jar 不匹配! Action 条 sherlock 和 facebook sdk

android - 在 Android 上使用 OpenSL 从内存中播放 PCM WAVE 声音