ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

如何使用Cython将外部C函数导入到IPython笔记本中?

2019-08-24 04:06:06  阅读:326  来源: 互联网

标签:c-3 python ipython cython


我想使用Cython将C函数导入到IPython笔记本中.目前,我正在尝试复制Cython documentation中的示例,但是我收到了编译错误.

我的Python代码(来自iPython笔记本):

import cython
%load_ext Cython

———————————-新细胞

%%cython
cdef extern from "spam.c":
    void order_spam(int tons)

我的C代码:

// spam.c
#include <stdio.h>

static void order_spam(int tons)
{
    printf("Ordered %i tons of spam!\n", tons);
}

运行此代码,我得到以下回溯和错误消息:

CompileError                              Traceback (most recent call last)
<ipython-input-13-8bb733557977> in <module>()
----> 1 get_ipython().run_cell_magic(u'cython', u'', u'\ncdef extern from "spam.c":\n    void order_spam(int tons)')

/Users/danielacker/anaconda2/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in run_cell_magic(self, magic_name, line, cell)
   2118             magic_arg_s = self.var_expand(line, stack_depth)
   2119             with self.builtin_trap:
-> 2120                 result = fn(magic_arg_s, cell)
   2121             return result
   2122 

<decorator-gen-126> in cython(self, line, cell)

/Users/danielacker/anaconda2/lib/python2.7/site-packages/IPython/core/magic.pyc in <lambda>(f, *a, **k)
    191     # but it's overkill for just that one bit of state.
    192     def magic_deco(arg):
--> 193         call = lambda f, *a, **k: f(*a, **k)
    194 
    195         if callable(arg):

/Users/danielacker/anaconda2/lib/python2.7/site-packages/Cython/Build/IpythonMagic.py in cython(self, line, cell)
    276             build_extension.build_temp = os.path.dirname(pyx_file)
    277             build_extension.build_lib  = lib_dir
--> 278             build_extension.run()
    279             self._code_cache[key] = module_name
    280 

/Users/danielacker/anaconda2/lib/python2.7/distutils/command/build_ext.pyc in run(self)
    337 
    338         # Now actually compile and link everything.
--> 339         self.build_extensions()
    340 
    341     def check_extensions_list(self, extensions):

/Users/danielacker/anaconda2/lib/python2.7/distutils/command/build_ext.pyc in build_extensions(self)
    446 
    447         for ext in self.extensions:
--> 448             self.build_extension(ext)
    449 
    450     def build_extension(self, ext):

/Users/danielacker/anaconda2/lib/python2.7/distutils/command/build_ext.pyc in build_extension(self, ext)
    496                                          debug=self.debug,
    497                                          extra_postargs=extra_args,
--> 498                                          depends=ext.depends)
    499 
    500         # XXX -- this is a Vile HACK!

/Users/danielacker/anaconda2/lib/python2.7/distutils/ccompiler.pyc in compile(self, sources, output_dir, macros, include_dirs, debug, extra_preargs, extra_postargs, depends)
    572             except KeyError:
    573                 continue
--> 574             self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
    575 
    576         # Return *all* object filenames, not just the ones we just built.

/Users/danielacker/anaconda2/lib/python2.7/distutils/unixccompiler.pyc in _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)
    120                        extra_postargs)
    121         except DistutilsExecError, msg:
--> 122             raise CompileError, msg
    123 
    124     def create_static_lib(self, objects, output_libname,

CompileError: command 'gcc' failed with exit status 1

我已经尝试在Google上搜索此错误,但我似乎找不到任何相关内容.

解决方法:

%cython magic命令probaby似乎没有做到这一点.

%cython magic命令在这里没有真正完成任务.为了编译它你还需要提供* .c源文件,并且(据我所知)%cython不允许这样做. (The source file for it indicates that it only uses the text entered in the cell as a source file.)

包裹你的C函数:

在介绍可能的解决方案之前,我要指出您创建的.pyx文件实际上并没有自动包装C函数order_spam.如果在cdef extern块中将其指定为cpdef,则可以将其自动换行(或者您可以将它自己包装在cdef extern块之外,这样可以提供更大的灵活性).

我将使用cyspam.pyx的文件名作为Cython文件:

cdef extern from "spam.c":
    cpdef void order_spam(int tons)

注意我是如何使用cpdef为函数声明添加前缀的,这指示Cython自动包装函数.

使用setup.py脚本:

为了完全控制编译过程,通常需要创建一个setup.py脚本,其中包含所有必需的源,包括目录等等.

以下是setup.py脚本的外观:

from distutils.core import setup, Extension
from Cython.Build import cythonize

# you specify the c source file in the sources list
ext = Extension('cyspam', sources = ['cyspam.pyx', 'spam.c'])
setup(name="C spam", ext_modules = cythonize([ext]))

您可以通过简单的文本编辑器或使用%%writefile magic命令通过IPython创建这样的文件. setup.py脚本当然应该放在与cyspam.pyx和spam.c文件相同的目录中.

编译文件:

您可以为此打开终端或使用来自IPython的%%bash命令,无论哪种方式都可以.发出以下命令:

python setup.py build_ext --inplace 

–inplace将生成的.so文件放在当前目录中.

完成这些操作后,您可以轻松地在Ipython中导入文件cyspam,并调用包装的C函数:

汇总来自IPython的所有命令:

总而言之,如果您只想从IPython中执行此操作,您将发出以下命令:

In [1]: %%writefile setup.py
   ....: from distutils.core import setup, Extension
   ....: from Cython.Build import cythonize
   ....: ext = Extension('cyspam', sources = ['cyspam.pyx', 'spam.c'])
   ....: setup(name="C spam", ext_modules = cythonize([ext]))

In [2]: %%bash
   ...: python setup.py build_ext --inplace

In [3]: import cyspam

In [4]: cyspam.order_spam(1000)
You ordered 1000 ammount of spam!

作为替代方法,您始终可以创建一个.pyxbld文件,该文件指定pyximport.install()所需的参数.这提供了相同级别的控制,但对于已经具有使用setup.py脚本经验的Python用户来说,这很可能是违反直觉的.

见相关:

How can I set Cython compiler flags when using pyximport?

标签:c-3,python,ipython,cython
来源: https://codeday.me/bug/20190824/1704548.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有