playbook/docs/tsl/syntax_book/function/09_compiler.md

25 KiB
Raw Blame History

TSL编译工具

内容

  • 功能简介
  • 应用场景
  • 特性
  • 编译范围
  • TSL指令
  • 调用效率的测试
  • 依赖关系

功能简介

将TSL代码编译成为可执行文件和动态库文件支持windows与linux环境。

编译成为可执行文件,即开发的程序与应用可作为一个独立运行的小程序,不需要依赖天软客户端或天软解释器。

编译动态库文件可将天软函数包编译成动态链接库方便其它开发工具如C++等进行调用为第三方开发工具提供支撑如由TSL开发的算法等让TSL语言程序可被更广泛地应用。

应用场景

内容
  • 编译可执行文件
  • 编译动态库
编译可执行文件

此前,天软语言只支持脚本方式运行,即在.NET平台、本地解释器或.web平台中进行执行。若只作为天软的建模语言已经满足了一般需求然而随着天软语言支持功能的扩展其应用也越来越广泛如用来开发编译桌面应用的天软TSL语言桌面开发工具开发好的应用是需要通过TSL.exe去执行这个桌面应用的这种方式不利于这些应用的发布由此编译成为可执行文件就显的很有必要。

另外天软还提供了信创版的客户端该客户端也是基于TSL语言的开发程支持编译成可执行文件后就可以将这些已开发的应用直接编译成windows或linux的可执行程序用起来就会非常方便。

除此之外,还有例如一些管理工具,业务的应用的小程序等,都可生成为一个独立的可执行文件。

编译动态库

可将天软TSL语言函数包创建成一个动态链接库即DLL文件并将该函数包进行输出。如此在第三方工具如C++中只需将生成的该动态库进行引入后就可直接调用不再需要天软TSSVRAPI等包的支持。

还可以将一些复杂的算法通过TSL语言进行开发后编译成动态库放入到其它语言工具中就可以直接进行调用不需要重复开发。

特性

TSL编译工具的三特性

其中,

独立编译目前除Linux中编译动态库还需依赖GCC相关功能才能完成外其它编译工作如windows中编译可执行文件与动态库及Linux中编译可执行文件等都已实现不依赖其它编译工具就可独立完成。

线程安全:输出的动态库可被多线程并发,且线程安全。

接口高效利用TSL编译出来的动态库接口调用所花费的时间消耗在亚微秒级别效率非常高大概一秒钟可以调用107次能适用于交易级别的应用。

编译范围

编译工具可将TSL语言的源代码与函数库以及相关的资源文件如配置类.ini文件桌面开发工具中的窗体.dfm文件、窗口资源文件等都可以通过天软编译工具生成一个单一的目标文件即单一的可执行文件或.so或.dll该文件的运行仅依赖天软运行环境的动态库可方便程序的直接运行与业务应用的安装发布。

TSL指令

根据编译目标大致可分为三块指令:

可执行文件(.exe),编译命--buildexe=

可选项一: -buildgui用来指定编译出来的目标是Windows UI应用程序默认为控制台应用程序。

可选项二:--buildico=用来指定Windows icon图标。

以上两个可选项只在Windows下有效在Linux中不生效。

动态库(.dll/.so),编译命--buildlib=

可选项一--exports=,可以指定输出的函数。

包文件,编译命令--build=

另外,还新增了对包执行等相关命令

如执行包文件,命令为:--runpkg=

加载包文件,命令为:--pkg=

等等详情可参考TSL命令集列表。

目前提供的指令功能分布大致如下:

将TSLDemo01.tsl程序编译成可执行文件操作如下

在文件路径下进入控制台,执行以下命令:

tsl --buildexe=TSLDemo01.tsl --output=test01.exe

执行完后在当前路径中会新增一个test01.exe可执行文件如下所示

双击test01.exe即可启动运行该程序。

内容
  • TSL命令集列表
  • 命令集详细解析
TSL命令集列表

执行命令行的命令为tsl xxx

Windows命令集

命令 功能说明 备注
tsl.exe /? 查看命令列表帮助或TSL /? 注意/前有一个空格
-COMPILE|-COMPILEC [/S] [-S] tslfiename 将tsl/tsf文件编译为二进制格式文件。
-COMPILE命令生成的文件后缀为.TSB
- COMPILEC命令生成的文件后缀为.TSC
可选项
/S递归模式即加上该可选命令后会从子目录中查找该函数。默认只在当前目录下查找。
-S安静模式不打印执行结果的信息
默认生成的文件与原文件同目录,如:
Tsl -COMPILE TsfDemo01.tsf
作用:编译成二进制文件后,函数与脚本照样可以正常调用,可以用于隐藏源代码。
编译指令
--buildexe=tslfilename 将指定tsl文件编译成可执行(.exe)文件默认生成文件名为default.exe可执行文件默认图标为tsl编译器图标
其可选项 -buildgui
指定编译的可执行文件为Windows UI应用程序
默认为控制台应用程序
--buildico=xxx.ico
指定可执行文件的图标
默认为TSL.exe的图标
--buildlib=tsl(tsf)filename 将指定tsl/tsf文件编译成动态库(.dll)文件 默认生成文件名为default.dll
其可选项 --exports=func1[:exp1][,…]
将指定函数名输出在动态库中
指定多个函数用逗号分割
--build=tslfilename 将指定tsl文件编译成.tsg包文件默认生成文件名为default.tsg 可以通过函数获取包中资源内容rs:
getglobalcache("@@tsl-resource@@",rs)
编译指令的可选项 --buildexe|--buildlib|--build通用的可选项
--output=filename 给输出目标指定文件路径与名称 默认为
default.exe|default.dll|default.tsg
默认生成在当前路径下
-strong 编译所有引用,将所有依赖的引用都进行编译
缺省为仅编译调用的
解决调用了某些动态库不能被检测到的函数。
--depends=fun1,fun2,… 指定额外需要编译的函数列表 多个函数或路径用,分隔
--dependsdir=dir1,dir2,… 指定额外需要编译的函数路径
--excludes=fun1,fun2,… 不编译某些函数
--resourcedir=foldername 指定编译资源文件目录
--resourcepat=pat1,pat2,… 指定资源文件的匹配串 需要搭配--resourcedir=一起使用
-resourcekeepdir 资源名保留相对路径
--extresource=filename1
[:keyname1],filename2…
指定额外的资源
运行指令
--runpkg=packagename 执行包文件 tsl --runpkg=runpkg.tsg
-eval tslstring 执行TSL脚本串 tsl -eval “inttostr(100)”
tslfilename 执行TSL脚本文件 tsl test.tsl
其可选项 -LIBPATH 扩展函数查找路径
-TESTMULTITHREAD N 线程调用N为线程数
-NODEBUGSERVER 不启用调试服务器
-DEBUGSERVER 开启调试服务器
-DEBUGPORT port 指定调试监听端口
-DEBUGLISTEN ip 指定调试监听地址
-DEBUGTHREADS N 指定调试用于网络通信的线程数
-WAITATTACH 运行时等待调试程序连接
-DEBUGLOGIN 1|0 是否需要进行用户登陆
--data-dir=datapath 使用指定文件夹中的配置文件
--pkg=pgk1,pkg2… 加载指定包中的函数
其它指令
-ENCODE configstring 生成加密串 用于数据库配置串加密
-ENCODEDEBUGPASS 生成密码串的加密串 用于远程调试配置中密码的加密

Linux命令集

命令 说明 备注
TSL /? 查看命令列表帮助 注意TSL后有一个空格
其它命令参考Windows命令集注意大小写
命令集详细解析

提示以下命令的操作展示都是在windows操作系统中完成的。

内容
  • 查看命令帮助
  • 编译成二进制文件
  • 编译成可执行文件
  • 编译动态库
  • 编译包文件
  • 编译命令的其它可选项
  • 执行包文件(.tsg)
  • 生成加密串
  • 执行TSL代码串
  • 加密密码串
  • 执行TSL脚本
查看命令帮助

进入cmd中执行tsl /?

展示所有命令及其帮助说明,显示如下:

编译成二进制文件

语法:-COMPILE|-COMPILEC [/S] [-S] tslfilename

功能:将指定脚本文件编译成二进制文件。

场景一默认方式下将tsf文件生成二进制文件

输入:

tsl -COMPILE C:\DoTSL\CompileToExe\TsfDemo01.tsf

输出在tsf文件同目录下生成.TSB文件。

新增文件如下:

####### 内容

  • 可选项:/S 递归模式
  • 可选项:-S 安静模式

####### 可选项:/S 递归模式

功能:编译时,若当前目录下无目标文件,会查找子目录下的目标进行编译

被编译的文件TsfFuncB.tsf在C:\DoTSL\CompileToExe\AAA目录下命令运行当前路径是在C:\DoTSL\CompileToExe\,执行以下操作进行对比:

执行命令 结果说明
默认情况下进行编译
命令行tsl -COMPILE TsfFuncB.tsf
执行结果:编译失败,找不到目标文件,原因是默认只在当前路径下查找。
在递归模式下进行编译
命令行tsl -COMPILE /S TsfFuncB.tsf
执行结果:编译成功,递归模式下,还会在当前目录下的子目录下进行查找。

执行具体表现如下:

####### 可选项:-S 安静模式

功能:安静模式,不打印执行结果的信息。

安静模式命令tsl -COMPILE -S TsfFuncA.tsf

默认情况下的命令tsl -COMPILE TsfFuncA.tsf

对比结果如下,安静模式下,不打印执行是否成功的提示信息。

编译成可执行文件

命令:--buildexe=tslfilename

功能将指定tsl脚本文件编译成可执行文件同时会编译该函数的相关依赖。

场景:将目标文件编译成.exe可执行文件默认文件名为default.exe

输入tsl --buildexe=TD_TSL_ExePath.tsl

输出在tsl文件同目录下生成.exe可执行文件。默认是一个控制台应用

运行结果和新增文件如下:

默认图标为天软客户端图标。

####### 内容

  • 可选项:-buildgui 指定为Windows UI应用程序
  • 可选项:--buildico= 指定图标

####### 可选项:-buildgui 指定为Windows UI应用程序

命令:-buildgui

功能指定编译的可执行文件为Windows UI应用程序。

场景:将创建了界面的脚本编译成带有图形界面的.exe可执行文件指定文件名为buildgui.exe

输入tsl --buildexe=Test_GUIexe.tsl --output=buildgui.exe -buildgui

输出在tsl文件同目录下生成一个带有图形界面的buildgui.exe可执行文件。

新增文件以及buildgui.exe执行结果如下

以下是上述Test_GUIexe.tsl文件中的代码仅供参考。执行下述案例中用到了界面tslvcl工具包。

uses tslvcl;
app := initializeapplication();
app.createform(class(tfm), fm);
fm.show();
app.run();
type tfm = class(TVCForm)
uses tslvcl;
function Create(AOwner);
begin
    inherited;
end;
end;

####### 可选项:--buildico= 指定图标

命令:--buildico=iconfile

功能:指定输出文件的图标,默认为天软可执行文件的图标。

场景将输出的可执行文件的图标指定为ts.ico图标文件名为buildico.exe

输入tsl --buildexe=TD_TSL_ExePath.tsl --output=buildico.exe --buildico=ts.ico

输出在tsl文件同目录下生成一个带有自定义图标的buildico.exe可执行文件。

注:自定义图标文件只能为.ico格式图片否则编译时打印错误信息但不会影响编译。

如发现编译后的可执行文件图标没有更改可能是windows存有缓存。

编译动态库

命令:--buildlib=tsl(tsf)filename

功能将tsl/tsf文件编译成动态库, 同时会编译该函数或脚本中的相关依赖

场景将指定的tsl文件及相关依赖编译到一个.dll动态库文件中

输入tsl --buildlib=TD_TSL_ExePath.tsl

输出在tsl文件同目录下生成.dll文件。tsl文件及其依赖会编译至单个文件中。

运行结果和新增文件如下:

####### 内容

  • 可选项:--exports 输出指定函数名

####### 可选项:--exports 输出指定函数名

命令:--exports=func1[:exp1],…

功能:将指定函数输出在动态库中,多个函数用逗号分割

场景将目标文件编译成动态库文件并在动态库的函数列表中暴露函数TD_TSL_ExePath别名为

ExePath

输入tsl --buildlib=TD_TSL_ExePath.tsl --exports=TD_TSL_ExePath:ExePath

输出在tsl文件同目录下生成.dll文件。

执行上述语句打印信息如下:

可以通过visual studio自带工具可以查看.dll文件暴露出的方法如下所示

编译包文件

命令:--build=tslfilename

功能将tsl/tsf文件编译成.tsg包文件, 同时会编译目标函数或脚本中的相关依赖

场景将指定的tsl文件编译成.tsg包文件

输入tsl --build=TD_TSL_ExePath.tsl

输出在tsl文件同目录下生成.tsg包文件。

运行结果和新增文件如下:

编译命令的其它可选项

在执行--build| --buildexe| --buildlib编译命令时可添加的可选项的使用样例。

在不添加可选项时编译默认会包含tsl文件中调用的tsf函数文件。不加额外参数的情况下默认编译文件名为default.xxx且文件生成在当前路径下。

####### 内容

  • --output= 输出目标文件的名称与路径
  • -strong 编译所有引用
  • --depends= 指定函数列表
  • --dependsdir= 函数扩展路径
  • --excludes= 不编译指定函数
  • --resourcedir= 资源扩展路径
  • --resourcepat= 指定资源匹配串
  • -resourcekeepdir 保留相对路径
  • --extresource= 指定额外资源

####### --output= 输出目标文件的名称与路径

可选命令:--output=filename

功能:给输出目标指定文件路径与名称

场景将目标文件编译成名为test.tsg的包文件并且指定输出目录为子目录output

输入tsl --build=TD_TSL_ExePath.tsl --output=.\output\test.tsg

输出在当前运行目录下的output子文件夹中生成test.tsg文件。

####### -strong 编译所有引用

命令:-strong

功能:将所有依赖的引用都进行编译

场景:目标文件中调用了单元方法,单元中其它方法还调用了其它函数,将目标文件编译成.exe可执行文件且将所有没有被调用到的引用也编译至生成文件中

输入tsl--buildexe=TestDemo01.tsl -strong

输出在tsl文件同目录下生成.exe可执行文件。

展示如下(包括不加该选项的对照):

其中TestDemo01.tsl?的源代码如下:

uses TSLUnitDemo01;
a := 10;
t := FuncA(a);
echo "TSLUnitDemo01.FuncA", t;
sleep(10 * 1000);
return t;

TSLUnitDemo01单元的源代码如下

unit TSLUnitDemo01;
interface
function FuncA(a);
function FuncB(a);
implementation
function FuncA(a);
begin
    return a + 20;
end;
function FuncB(a);
begin
    a := TD_Test(a);
    return a * a;
end;
Initialization
FuncA(2);
Finalizationend.

####### --depends= 指定函数列表

命令:--depends=fun1,fun2,…

功能:指定额外的需要一起编译的函数列表,多个函数用,分隔

场景:目标函数不依赖该函数的情况下,将该函数与目标文件一起编译至动态库中

输入tsl --buildlib=Test_depends.tsl --depends=Test01_TD

输出在tsl文件同目录下生成.dll文件。

####### --dependsdir= 函数扩展路径

命令:--dependsdir=dir1,dir2,…

功能:指定其它需要被编译的函数路径

场景:将指定文件夹(子目录\test)中的所有函数一起编译至动态库中

输入tsl --buildlib=Test_dependsdir.tsl --dependsdir=test

输出在tsl文件同目录下生成.dll文件该dll中包含指定路径下的所有文件。

####### --excludes= 不编译指定函数

命令:--excludes=fun1,fun2,…

功能:不编译指定函数,一般用于在依赖范围内时需要不被编译的场景

场景将一个调用了Test01_TD函数的脚本文件编译成可执行文件并且指定Test01_TD函数不被编译。

输入tsl --buildexe=Test_depends.tsl --excludes=Test01_TD

输出生成可执行文件该文件中不包含Test01_TD函数

其生成过程的表及与运行该可执行文件的表现如下运行会报找不到Test01_TD函数的错说明打包中没有该模型。

编译过程中的打印信息是指分析到的依赖关系或资源文件像上面Test01_TD这种被依赖但是不需要编译的文件还是会被打印在提示信息中。

####### --resourcedir= 资源扩展路径

命令:--resourcedir=foldername

功能:指定其它需要被编译的资源路径。

场景:在编译动态库文件时,指定子目录\ resourcedir\下的文件一起编译至动态库中

输入tsl --buildlib=Test_resourcedir.tsl --resourcedir=resource

执行上述语句,打印信息如下:

资源文件夹中文件如下:

####### --resourcepat= 指定资源匹配串

命令:--resourcepat=pat1,pat2,…

功能:将指定目录下的符合匹配串的文件编译进目标文件中,需要通过--resourcedir=进行指定目录,指定当前目录时,用--resourcedir=.\。

场景01在编译成可执行文件时将\ resource \目录下的所有.ini文件编译至生成文件中。

输入tsl --buildexe=Test_resourcepat.tsl --resourcedir=resource --resourcepat="*.ini"

输出:在同目录下生成了.exe文件并一起编译了\ resource \目录下的ini文件

子目录\ resource \文件夹如下可以看出上面的命令中只编译了两个ini其它文件没有被编译。

Test_resourcepat.tsl中代码如下

echo "\r\n";
echo "Running!!\r\n";
getglobalcache("@@tsl-resource@@", rs); // 获取可执行文件中的所有资源文件信息
echo tostn(rs);
sleep(20 * 1000);
return 1;

执行目标文件打印如下可以到符合条件的ini文件信息

场景02编译可执行文件时将当前路径及其子路径下的pat.ini文件一起编译。

输入tsl --buildexe=Test_resourcepat.tsl --resourcedir=.
--resourcepat="pat.ini"

输出:生成.exe文件并编译了两个路径下的pat.ini文件

执行命令目录下的pat.ini文件展示如下

####### -resourcekeepdir 保留相对路径

命令:-resourcekeepdir

功能:资源文件名中保留文件的相对路径

场景编译可执行文件时编译pat.ini文件并保留相对路径目标源代码中输出当前资源数据。

输入tsl --buildexe=Test_resourcekeepdir.tsl --resourcedir=.
--resourcepat=pat.ini -resourcekeepdir

输出:生成可执行文件。

执行可执行文件:资源文件名中加入了相对路径

下面是不加相对路径命令的生成结果:可对比查看差异

####### --extresource= 指定额外资源

命令:--extresource=filename1[:keyname1],filename2…

功能:将指定资源加入编译,一般用于需要额外加入资源文件时使用,支持相对路径的指定

场景在编译可执行文件时将ts.ico图标文件一起编译

输入tsl--buildexe=Test01_TD.tsl?--extresource=ts.ico

输出:生成.exe文件

执行编译与运行可执行文件展示资源包中存在ts.ico文件

其中Test01_TD.tsl?的源程序如下:

echo "\r\n";
echo "Running!!\r\n";
getglobalcache("@@tsl-resource@@", rs); // 获取包中的资源文件信息
echo tostn(rs);
sleep(20 * 1000);
return 1;
执行包文件(.tsg)

命令:--runpkg=packagename

功能:执行包文件

场景执行一个写入本地test_runpkg.txt文件中的包文件

输入tsl --runpkg=runpkg.tsg

输出:运行.tsg包文件在本地新增test_runpkg.txt文件并写入内容

其中,包中目标文件的的源代码如下:

content := "test_runpkg";
writefile(rwraw(), "", "D:\\test\\tslCmdTest\\runpkg\\test_runpkg.txt", 0, 1000, content);
return 1;

####### 内容

  • 可选项:--pkg= 加载指定资源包

####### 可选项:--pkg= 加载指定资源包

命令:--pkg=pkg1,pkg2…

功能:执行包文件的同时,加载指定包文件。

场景:执行包文件,加载并调用指定包中的函数

输入tsl --runpkg=main.tsg --pkg=data.tsg,SumVol.tsg

输出:运行结果如下

注:

包main.tsg对应的TSL代码如下

echo evalData(0);
function evalData(n)
begin
    data := data();
    ret := 
    case n of
        0:SumVol(data);
        1:AvgVol(data);
        2:SumAmount(data);
        3:AvgAmount(data);
    end;
    return ret;
end;

包data.tsg对应的TSL代码如下

function data()
begin
    return array(
    ("StockID":"SZ000002", "收盘价":7.79, "成交量":189366181.0, "成交金额":1482908609.8),
    ("StockID":"SZ000002", "收盘价":7.64, "成交量":145843421.0, "成交金额":1110094218.41),
    ("StockID":"SZ000002", "收盘价":7.53, "成交量":136469106.0, "成交金额":1027113710.84),
    ("StockID":"SZ000002", "收盘价":7.77, "成交量":211713302.0, "成交金额":1624520449.34),
    ("StockID":"SZ000002", "收盘价":7.53, "成交量":159372804.0, "成交金额":1205270122.69),
    ("StockID":"SZ000002", "收盘价":7.48, "成交量":97780993.0, "成交金额":732008884.19)
    );
end;

包SumVol.tsg对应的TSL代码如下

function SumVol(data)
begin
    return sum(data[:, "成交量"]);
end;
生成加密串

命令:-ENCODE configstring

功能:生成指定字符串的加密串,可用于数据库配置串的加密处理。

场景:对数据库的连接串进行加密处理

输入tsl -encode "Server=127.0.0.1;Database=tsBase;Uid=TinySoft;Pwd=admin;"

输出:返回加密串

执行TSL代码串

命令:-eval tslstring

功能执行TSL语言代码串

场景:执行字符串” datetostr(20231106T)”

输入tsl -eval "datetostr(20231106T)"

输出:返回串执行的结果

加密密码串

命令:-ENCODEDEBUGPASS password

功能:生成密码串加密后的串,用于远程调试配置中对密码信息的加密隐藏

场景生成密码“admin”的加密串

输入tsl -encodedebugpass admin

输出:得到加密后的密码串

执行TSL脚本

命令tsl filename

功能执行指定tsl程序若不在当前路径下需要加上路径信息。

场景执行TSLDemo01.tsl

输入tsl TSLDemo01.tsl

####### 内容

  • 可选项:-LIBPATH 扩展函数查找路径
  • 可选项:-TESTMULTITHREAD多线程执行
  • 可选项:--pkg= 加载指定资源包

####### 可选项:-LIBPATH 扩展函数查找路径

命令:-LIBPATH libpath

功能:设置函数(.tsf)的搜索路径,多个路径用分号分割,当前路径为.场景执行TSLDemo01.tsl脚本程序中有调用函数TsfFuncA(),且该函数不在当前目录下

输入tsl TSLDemo01.tsl -libpath .\aaa\

输出如下图所示成功调用TsfFuncA ()函数

TsfFuncA函数的路径如下

####### 可选项:-TESTMULTITHREAD多线程执行

命令:-TESTMULTITHREAD N

功能指定N个线程调用脚本

场景起用5个线程调用testMultiThread.tsl该脚本中执行打印当前线程的id号

输入tsl testMultiThread.tsl -TestMultiThread 5

输出如下图打印了5个不同线程的id号说明函数被调用了5次

其它更多请查看命令列表的介绍。

####### 可选项:--pkg= 加载指定资源包

命令:--pkg=pkg1,pkg2…

功能:加载包文件。

场景:执行调用包中的函数的脚本

输入tsl TestAAA.tsl--pkg=TestB.tsg

输出:运行结果如下

注:上述中给出了不加载包时执行的结果,方便功能体现。

调用效率的测试

通过上述测试可以看出调用TSL编译的动态库1千万次只花费了1.9秒,属于亚微秒级别的调用,可用于交易级别的开发中。

依赖关系

内容
  • 查找执行文件的依赖关系
  • SysGetFuncdepends
查找执行文件的依赖关系

在实现编译成可执行文件以及动态库的过程中,有一个重要的过程,即查找执行文件的依赖关系。

因此天软提供了SysGetFuncdepends模型专门获取指定目标的依赖关系。

查找的依赖关系范围包括如下:

SysGetFuncdepends

范例

范例01查找函数的依赖关系

obj := Findfunction("stockzf");
v := SysGetFuncdepends(obj, 2 + 4 + 8, v1, v2);
return array("依赖的函数信息":v, "二进制函数信息":v1, "二进制类信息":v2);

其中,依赖的函数信息结果截图如下:

二进制函数信息截图如下:

范例02查找类相关函数的依赖关系

obj := Findfunction("getPYStringList");
v := SysGetFuncdepends(obj, 2 + 4 + 8, v1, v2);
return array("依赖的函数信息":v, "二进制函数信息":v1, "二进制类信息":v2);

其中函数getPYStringList调用了天软内置类THashedStringList。

返回:

其中,二进制类信息展开如下: