TCL作为一种工具语言已经在很多地方得到广泛的应用,在土木方面著名的例子就是ANSYS了。当然作为UCB开发的OpenSees自然也是要用自家的TCL语言了,不过最新的OpenSees源代码中已经增加了对于Python语言的支持。虽然官方尚没有公开Python的使用方式,但是相信应该很快就可以看到使用Python语言建立OpenSees模型了。OpenSees作为一个C++编写的软件,如果用C++实现一个类似于ANSYS中的APDL语言,会大大增加工作量,因此在使用TCL语言建模时需要调用TCL解释器对tcl脚本进行解析,这也是在安装OpenSees的时候需要先安装tcl/tk的原因。
如果有同学安装了Python的集成包,比如Anaconda或者Winpython之类,就会发现不需要安装tcl/tk就可以运行OpenSees了,我自己的电脑就没有安装OpenSees官网提供的tcl/tk安装程序而能够直接运行64位的OpenSees。为了能够自己实现C++中调用TCL解释器,首先还是要安装一下ActiveTcl的,我自己安装的是32位ActiveTcl,这并不影响我电脑运行64位的OpenSees,因为OpenSees调用的是Anaconda中64为的tcl86.dll。
回归主题,因为我自己使用的是32为gcc编译器,因此为了比较好的继承性,我直接下载了32位的ActiveTcl,下载地址可以从ActiveTcl官网找到,这里给一个ActiveTcl 8.5的下载链接:点击下载
下载之后直接安装到C:\Program Files\Tcl目录下即可,打开Qt Creator新建一个Project:
选择Qt Console Application,因为我只是建立一个测试程,选择Choose…后设置项目的名称和路径:
完成之后需要做一件重要的事情就是将Tcl目录下的include和lib复制到工程文件夹E:\QT\tcltest\tcltest下并从新命名为tcltkinclude和tcltklib:
然后回到Qt Creator中右键工程文件夹,选择添加库…:
选择外部库:
在外部库的设置页面,选择tcktklib中的tcl85.lib,链接选择动态,将“为debug版本添加‘d’作为后缀”选项去掉,点击下一步完成添加:
这时候pro文件中自动增加了tcl85的库文件,但是还缺少头文件的位置,因此增加INCLUDEPATH += $$PWD/tcltkinclude到pro文件中去,这样pro文件应该与下面一致:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
QT += core QT -= gui CONFIG += c++11 TARGET = tcltest CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp INCLUDEPATH += $$PWD/tcltkinclude unix|win32: LIBS += -L$$PWD/tcltklib/ -ltcl85 INCLUDEPATH += $$PWD/tcltklib DEPENDPATH += $$PWD/tcltklib |
然后回到main.cpp直接Ctrl+R运行一下,如果没有出错会出现一个黑框框。然后在main.cpp中增加include “tcl.h”,这样在主文件中输入Tcl_就可以看到Qt Creator的智能提示了:
这样环境就部署好了,下面先创建一个test.tcl文件,文件的路径为E:\QT\tcltest\tcltest\test.tcl:
在main.cpp中写入下面的语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <QCoreApplication> #include <iostream> #include "tcl.h" using namespace std; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Tcl_Interp *interp = Tcl_CreateInterp(); int Res; const char *detail; Res = Tcl_EvalFile(interp, "E:/QT/tcltest/tcltest/test.tcl"); detail = Tcl_GetStringResult(interp); if (Res != TCL_OK) { cout<<"Failed!"<<endl; cout<<detail<<endl; } else { cout<<"Success!"<<endl; } Tcl_DeleteInterp(interp); return a.exec(); } |
稍微解释一下,需要先生成一个解释器实例,Tcl_CreateInterp()用于创建这个实例并返回Tcl_Interp *的指针。具体可以参看Tcl的C接口帮助文档,然后使用了两个函数Tcl_EvalFile()和Tcl_GetStringResult()。
Tcl_EvalFile()需要两个参数,第一个是解释器的指针,即刚才创建的interp这个指针, 第二个为文件路径,注意在Qt中需要使用正斜杠/代替Windows的反斜杠\,否则会出错。Tcl_EvalFile()会返回一个下面之一的整数表示执行结果:
- 0 (TCL_OK)
- 1 (TCL_ERROR)
- 2 (TCL_RETURN)
- 3 (TCL_BREAK)
- 4 (TCL_CONTINUE)
Tcl_GetStringResult()可以从解释器接受解释器的信息,这个信息不是程序中的输出信息,是解释器解释tcl失败的原因,可以用来辅助调试。
这里我用没有用qDebug()而是直接用了cout输出到控制台,直接使用Ctrl+R执行之后就可以看到黑框框里面直接输出“orycho”和“Success!”表明调用tcl解释器成功:
至此,成功在C++中调用TCL解释器对tcl文本文件进行解释。