LuaJIT源码分析(一)搭建调试环境

LuaJIT源码分析(一)搭建调试环境

众所周知,LuaJIT是一个针对lua编程语言的即时编译器(JIT,Just-In-Time Compiler),它执行lua代码的速度相当的快。而网络上关于LuaJIT源码的资料相当地少,只能自己开一个坑,从头开始阅读了。

万事开头难。想要分析源码,第一步肯定是要先搭建一个可以调试源码的环境出来。然而,就连这个第一步,网络上可参考的内容也很有限,大概是LuaJIT的编译本身也比较复杂吧。

先checkout下源代码,官方git如下:

git clone https://luajit.org/git/luajit.git

github上也有一个镜像地址

我们准备使用visual studio进行调试,LuaJIT提供了使用msvc编译的脚本msvcbuild.bat,它位于src目录下。浏览这个脚本,可以发现LuaJIT的编译分为三个部分,首先是build出一个minilua,它是lua原生代码的一个子集,用来判断当前平台是32位还是64位,并执行lua脚本并生成平台相关的指令;然后是buildvm,用来生成各种库函数的映射;最后编译lua的各种lib,然后生成最终的LuaJIT。这个脚本需要在Visual Studio Command Prompt环境下执行,根据注释它还有4个编译选项:

@rem Open a "Visual Studio Command Prompt" (either x86 or x64).
@rem Then cd to this directory and run this script. Use the following
@rem options (in order), if needed. The default is a dynamic release build.
@rem
@rem   nogc64   disable LJ_GC64 mode for x64
@rem   debug    emit debug symbols
@rem   amalg    amalgamated build
@rem   static   static linkage

这里我们编译并不需要带上这些选项。另外,脚本在编译结束时,会执行一些清理工作,把中间生成的代码,以及编译产生的obj都会删除掉。而我们调试时其实是希望保留这些代码的,那么就要在脚本中把这部分逻辑给注释掉:

@REM @del *.obj *.manifest minilua.exe buildvm.exe
@REM @del host\buildvm_arch.h
@REM @del lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h

以Visual Studio 2022为例,我们找到64位的command prompt:

LuaJIT源码分析(一)1

单击它,然后cd到LuaJIT的src目录,运行编译脚本msvcbuild.bat:

LuaJIT源码分析(一)2

编译很快,如果一切顺利,会在编译结束时看到成功build的日志:

LuaJIT源码分析(一)3

在src目录下也能看到build的luajit.exe,双击运行,它就是我们要的lua虚拟机。

LuaJIT源码分析(一)4

然后,我们在src同级目录下新建一个目录,用来存放vs工程,在vs中新建一个empty console C++工程,然后把src目录的头文件和源文件都添加进去。

LuaJIT源码分析(一)5

执行F5调试,此时可能会遇到一个报错:

error C4996: ‘strerror’: This function or variable may be unsafe. Consider using strerror_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

这是因为LuaJIT源码中使用strerror这个C API,而它是不安全的,编译器更推荐使用strerror_s,所以报错提示了。不过这里我们并不打算修改源码,而是直接在工程里添加_CRT_SECURE_NO_WARNINGS宏:

LuaJIT源码分析(一)6

再来一次,编译能通过了,但是到链接的时候,又报错了:

LuaJIT源码分析(一)7

从报错可以看出是有函数被重复定义了,既然都指向ljamalg.obj,那么先去它对应的源文件ljamalg.c一探究竟,原来它直接include了一堆源文件进来了:

LuaJIT源码分析(一)8

我们回到msvcbuild.bat,可以看到ljamalg.c这个文件只有在开启了amalg选项时才会被编译进来:

@if "%1"=="amalg" goto :AMALGDLL
...
:AMALGDLL
%LJCOMPILE% %LJDYNBUILD% ljamalg.c

而我们正常编译没有带这个选项,这个文件实际上是不参与build过程的,因此我们要把这个文件从vs里排除掉。那么这个amalg选项是做什么的呢?这一点LuaJIT的官网上有提:

The build system has a special target for an amalgamated build, i.e. make amalg. This compiles the LuaJIT core as one huge C file and allows GCC to generate faster and shorter code. Alas, this requires lots of memory during the build. This may be a problem for some users, that’s why it’s not enabled by default. But it shouldn’t be a problem for most build farms. It’s recommended that binary distributions use this target for their LuaJIT builds.

简而言之,该选项会将 LuaJIT 核心编译为一个巨大的 C 文件,并允许编译器生成更快、更短的代码。

去除ljamalg.c之后,我们再次尝试,然后很不幸链接依旧会失败:

LuaJIT源码分析(一)9

我们回忆一下LuaJIT的build过程,vm中各种库函数的映射是通过buildvm完成的,它本身并没有对应的源代码,不过它生成的目标文件倒是在src目录下,这也是在bat中完成的:

buildvm -m peobj -o lj_vm.obj

这个目标文件中应该包含这里需要引用的各种函数。那么我们在vs中手动添加进来:

LuaJIT源码分析(一)10

再次尝试,LuaJIT终于可以启动了。默认我们debug是没有带上参数的,所以它是从stdin接收参数的。

LuaJIT源码分析(一)11

在main函数的入口加上断点,再次执行F5,也能正常调试了:

LuaJIT源码分析(一)12

好了,这样就可以愉快地阅读LuaJIT源码了。

Reference

[1] LuaJIT

[2] 什么是 LuaJIT?为什么 Apache APISIX 选择了 LuaJIT?

[3] 浅入浅出LuaJIT

[4] 如何阅读luajit的代码——用vs调试篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值