讨论C/C++中嵌入Python计算器的方法。
本文以VS2010、Python27为例进行说明。
在vs中创建了project之后,增加python的include和lib目录到对应位置。
创建一个C++控制台应用程序,只包含python头文件:
#include
#include
int main(int argc, char* argv[])
{
printf("Hello, Python!\n");
return 0;
}
链接出错:
>LINK : fatal error LNK1104: 无法打开文件“python27_d.lib”
此时,我们并没有在.cpp中或项目属性中提到python27_d.lib这个库,为什么会有这个提示呢?一种可能就是Python.h自动做了这个事情。为此,在头文件中以lib为关键字进行搜索,找到如下的内容:
/* For an MSVC DLL, we can nominate the .lib files used by extensions */
#ifdef MS_COREDLL
# ifndef Py_BUILD_CORE /* not building the core - must be an ext */
# if defined(_MSC_VER)
/* So MSVC users need not specify the .lib file in
their Makefile (other compilers are generally
taken care of by distutils.) */
# ifdef _DEBUG
# pragma comment(lib,"python27_d.lib")
# else
# pragma comment(lib,"python27.lib")
# endif /* _DEBUG */
# endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */
这就解释了为什么会自动去找python lib库。
接下来,就去Python安装目录下的libs中看看是否有所要求的lib文件。结果就是:只有python27.lib,而没有python27_d.lib文件。——如果将VS缺省的Debug改成Release配置,就无链接错误。
两种解决方法:
这里采用第一种方法。
事实上,还有一种方法,就是从源代码编译出一份。——这在后面会提到。
代码增强:用doc的第一个例子继续验证。
#include
#include
int main(int argc, char* argv[])
{
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
Py_Finalize();
printf("Hello, Python!\n");
return 0;
}
运行时出现错误:
ImportError: No module named site
请按任意键继续. . .
有两种解决办法:
这里采用第一种方法,即:
#include
#include
int main(int argc, char* argv[])
{
Py_SetPythonHome("C:/Python27");
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
Py_Finalize();
printf("Hello, Python!\n");
return 0;
}
可以运行成功。
在一开始的时候,main第二个参数用的是const char*,但编译出现错误。所以改成了上面看到的char*。
继续按照python chm中的内容往下走,使用PyRun_SimpleFile()。代码如下:
#include
#include
int main(int argc, char* argv[])
{
Py_SetPythonHome("C:/Python27");
Py_Initialize();
char* filename = "test.py";
FILE* fp = fopen(filename, "r");
PyRun_SimpleFile(fp, filename);
Py_Finalize();
fclose(fp);
return 0;
}
这个时候,代码一运行就挂掉:
不管换成debug或release,不管是MD、MT、MTd等等,都不行。网上找到原因说是当前使用的VC环境和python安装的lib生成环境不一致。为此,就只能用当前的VS从Python源码编译一套lib出来。
用VS2010打开Python-2.7.7\PCbuild\pcbuild.sln,工程会自动升级。然后开始编译(为了省事,全部生成),最后会生成python27_d.lib,python27_d.dll等文件。——可能会有某些项目生成失败,但通常不会影响当前的python使用场景。
用这个生成的lib放到(/替换)(比如)C:/python27/libs/目录下,重新编译&链接上面的示例代码,就可以正常运行了。不过对于release版本,会使用python27.dll,而这个dll则会在机器的环境变量的目录中存在。如果不更改这些已在环境变量目录中的这些dll,即便把自己生成的dll放在exe目录下,仍然不会去调用它。
为此,我们转了一圈,还是回到PyRun_SimpleString+execfile这条更省事的路上来。
参考:https://docs.python.org/2/faq/windows.html#how-can-i-embed-python-into-a-windows-application
拷贝如下:
There are two problems with Python’s C API which will become apparent if you use a compiler other than MSVC, the compiler used to build pythonNN.dll.
Problem 1: The so-called “Very High Level” functions that take FILE * arguments will not work in a multi-compiler environment because each compiler’s notion of a struct FILE will be different. From an implementation standpoint these are very _low_ level functions.
因为lib和dll版本的问题,所以使用PyRun_SimpleString+execfile这种方法。代码如下:
#include
#include
int main(int argc, char* argv[])
{
Py_SetPythonHome("C:/Python27");
Py_Initialize();
PyRun_SimpleString("execfile(\"test.py\")");
Py_Finalize();
return 0;
}
源码下载位置:http://download.csdn.net/detail/u013344915/7478759
Set the default “home” directory, that is, the location of the standard Python libraries. See PYTHONHOME for the meaning of the argument string.
The argument should point to a zero-terminated character string in static storage whose contents will not change for the duration of the program’s execution. No code in the Python interpreter will change the contents of this storage.
Return the default “home”, that is, the value set by a previous call to Py_SetPythonHome(), or the value of the PYTHONHOME environment variable if it is set.
Change the location of the standard Python libraries. By default, the libraries are searched in prefix/lib/pythonversion and exec_prefix/lib/pythonversion, where prefix and exec_prefix are installation-dependent directories, both defaulting to /usr/local.
When PYTHONHOME is set to a single directory, its value replaces both prefix and exec_prefix. To specify different values for these, set PYTHONHOME to prefix:exec_prefix.
对应的源码:
static char *default_home = NULL;
void
Py_SetPythonHome(char *home)
{
default_home = home;
}
char *
Py_GetPythonHome(void)
{
char *home = default_home;
if (home == NULL && !Py_IgnoreEnvironmentFlag)
home = Py_GETENV("PYTHONHOME");
return home;
}
解读: