起因
本来一直没想过还会在 windows 下开发的,但是一想到我的处理 Excel 的转表工具可能需要提供给策划本地使用,我就想方设法了,安装 mingw 的话应该更好解决,但是不了解发布版需不需要安装 mingw,而且刚好电脑已经安装好了 vs。所以就有了这篇文章。其实不用 nmake ,完全用 cl 和 link 命令也是可以的。只不过 nmake 和 make 一样,更适合管理。
编译 Lua
为了能编译并使用扩展,需要在生成 .dll
的时候生成 .lib
文件。生成 DLL 使用 /DLL
参数。但是生成的 lib 文件有问题,编译扩展库的时候会出现 unresolved xxx
。搜到这个 https://ci.appveyor.com/project/xpol/lua-rapidjson/build/0.1.0.4/job/93u2pxa808er1huc 。最有用了,虽然是用 CMake 生成的 Make 日志,但是都把编译命令输出来了。需要添加 -DLUA_BUILD_AS_DLL
,至于为什么的话可以去 src/luaconf.h
中搜就知道了。
下面的 makefile 就是使用 nmake 执行的。生成 Lua.exe 比较简单。生成 Lua.lib 主要是要加上面提到的预定义。
STD_INC=/I "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include" \
/I "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\include" \
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\um" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\shared" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\winrt"
STD_LIB_PATH=/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib" \
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\lib" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.10150.0\ucrt\x86" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\8.1\lib\winv6.3\um\x86" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\Lib\um\x86"
SRC_DIR=src
OBJ_DIR=objs
LUA_INC=/I $(SRC_DIR)
INCLUDE_DIR=$(STD_INC) $(LUA_INC)
LIB_PATH=$(STD_LIB_PATH)
OBJS=$(OBJ_DIR)\lapi.obj \
$(OBJ_DIR)\lauxlib.obj \
$(OBJ_DIR)\lbaselib.obj \
$(OBJ_DIR)\lbitlib.obj \
$(OBJ_DIR)\lcode.obj \
$(OBJ_DIR)\lcorolib.obj \
$(OBJ_DIR)\lctype.obj \
$(OBJ_DIR)\ldblib.obj \
$(OBJ_DIR)\ldebug.obj \
$(OBJ_DIR)\ldo.obj \
$(OBJ_DIR)\ldump.obj \
$(OBJ_DIR)\lfunc.obj \
$(OBJ_DIR)\lgc.obj \
$(OBJ_DIR)\linit.obj \
$(OBJ_DIR)\liolib.obj \
$(OBJ_DIR)\llex.obj \
$(OBJ_DIR)\lmathlib.obj \
$(OBJ_DIR)\lmem.obj \
$(OBJ_DIR)\loadlib.obj \
$(OBJ_DIR)\lobject.obj \
$(OBJ_DIR)\lopcodes.obj \
$(OBJ_DIR)\loslib.obj \
$(OBJ_DIR)\lparser.obj \
$(OBJ_DIR)\lstate.obj \
$(OBJ_DIR)\lstring.obj \
$(OBJ_DIR)\lstrlib.obj \
$(OBJ_DIR)\ltable.obj \
$(OBJ_DIR)\ltablib.obj \
$(OBJ_DIR)\ltm.obj \
$(OBJ_DIR)\lundump.obj \
$(OBJ_DIR)\lutf8lib.obj \
$(OBJ_DIR)\lvm.obj \
$(OBJ_DIR)\lzio.obj
all: Lua.dll Lua.exe Luac.exe
#compile
{$(SRC_DIR)}.c{$(OBJ_DIR)}.obj::
@if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
$(CC) /nologo $(INCLUDE_DIR) /Fo$B /c -DLUA_BUILD_AS_DLL $<
@move *.obj $(OBJ_DIR)
# link
Lua.exe: Lua.lib $(OBJ_DIR)\lua.obj
LINK /nologo /OUT:$@ $(LIB_PATH) $?
Luac.exe: $(OBJS) $(OBJ_DIR)\luac.obj
LINK /nologo /OUT:$@ $(LIB_PATH) $?
Lua.dll: $(OBJS)
LINK /nologo /DLL /OUT:$@ $(LIB_PATH) $?
clean:
rd /S /Q $(OBJ_DIR)
del *.exe
del *.dll
del *.exp
del *.lib
对应的 Lua 源码目录结构是这样的
E:\workspace\lua\
|
.---src\
|
.---objs\
|
.---Makefile
编译 Lua 的扩展库
我主要是为了编译 xlsx 库,所以就以这个为例子。
主要就是为了生成 zip.so
和 base64.so
。 生成 base64.so 比较简单就一个文件,生成一个obj,
然后再 link 成 dll。主要关键点在引用 Lua.lib 和 两个预定义 -DLUA_LIB -DLUA_BUILD_AS_DLL
。
Lua.lib 是上面编译 Lua 的时候生成的,要使用绝对路径。两个预定义的话还是要依据 luaconf.h
也是根据而来。改了这么多还不够,还要改 lbase64.c
和 luazip.c
的 xxx_open
函数的定义,
需要在前面加上 LUA_API
。/MD
需要改为 /MT
,要不然移植到没有安装 vc++ 环境的机器上就跑不起来。历经N次尝试和谷歌搜索,就这样结束了。luazip.c
里面有行代码不兼容VC编译器:char tmp[szfn];
,这是C99的用法,需要自行修改下。
STD_INC=/I "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include" \
/I "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\include" \
/I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\um" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\shared" \
/I "C:\Program Files (x86)\Windows Kits\8.1\Include\winrt"
STD_LIB_PATH=/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib" \
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\lib" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.10150.0\ucrt\x86" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\8.1\lib\winv6.3\um\x86" \
/LIBPATH:"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\Lib\um\x86"
CFLAGS=/nologo /MT /O2 /c
LUA_INC=/I "E:\workspace\lua\src"
LUA_LIB= E:\workspace\lua\Lua.lib
LUA_LIB_PATH=/LIBPATH:"E:\workspace\lua"
ZLIB_SRC=zlib
MINIZIP_SRC=minizip
INCLUDE_DIR=$(STD_INC) $(LUA_INC) /I $(ZLIB_SRC) /I $(MINIZIP_SRC)
LIB_PATH=$(STD_LIB_PATH) $(LUA_LIB_PATH)
OBJ_DIR=objs
ZLIB_OBJS=$(OBJ_DIR)\adler32.obj \
$(OBJ_DIR)\compress.obj \
$(OBJ_DIR)\crc32.obj \
$(OBJ_DIR)\deflate.obj \
$(OBJ_DIR)\gzclose.obj \
$(OBJ_DIR)\gzlib.obj \
$(OBJ_DIR)\gzread.obj \
$(OBJ_DIR)\gzwrite.obj \
$(OBJ_DIR)\infback.obj \
$(OBJ_DIR)\inffast.obj \
$(OBJ_DIR)\inflate.obj \
$(OBJ_DIR)\inftrees.obj \
$(OBJ_DIR)\trees.obj \
$(OBJ_DIR)\uncompr.obj \
$(OBJ_DIR)\zutil.obj
MINIZIP_OBJS=$(OBJ_DIR)\ioapi.obj \
$(OBJ_DIR)\iowin32.obj \
$(OBJ_DIR)\miniunz.obj \
$(OBJ_DIR)\mztools.obj \
$(OBJ_DIR)\unzip.obj \
$(OBJ_DIR)\zip.obj
all: base64.dll zip.dll
#compile
.c{$(OBJ_DIR)}.obj::
@if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
$(CC) $(CFLAGS) $(INCLUDE_DIR) /Fo$B -DLUA_LIB -DLUA_BUILD_AS_DLL $<
@move *.obj $(OBJ_DIR)
{$(MINIZIP_SRC)}.c{$(OBJ_DIR)}.obj::
@if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
$(CC) $(CFLAGS) $(INCLUDE_DIR) /Fo$B -DLUA_LIB -DLUA_BUILD_AS_DLL $<
@move *.obj $(OBJ_DIR)
{$(ZLIB_SRC)}.c{$(OBJ_DIR)}.obj::
@if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
$(CC) $(CFLAGS) $(INCLUDE_DIR) /Fo$B -DLUA_LIB -DLUA_BUILD_AS_DLL $<
@move *.obj $(OBJ_DIR)
# link
base64.dll: $(OBJ_DIR)\lbase64.obj
LINK /nologo /DLL /OUT:$@ $(LIB_PATH) $(LUA_LIB) $?
zip.dll: $(OBJ_DIR)\luazip.obj $(ZLIB_OBJS) $(MINIZIP_OBJS)
LINK /nologo /DLL /OUT:$@ $(LIB_PATH) $(LUA_LIB) $?
clean:
rd /S /Q $(OBJ_DIR)
del *.exe
del *.dll
del *.exp
del *.lib
目录结构
luaclib\
|
.---minizip\
|
.---zlib\
|
.---objs\
|
.---lbase64.c
|
.---luazip.c
|
.---Makefile
编译 luasocket
makefile 见 https://github.com/hanxi/luasocket-nmake
跟上面的不同的是 lua.exe 和 luac.exe 都为静态编译的方式