本文一个运行于iphone的python解释器的例子,版本为python2.7,由于主要是为了说明如何初始化python解释器,运行python脚本,例子中的界面比较简单,一个输入栏用于输入python脚,一个输出栏用于显示运行的结果。Iphone支持Object-C和C++代码混合编译,可以直接使用C++代码进行开发。
这里Python解释器基于cle开发,首先需要初始化cle,然后加载和初始化python解释器,最后是获取输入的脚本并捕获输出结果。
1.创建工程
创建一个iphone的SingleView工程,添加需要的库文件:sqlite3,iconv,starpy,python2.7,starcore
设置工程参数,宏定义,头文件和库文件的搜索路径
添加python扩展库文件,已经打包成一个压缩文件,可以根据需要裁剪。
2.初始化CLE和python
例子基于CLE开发,首先需要初始化CLE,为了不影响界面刷新,使用独立的线程进行初始化,CLE运行于初始化的线程中。但是从界面线程或者其它线程中调用CLE相关的函数,或者执行python脚本,需要进行加锁操作,此外该线程需要维护CLE的消息循环。
StarCoreBackgroundWorker* myworker = [StarCoreBackgroundWorker initStarCoreBackgroundWorker];
[myworker RunAsync:^(id sender1, DoWorkEventArgs *e) {
BackgroundWorker* worker = (BackgroundWorker*)sender1;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
const char* destDir = [documentsDirectory UTF8String];
StarCore_Init((VS_CHAR *)destDir);
NSString *respaths = [[NSBundle mainBundle] resourcePath];
const VS_CHAR *res_cpath = [respaths UTF8String];
VS_CHAR python_path[512];
VS_CHAR python_home[512];
sprintf(python_home,"%s/python",res_cpath);
sprintf(python_path,"%s/python2.7.zip",res_cpath);
VSCoreLib_InitPython((VS_CHAR*)python_home,(VS_CHAR *)python_path,NULL);
VS_CORESIMPLECONTEXT Context;
SRPInterface = VSCoreLib_InitSimple(&Context,"test","123",0,0,MsgCallBack,0,NULL);
BasicSRPInterface = SRPInterface->GetBasicInterface();
BasicSRPInterface->InitRaw("python", SRPInterface);
void *python = SRPInterface ->ImportRawContext((VS_CHAR*)"python",(VS_CHAR*)"",false,NULL);
//---enter msg loop
SRPControl = BasicSRPInterface->GetSRPControlInterface();
while(true){
while(SRPControl->SRPDispatch(VS_FALSE) == VS_TRUE);
[NSThread sleepForTimeInterval:0.01];
}
}
userState:nil
ProgressChanged:^(id sender1, ProgressChangedEventArgs *e) {
}
RunWorkerCompleted:^(id sender1, RunWorkerCompletedEventArgs *e) {
}];
StarCoreBackgroundWorker是为移植性封装的ios的线程,详细介绍见http://blog.csdn.net/srplab1/article/details/58251894
3.捕获python脚本的输出
为了捕获python脚本的输出结果,需要注册CLE的回调函数,在回调函数中,将输出结果显示到文本框中。
回调函数:
static VS_UWORD MsgCallBack( VS_ULONG ServiceGroupID, VS_ULONG uMsg, VS_UWORD wParam, VS_UWORD lParam, VS_BOOL *IsProcessed, VS_UWORD Para )
{
switch( uMsg ){
case MSG_VSDISPMSG :
case MSG_VSDISPLUAMSG :
printf("[core]%s\n",(VS_CHAR *)wParam);
break;
case MSG_DISPMSG :
case MSG_DISPLUAMSG :
//--display message in text box
[Control showPythonResult:[NSString stringWithUTF8String:(VS_CHAR*)wParam]];
break;
}
return 0;
}
在初始化CLE时,指定回调函数
VS_CORESIMPLECONTEXT Context;
SRPInterface = VSCoreLib_InitSimple(&Context,"test","123",0,0,MsgCallBack,0,NULL);
4. 执行python脚本
4.1 编译不执行
可以只编译脚本,不执行,此时检查脚本中的语法错误。编译脚本需要调用CLE的函数PreCompile。该函数返回bool值和错误信息,如果返回true,则成功编译;如果返回false, 并且错误信息为空,表示输入脚本不完整;否则错误信息中为返回的编译错误。
SRPControl->SRPLock();
VS_CHAR *ErrorInfo;
const VS_CHAR *str = [val UTF8String];
VS_BOOL Result = BasicSRPInterface->PreCompile("python", str, strlen(str), NULL, &ErrorInfo);
if( Result == VS_TRUE )
self.textBlock1.text = @"success";
else{
if( ErrorInfo == NULL )
self.textBlock1.text = @"More Input";
else
self.textBlock1.text = [NSString stringWithUTF8String:ErrorInfo];
}
SRPControl->SRPUnLock();
4.2 直接执行脚本
调用CLE的函数_RunScript执行python脚本。脚本的输出会被之前设置的回调函数捕获,显示到输出窗口中。
SRPControl->SRPLock();
const VS_CHAR *str = [val UTF8String];
SRPInterface->DoBuffer("python", str, strlen(str), NULL, NULL, NULL, VS_TRUE);
SRPControl->SRPUnLock();
5. 结束语