云网牛站
所在位置:首页 > Linux编程 > Ubuntu 18.04系统Python3.6下在Python中调用C函数

Ubuntu 18.04系统Python3.6下在Python中调用C函数

2018-07-01 15:15:04作者:zenny_chen稿源:linux站

本文将介绍在Ubuntu 18.04系统下,在Python3.6版本中使得Python脚本能调用C语言函数。以前在Python2.7版本中调用C语言函数的方法不能用在Ubuntu 18.04上,请按本文介绍的做。

 

由于在最新的Ubuntu 18.04中已经预装了Python3.6,因此我们可以直接使用,在命令行中直接用python3.6再加Python脚本文件即可运行。但是,如果我们要写C语言接口提供给Python3.6调用的话需要安装Python3.6的开发包,通过以下命令即可下载安装:

sudo apt-get install python3.6-dev

 

完成之后会在原先/usr/include/目录下的Python3.6m中新增Python.h等诸多头文件。

在开始前,为了方便编译构建,我们先创建一个shell文件,内容如下:

clang c_api.c -std=gnu11 -Os -fPIC -shared -o c_api.so

 

这里,我们将C源文件名命名为c_api.c,然后输出共享动态库名为c_api.so。这里大家要注意的是,最后生成的共享动态库名前面不要加lib前缀,尽管这个是类Unix系统的标准命名法,但如果前面加了lib,Python解释器反而将无法识别。由于Ubuntu下已经把Python相关的头文件以及库路径放置在了/usr目录下,因此我们这里也无需通过-I、-L 去指定头文件路径以及库的路径。最后,各位对于输出的共享动态库的命名要与之后所要创建的Python模块名一致。

 

下面我们来看一下c_api.c源文件内容:

//

//  c_api.c

//  C_API

//

//  Created by Zenny Chen on 2018/7/1.

//  Copyright 2018 CodeLearning Studio. All rights reserved.

//

#include <stdio.h>

#include <python3.6m/Python.h>

static void __attribute__((overloadable)) foo(void)

{

puts("Foo...");

}

static int __attribute__((overloadable)) foo(int i)

{

printf("foo i = %d\n", i);

return i + 1;

}

static int __attribute__((overloadable)) foo(int i, int j)

{

printf("foo i = %d, j = %d\n", i, j);

return i + j;

}

static PyObject* python_foo_v(PyObject *this, PyObject *args)

{

foo();

// 返回None这一Python对象

return Py_BuildValue("s", NULL);

}

static PyObject* python_foo_i(PyObject *this, PyObject *args)

{

int i;

if(PyArg_ParseTuple(args, "i", &i) == 0)

return NULL;

return Py_BuildValue("i", foo(i));

}

static PyObject* python_foo_ii(PyObject *this, PyObject *args)

{

int i, j;

if(PyArg_ParseTuple(args, "ii", &i, &j) == 0)

return NULL;

return Py_BuildValue("i", foo(i, j));

}

static PyMethodDef pythonMethods[] = {

{"foo_v", python_foo_v, METH_NOARGS, "foo with void param and void return value"},

{"foo_i", python_foo_i, METH_VARARGS, "foo with int param and int return value"},

{"foo_ii", python_foo_ii, METH_VARARGS, "foo with (int, int) param and int return value"},

{ NULL }

};

static struct PyModuleDef pythonModule =

{

PyModuleDef_HEAD_INIT,

"c_api",    // name of module

"This is a C API python moddule",   // module documentation, may be NULL

-1,         // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.

pythonMethods

};

PyMODINIT_FUNC PyInit_c_api(void)

{

return PyModule_Create(&pythonModule);

}

 

这里各位要注意的是,最后定义的PyInit_c_api函数就是C语言提供给Python调用的模块加载接口,也就是属于我们当前所创建模块的入口函数。因此它必须顺从一定的命名规则,也就是PyInit_<模块名>。

我们完成c_api.c的编辑之后,打开命令行,进入到它与build.sh所在的文件目录,直接通过bash build.sh即可编译。

 

最后我们再看看Python文件里的内容。我们将Python文件命名为test.py。

# -*- coding: utf-8 -*-

import sys

# 导入c_api模块

import c_api

print(u"开始测试!")

a = c_api.foo_v()

print("a = " + str(a))

a = c_api.foo_i(10)

print("a = " + str(a))

a = c_api.foo_ii(10, 20)

print("a = " + str(a))

 

编辑完之后,我们将它放在之前所生成c_api.so同一文件路径下。各位在Ubuntu 18.04命令行中直接输入python3.6 test.py即可运行!各位这里要注意的是,我们必须用python3.6,这里3.6不能省,否则默认python命令的版本为2.7.x版本。

当然,如果我们在当前系统中就装了一个Python3.6.x版本,没有其他Python3.x版本的话也可以直接用python3 test.py,python3会被直接关联到python3.6上。

 

相关主题

在Ubuntu18.04中使用python的注意事项:pip安装,pip提速

精选文章
热门文章