Python的标准版本是用C语言写成的,提供C语言的API,所以可以很容易嵌入C/C++程序中。本文介绍嵌入操作如何进行,并如何采用cmake编译。
嵌入还是扩展
嵌入(Embedding)是指在C++程序中嵌入Python的解释器。如果你用过Sublime Tex编辑器,你很可能知道Sublime Text就嵌入了Python解释器,所以Sublime Text的插件都是用Python语言编写的。
扩展(Extending)是指用其他语言(C/C++)编写Python的模块,最后导入Python使用。
嵌入和扩展这两种操作从原理上并没有很大区别,一般都要用到Python的API,以及在Python和与其交互的语言之间转换数据类型。差别在于运行的时候以谁为主,嵌入的话程序的主体由宿主语言控制,扩展的话程序的主体由Python控制。
这里的Python指的是标准版的用C语言实现的Python,俗称CPython。Python语言还有其他版本,比如基于Java平台的Jython,或者基于.Net平台的IronPython。
嵌入的例子
Python3的官方文档中有一个章节Embedding Python in Another Application,专门介绍如何把Python嵌入到其他程序中。 该章节中由一个例子:
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
上面的代码看起来有点复杂,在C++程序中初始化了Python解释器,然后让这个解释器执行一下Python脚本:
from time import time, ctime
print('Today is', ctime(time()))
程序的结果是在命令行上输出当前的时间,比如:Today is Mon Jul 30 14:14:14 2018
。
使用cmake编译
那如果编译上面的例子呢?如果直接调用gcc/g++命令或者手写makefile会比较麻烦,一个简化的办法是使用cmake。
cmake需要写一个CMakeLists.txt
的指令文件。对于上面的例子,对应的CMakeLists.txt
的内容如下:
cmake_minimum_required(VERSION 3.12)
project(mypy)
find_package(Python3 COMPONENTS Development)
include_directories(${Python3_INCLUDE_DIRS})
add_executable(mypy main.cc)
target_link_libraries(mypy PRIVATE ${Python3_LIBRARIES})
上面的cmake指令使用了FindPython3
指令包。该指令包在cmake 3.12版本才支持,所以要通过cmake_minimum_required(VERSION 3.12)
指定cmake的最小版本为3.12。
find_package(Python3 COMPONENTS Development)
使用FindPython3
指令包来查找系统中的Python,这条指令会生成一系列的变量,比如用来指示Python头文件位置的Python3_INCLUDE_DIRS
,还有用来指示Python链接库的Python3_LIBRARIES
。
project(mypy)
告诉cmake我们的项目名为mypy,最后生成的可执行文件就叫mypy。add_executable(mypy main.cc)
指定main.cc
为mypy的源代码。main.cc
的内容就是上个章节的那个例子。include_directories(${Python3_INCLUDE_DIRS})
告诉cmake在编译mypy时要添加Python的头文件目录;target_link_libraries(mypy PRIVATE ${Python3_LIBRARIES})
告诉cmake在链接的时候添加Python的库。
一起就绪,执行以下命令来生成mypy:
cmake . # CMakeLists.txt必须在同一个目录
make # 在cmake成功之后,执行make
一起顺利的话就会生成mypy,然后执行mypy,就会获得当前日期:
> ./mypy
Today is Mon Jul 30 14:14:14 2018
大功告成!
其他参考
- Extending/Embedding FAQ
- Python/C API Reference Manual
- Python Embedding in C++ : ImportError: No module named pyfunction
(本篇完)