python编译so
A. python 怎么调用so文件
当需要采用调用c++的程序的时候,需要对原有的数据加一个extern "C"封装一下即可。
采用g++编译的代码也需要的,原因可能是因为c++编译器编译后的二进制so文件中,对c++的函数进行了重新的命名导致的。
extern "C" {
Foo* Foo_new(){ return new Foo(); }
void Foo_bar(Foo* foo){ foo->bar(); }
}
以下两个网页又更详细的介绍
http://blog.waterlin.org/articles/using-python-ctypes-to-link-cpp-library.html
http://stackoverflow.com/questions/145270/calling-c-c-from-python
最后需要补充的一个问题是:当我调用so文件的时候,会发生一个有趣的现象:
我把python放到streaming找运行的时候,发现streaming始终查找不到so,但是数据却是被上传到hadoop的对应的work目录下。
后来定位到原因:
是python加载动态库方面是默认从系统lib库上查找库文件。
我的目录在当前目录下,所以需要从libdy.so变为./libdy.so
B. python *.so 文件 怎么生成的
openstack是最近3年学习python的人最值得学习的一个云计算框架。 OpenStack 包含两个主要模块:Nova 和 Swift,前者是 NASA 开发的虚拟服务器部署和业务计算模块;后者是 Rackspace开发的分布式云存储模块,两者可以一起用,也可以分开单独用。
C. 如何编译C++文件为Python扩展模块
大概有三种常用方法:
1>使用ctypes模块来调用C写的共享库,比如:
[python] view plain print?
#测试ctypes调用linux动态库的能力
from ctypes import *
lib = CDLL("libc.so.6")
printf = lib.printf
printf("Hello World\n")
#查找动态库
from ctypes.util import find_library
print find_library('c')
output = CDLL(find_library("c")).printf
output("测试成功!\n")
但是用它来调用C++写的so就不太合适,因为编译时c++函数名修饰会给你的函数取一个特殊的字符串,你不能在你的python代码里直接使用此函数名,除非你使用的是修饰后的函数名。(在linux下你可以用nm来查看so中的函数名)
2>用C来写python的扩展模块,这个没怎么用过,以后使用时再记录在此。
3>用C++来写python扩展模块:
我是使用Boost.Python来写扩展的,先上工作中的代码片段:
[python] view plain print?
#include <boost/python.hpp> //包含boost.python头文件
#include <cstdio>
#include <string>
using namespace boost::python;//引入命令空间
class lshw //定义一个类
{
public:
lshw();
virtual ~lshw();
void scan_device();
string get_xml();
private:
hwNode *computer;
};
lshw::lshw()
{
computer = new hwNode("computer", hw::system);
}
lshw::~lshw()
{
if (computer)
delete computer;
}
void lshw::scan_device()
{
enable("output:numeric");
disable("output:sanitize");
scan_system(*computer);
}
string lshw::get_xml()
{
return computer->asXML();
}
void hello()
{
std::cout << "Hello World!" <<std::endl;
}
BOOST_PYTHON_MODULE(lshw)
{
class_<lshw, boost::nonable > ("lshw", "This is a lshw project python extend", init<>())//导出类中的方法
.def("scan_device", &lshw::scan_device)
.def("get_xml", &lshw::get_xml)
;
def("hello",&hello);//导出方法
}
使用boost.python其实结构很简单,你只要写很少的boost.python的代码,你可以把大部分的精力放在C++功能代码上,花很少的精力就可以把它扩展成python的模块。下面是我在Ubuntu11.10上的编译过程:
首先安装boost.python:
sudo apt-get install libboost-python1.46.1
再来编译生成so共享库文件:
g++ -shared -fPIC lshw.cc -o lshw.so -lboost_python
使用:
[python] view plain print?
import lshw
hw = lshw.lshw()
lshw.hello()
hw.scan_device()
xml = self.hw.get_xml()
D. python扩展的c代码在哪里写
在哪里写都可以啊,重要的是编译过程。给你介绍下编译过程吧。
在windows和linux下面,对C扩展的编译方法是不一样的,我们先来看windows版的。
我们用C实现一个简单的加法。
首先新建一个文件add.c,代码如下:
#include<Python.h>;
staticPyObject*add(PyObject*self,PyObject*args);
//一定声明为static,把他们限制在这个文件范围里。几乎所有的参数都是PyObject类型,在python,每个东西都是object。
staticPyObject*add(PyObject*self,PyObject*args)
{
intx=0;
inty=0;
intz=0;
if(!PyArg_ParseTuple(args,"i|i",&x,&y))
returnNULL;
/*第一个参数是self,这个是python用的,每个函数都要有。我们暂时不管。args是一个参数列表。她把所有的参数都整合成一个string。所以
我们需要从这个string里来解析我们的参数。PyArg_ParseTuple来完成这个任务。第一个参数是args,就是我们要转换的参数。第二个是格式符号。
“s”代表是个string。从args里提取一个参数就写"s",两个的话就写"s|s",如果是一个string,一个int,就写"s|i",和printf差不多。第三个
参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add,他将提取两个参数。分别是x和y。*/
z=x+y;
returnPy_BuildValue("i",z);
/*调用完之后我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把他转换成PyObject,让python认识。这个用Py_BuildValue
来完成。他是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样,是个格式化符号。第三个参数
是我们需要转换的参数。Py_BuildValue会把所有的返回只组装成一个tutple给python。*/
}
staticPyMethodDefaddMethods[]=
{
{"add",add,METH_VARARGS,"Executeashellcommand."},
{NULL,NULL,0,NULL}
};
/*这个是一个c的结构。他来完成一个映射。我们需要把我们扩展的函数都映射到这个表里。表的第一个字段是python真正认识的。是python里的方法名字。第二个字段是python里的这个方法名字的具体实现的函数名。在python里调用add,真正执行的是用c写的add函数。第三个字段是METH_VARARGS,他告诉python,add是调用c函数来实现的。第四个字段是这个函数的说明。如果你在python里来help这个函数,将显示这个说明。相当于在python里的函数的文档说明。*/
PyMODINIT_FUNCinitadd()
{
Py_InitMole("add",addMethods);
}
/*注意,这个函数的名字不能改动。必须是init+模块名字。我们的模块名字是add。所以这个函数是initadd()。
这样python在导入add的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitMole来将模块名字和映射表结合在一起。他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的mole的.*/
新建一个setup.py,内容如下:
fromdistutils.coreimportsetup,Extension
mole1=Extension('add',sources=['add.c'])
setup(name='PackageName',version='1.0',description='Thisisademopackage',ext_moles=[mole1])
组建:(由于我的机器上装了mingw,所以指定了mingw32。默认的编译器是vs2008。参考:
python setup.py build--compiler=mingw32
执行后会在当前目录生成一个build目录及文件:
buildlib.win32-2.6add.pyd
将add.pyd拷贝到当前目录,并写一个测试文件test.py,代码如下:
import add
print add.add(3,4)
执行一下,输出为7
OK,基本上就是如此了。
在linux下的话,会有少许不同.
即直接用makefile将add.c编译成.so,python可以直接import,makefile代码如下:
PYLIB=/usr/bin
PYINC=/usr/include/python2.6
all:add.c
gccadd.c-g-I$(PYINC)-shared-L$(PYLIB)-lpython2.6-oadd.so
clean:
rm-fadd.so
用同样的测试代码,可以测试通过。
E. windows安装mod_python未生成mod_python.so
在windows上需要.so是非常奇怪的……因为那是linux下动态链接库的拓展名。windows下是dll。
题主最好转到linux下去做这些。
F. 【python-C相互调用】python里的dict如何作为参数传入.so中的c语言函数
#include<stdio.h>
#include<stdlib.h>
#include<Python.h>
staticPyObject*
wmf_reverse(PyObject*self,PyObject*args,PyObject*kwargs){
staticchar*kwlist[]={"name",NULL};
char*name=NULL;
PyObject*retval=NULL;
//问题1:只取一个字符串,format应该是"s"
//>>>if(PyArg_ParseTupleAndKeywords(args,keyds,"isi",kwlist,&name))
if(PyArg_ParseTupleAndKeywords(args,kwargs,"s",kwlist,&name)){
retval=(PyObject*)Py_BuildValue("i",1);
printf("%s ",name);
//问题2:不要释放
//>>>free(name);
}else{
retval=(PyObject*)Py_BuildValue("i",0);
}
returnretval;
}
staticPyMethodDef
wmf_methods[]={
{"reverse",(PyCFunction)wmf_reverse,METH_VARARGS|METH_KEYWORDS,"reverse"},
//问题3:方法定义表,应该用一条空记录来表示结束。
{NULL,NULL,0,NULL},
};
//问题4:没有定义mole
staticstructPyMoleDef
wmf_mole={
PyMoleDef_HEAD_INIT,
"wmf",/*nameofmole*/
NULL,/*moledocumentation,maybeNULL*/
-1,/*sizeofper-interpreterstateofthemole,
or-.*/
wmf_methods,
};
//问题5:入口函数要声明为:PyMODINIT_FUNC
PyMODINIT_FUNC
PyInit_wmf(void){
//问题6:Py_InitMole要初始化的是模块,不是方法。所以传方法定义是错误的。
//另外,python2.x是用Py_Init_mole,python3.x改用PyMole_Create了。
//两者略有差别,自己注意一下吧。这里我用的是python3.x。
//Py_InitMole("wmf",ExtestMethods);
PyObject*m;
m=PyMole_Create(&wmf_mole);
if(m==NULL){
returnNULL;
}
returnm;
}
G. python调用动态库(并且动态库依赖其它动态库)
用depends看一下导出了没有?一般只要标准格式导出就可以使用的。
H. python怎么调用安卓的.so文件
调用不了的,CPU架构都不一样,一个是x86指令集,一个是arm指令集,怎么调?
就算是指令集一样的,你windows的程序也调用不了Linux的so库。
I. python程序py文件能做成so文件吗
可以
一、环境准备
安装cython,以及gcc编译环境
wget get-pip.py
python get-pip.py
pip install cython
yum install -y gcc python-devel
二、编写测试脚本
test.py,内容如下
import os
def test():
print os.path.realpath('.')
三、将其拷贝到python系统路径
/usr/lib/python2.7/site-packages/test
在test目录下创建__init__.py, 与 test.py 的文件
test.py 上面内容如上所示
四、脚本测试
python
>>> import lyh.test
>>> lyh.test.test()
五、编译so文件
以下操作均在 /usr/lib/python2.7/site-packages/test 路径下执行
1. cython test.py
2. gcc -c -fPIC -I/usr/include/python2.7/ test.c
3. gcc -shared test.o -o test.so
六、验证so文件的可用性
1. 移除/usr/lib/python2.7/site-packages/test/test.py 文件,只保留 test.so文件
test
├── __init__.py
└── test.so
2.
python
>>> import test.test
>>> test.test.test()
可以执行
验证完成
七、使用setup.py 编译so
1. 编写setup.py文件,位于/usr/lib/python2.7/site-packages/test,内容如下:
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_moles = cythonize("test.py")
)
2.然后运行
setup.py build_ext --inplace
J. 请教Python 从 egg 中 import so 文件的正确姿势
我写了一个包,用
python setup.py install
安装后会在site-package目录下得到一个.egg 的文件,然后可以在 python 中 import 这个包。 问题是,我在setup.py文件中包含了 package_data,是一个名为xxx.so的动态库文件,这个库文件在 install 之后也被正确包含进那个.egg 文件里了(把.egg 重命名成.zip 解压后可以确认)。 但是,如果只用这个.egg 文件,那么包里的一行代码
from . import xxx
就会报错
ImportError: cannot import name 'xxx'
奇怪的是,如果我重命名.zip 然后解压成文件夹,from . import xxx就能正常加载那个动态库了。
请问熟悉 Python 的 V 友这种情况该如何解决?谢谢!
我后来在`setup.py`中的`setup()`中加入了一条`zip_safe=False`来生成 folder 而不是 egg,解决了问题,但不知道有没有更优雅的解决方案?