问题描述
在C++和Python混合编程中,在软件发布的时候需要将python的解释器打包到安装程序中,为了提高用户体验,我们需要让用户感觉不到python的安装,如果用户已经安装有python的环境,我们也要保证不影响现有的系统。
解决方案
在Python2.5以后,python支持从zip文件中读取python脚本文件,支持读取py,pyc,pyo,不支持读取pyd,因此
我们可以将python的标准库编译以后打包到一个zip文件中,在C++中调用python脚本的时候,将zip文件加入到sys.path的搜索路径中来完成。
- 将python的标准库的脚本文件目录C:/Python25/Lib中的脚本文件copy到一个指定的目录,然后我们删除掉一些不用的库文件比如msilib,complier等(此步不熟悉可以不要省去删除多余文件)。
- 将脚本编译为优化后的文件 python -O -m compileall destdir,然后删除所有冗余的py和pyc, del /S /Q "%1/*.pyc" "%1/*.py " ( %1 表示目标文件夹 )
- 将文件压缩成zip格式 "%WINRAR_DIR%/WinRar" a -r -m5 -tk "python25.zip" "*"
- 我们自己的py文件可以按照同样的方法压缩到src.zip中
- 将python的pyd文件(Windows默认是C:/Python25/DLLs)复制到目标文件夹python25_dll中
- 将python25.dll复制到应用程序的搜索路径中
- 在C++中调用Python的C API设置python库的搜索路径,这样我们就可以就可以通过Python C API进行混合语言的编程,在部署的时候不需要单独按照python安装程序
char buffer[1024] = { 0 };
Py_Initialize();
PyRun_SimpleString( "import sys" );
//获取当前路径,如果是GUI程序有可能会改变程序的当前工作目录,如果是服务器
//程序一般当前的工作目录就是二进制文件所在的目录
#ifdef WIN32
char achCwdBuf[PATH_MAX] = {0};
if( NULL != GetModuleFileName(NULL, achCwdBuf, PATH_MAX) )
#else
if( NULL != ACE_OS::getcwd(achCwdBuf, PATH_MAX) )
#endif // end of ifdef WIN32
{
string strCwd = achCwdBuf;
strCwd = strCwd.substr( 0, strCwd.find_last_of( "///" ) );
string strStdZip = strCwd;
strStdZip += "//python25.zip";
sprintf( buffer, "sys.path += ['.', r'%s', r'%s//python25_dlls', r'%s//src.zip', r'%s//python_script']",
strStdZip.c_str(), strCwd.c_str(), strCwd.c_str() );
PyRun_SimpleString( buffer );
}