使用 Lua 语言及其脚本实现 Fortran 程序的热重载
fortran-lua53
🔥仓库 (许可证: ISC,类似BSD-2): https://github.com/interkosmos/fortran-lua53
fortran-lua
是 Philipp 编写的开源项目,它是 Lua 5.3 的 Fortran 接口。
Lua 简介
Lua 由 C 语言编程,可以作为单独的 Lua 解释器或 C 语言函数库,是一名优秀小巧的函数式动态语言,其速度是动态语言中 Top 0 级别的,另外,Lua 语言是罕见的由发展中国家设计开发出的著名语言。
它的主要应用场景是:
- 为编译型语言带来灵活性;
- 为编译型语言代码可拓展性,这一点体现在热重载能力。
🔰 热重载: 一般情况下,当不具备任何反射特性的编译型语言一旦完成编译,实现部署,中途如果发现 Bug ,则需要重新修改源码,再进行编译部署,且需要中断之前正在运行的含 Bug 的程序。
但是,通过 Lua 脚本,比如 Fortran ,可以借助 Lua 只实现 Lua 脚本的内容,就能一定程度改变程序的后续运行过程,可以一定程度避免中断运行。
这点与配置文件似乎有着异曲同工之妙,但配置文件主要负责程序数据的配置,而 Lua 脚本则更体现出从函数(方法)上改变程序的运行业务,且更灵活,数据配置亦可。
所以,Lua 在游戏开发行业用的较多,可以为上线的游戏快速推送 Lua 补丁,性能又好,体积又小。 在科学计算中,如计算流体力学,我们可以通过自定义lua脚本实现网格、粒子的初始化,从内存传递给核心计算程序。
演示: 使用 Lua 脚本改变程序的运行效果
我们演示一下在代码编写过程中写错了 Lua 业务,然后在不修改 Fortran 代码、不重新编译代码、不中断程序运行的情况下,实现 Lua 业务修改和正确运行:
cd workspace # 切换到你常用的工作区间
fpm new --app lua-demo # 创建fpm项目
cd lua-demo && code . # 切换到`lua-demo`文件夹,并使用vs code打开它
我们创建了一个lua-demo
工程,使用vs code打开了它,我们可以在fpm工程的fpm.toml
文件中添加以下语句,以使用fortran-lua53
:
[dependencies]
fortran-lua53 = { git = "https://github.com/interkosmos/fortran-lua53.git" }
上图,我们“不小心”在 Lua 脚本中写了一个错误的times
函数(粗心的程序员写成了加法函数),可是程序已经运行了,幸亏这个 Bug 不会导致程序崩溃,我们得赶紧修改它,并且将这个补丁发送给用户。
5 * 5 = 10
按回车继续运行..
我们在程序运行的间隙,修改了times
函数的业务,并且推送给用户运行环境,此后程序业务得到正常合理运行。
5 * 5 = 25
按回车继续运行..
我们能看到,Lua 脚本的强大之处,尤其是对强编译型语言的特殊需求,它使得程序变得更灵活,相当于用户业务程序实时自带了一个实时高效的 Lua 解释器。
大多数情况下,这个特性常规用户是不太需要的,但确实为编程提供了一种特色强烈的可能性,跨语言交互和热重载。
代码
program main
use, intrinsic :: iso_c_binding, only: c_ptr
use lua
implicit none
!> C 指针, 可以指向任何类型的 C 对象
type(c_ptr) :: l
integer :: rc
do
!> 启动 Lua 虚拟机
l = lual_newstate()
call lual_openlibs(l)
rc = lual_dofile(l, "times.lua")
rc = lua_getglobal(l, "times")
!> 推送参数值
call lua_pushinteger(l, 5)
call lua_pushinteger(l, 5)
rc = lua_pcall(l, 2, 1, 0) ! 调用times函数,推送2个参数,返回1个结果
!> 获取返回值
rc = lua_tointeger(l, -1) ! -index: 第几个返回值
call lua_pop(l, 1) ! 弹出返回值及其数量
print *, "5 * 5 = ", rc
print *, "按回车继续运行.."
read (*, *)
end do
end program main
-- 整数乘法
function times(a, b)
return a + b
end