項目需在 Lua 5.2 中使用 JSON,選擇高性能的 cJSON(C 實現),並將其編譯為靜態庫鏈接進 Lua,避免運行時依賴。本文記錄 VS2010 下的完整編譯步驟與踩坑記錄。
cJSON.c、cJSON.h、fpconv.c、fpconv.h)lua_static_lib/ ├── lua/ # Lua 5.2 源碼 │ ├── src/ │ │ ├── *.c, *.h │ │ ├── linit.c │ │ └── lualib.h ├── cjson/ # cJSON 源碼 │ ├── cJSON.c │ ├── cJSON.h │ ├── fpconv.c │ └── fpconv.h └── lua_static.vcxproj
lualib.h 添加聲明:
#define LUA_CJSONLIBNAME "cjson"
LUAMOD_API int (luaopen_cjson) (lua_State *L);
linit.c 註冊到標準庫列表:
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_CJSONLIBNAME, luaopen_cjson}, // ← 新增
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
刪除 fpconv.c(MSVC 不支援其內聯語法)
修改 fpconv.h:
#define FPCONV_G_FMT_BUFSIZE 32
#define USE_INTERNAL_FPCONV // 強制使用內部實現
#define inline __inline // MSVC 關鍵字
#ifdef USE_INTERNAL_FPCONV
static inline void fpconv_init() { /* 空實現 */ }
#else
extern inline void fpconv_init();
#endif
extern int fpconv_g_fmt(char*, double, int);
extern double fpconv_strtod(const char*, char**);
修改 lua_cjson.c 頭部:
#include "..\lua.h"
#include "..\lauxlib.h"
#include
#define isnan(x) ((x) != (x))
#define isinf(x) (!_finite(x) && !_isnan(x))
#define strncasecmp _strnicmp
LUA_BUILD_AS_DLL=0(靜態庫).c/.h 加入專案(建議建立「篩選器」管理).lib 或直接輸出 .exe編譯成功後,在 Lua 腳本中即可直接使用:
local json = require("cjson")
local t = {name = "test", value = 123}
local str = json.encode(t)
print(str) -- {"name":"test","value":123}
local obj = json.decode(str)
print(obj.name) -- test
| 錯誤現象 | 原因 | 解決 |
|---|---|---|
| unresolved external symbol luaopen_cjson | linit.c 未註冊或聲明缺失 | 檢查 lualib.h 聲明、linit.c 註冊表 |
| fpconv 相關編譯錯誤 | MSVC 不支援 GNU inline 語法 | 刪除 fpconv.c、修改 fpconv.h 定義 USE_INTERNAL_FPCONV |
| isnan/isinf 未定義 | MSVC 使用 _isnan/_finite | lua_cjson.c 宏定義映射 |
| strncasecmp 未定義 | MSVC 為 _strnicmp | 宏定義映射 |
lua52_static.lib/O2 優化、/MT 靜態運行時,減少依賴LUA_BUILD_AS_DLL=1 並導出符號將 cJSON 靜態編譯進 Lua,既保證了部署簡單(單一二進制),又獲得了高性能 JSON 解析。關鍵在於處理好 MSVC 與 C99 代碼的兼容性差異。此法同樣適用於其他 C 庫嵌入 Lua 的場景。