【问题标题】:How to call JUCE using Cython?如何使用 Cython 调用 JUCE?
【发布时间】:2017-07-30 18:31:26
【问题描述】:

目前我正在尝试让 JUCE 音频框架在 Cython 中工作。因此,我首先想通过 JUCE 框架显示AlertWindow 来运行一个小而简单的示例,但目前我似乎有两个小问题: 1. 从 JUCE 框架调用枚举时遇到问题 2.我不知道如何包含整个框架进行编译和链接。

我的 setup.py(用“python3 setup.py build_ext --inplace”调用):

# Cython compile instructions
from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize


compile_args = ['-g', '-std=c++11', '-stdlib=libc++']

extensions = [Extension('testb', ['src/JUCE/testb.pyx'],
            extra_compile_args=compile_args,
            include_dirs = ["JUCE/modules"],)]

setup(
    name='My app',
    ext_modules=cythonize(extensions)
)

我的 testb.pyx(问题 1 在这里):

# distutils: language = c++

cdef extern from "JuceLibraryCode/JuceHeader.h" namespace "juce":
    cdef cppclass AlertWindow:
        AlertWindow(String, String, AlertIconType)

cdef class PyAlertWindow:
    cdef AlertWindow *thisptr
    def __cinit__(self):
        self.thisptr = new AlertWindow("", "", NoIcon) # Don't know how to call the enum right here
    def __dealloc__(self):
        del self.thisptr
    @staticmethod
    def showAlertWindow(b):
        print("at least this works")

此外,我不断收到这些类型的错误,据我所知,这是由于框架的其余部分没有被编译和包含/链接造成的。我该怎么做?

ImportError:
dlopen(<project root>/build/lib/testb.cpython-36m-darwin.so, 2): Symbol not found: __ZN4juce6StringC1Ev
Referenced from:
<project root>/build/lib/testb.cpython-36m-darwin.so
Expected in: flat namespace
in <project root>/build/lib/testb.cpython-36m-darwin.so

此外,使用 --inplace 标志,所有已编译的文件都会转储到我的主文件夹中,这似乎不是很可扩展,尤其是对于较大的框架。如何确保所有 .so 文件最终都包含在内,以便轻松引用?还是有更好的方法来解决这个问题?


好的,所以在@ead 的帮助下,我能够更进一步。代码现在如下所示:

# setup.py

from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize

compile_args = ['-g', '-std=c++11', '-stdlib=libc++']

extensions = [Extension('testb', ['src/program/testb.pyx'],
                extra_compile_args=compile_args,
                include_dirs = ["JUCE/modules"],
                libraries=["NewProject"], #the name of your library, WHICH MIGHT BE DIFFERENT FROM THE FILENAME!
                library_dirs=["src/program/JuceLibraryCode"] #where your library is placed.

                    )]

setup(
    name='My app',
    ext_modules=cythonize(extensions)
)

还有我的 Cython 文件:

# testb.pyx
# distutils: language = c++

from libcpp.string cimport string

cdef extern from "JuceLibraryCode/JuceHeader.h":
    cdef cppclass AlertWindow:
        AlertWindow(String, String, AlertIconType, Component*)

    cdef cppclass Component:
        Component()

    cdef cppclass String:
        String(string)

cdef extern from "JuceLibraryCode/JuceHeader.h" namespace    "juce::AlertWindow":
    ctypedef enum AlertIconType:
        NoIcon
        QuestionIcon
        WarningIcon
        InfoIcon

cdef class PyAlertWindow:
    cdef AlertWindow *thisptr
    def __cinit__(self):
        self.thisptr = new AlertWindow(String(""), String(""), AlertIconType(NoIcon), NULL)
    def __dealloc__(self):
        del self.thisptr

该示例现在可以正常编译。但是,当我导入生成的包时,出现以下错误:

ImportError: dlopen(<project root>/testb.cpython-36m-darwin.so, 2): Symbol not found: _CGAffineTransformIdentity
  Referenced from: <project root>/testb.cpython-36m-darwin.so
  Expected in: flat namespace
 in <project root>/testb.cpython-36m-darwin.so

这似乎与 Cocoa (here) 或 CoreGraphics (here) 相关(我也相信它是 Cocoa 的继承者)。那么我将如何解决这个问题?我是否需要包含 CoreGraphics 框架,如果需要,如何包含? (只需添加标志 -framework CoreGraphics 会导致 clang: error: unknown argument: '-framework CoreGraphics'

提前感谢您的回答!

【问题讨论】:

    标签: enums compilation cython juce


    【解决方案1】:

    你的第一个问题:如果你的枚举和函数被定义为

    //YYY.h
    namespace Foo{
      enum Bar {bar1, bar2};
      void do_it(Bar bar);
    }
    

    然后您需要在 cython 中导入枚举值以及枚举类型名称,它应该如下所示:

    cdef extern from 'XXX/YYY.h' namespace 'Foo':
        ctypedef enum Bar:
          bar1
          bar2
        cpdef void do_it(Bar a)
    

    然后可以通过do_it(bar1)do_it(bar2) 在您的 cython 代码中的某处调用它。其实我前段时间是从this question here on SO那里学来的,大家可以考虑点个赞哦。

    第二个问题是您需要链接到 juce-library(现在您只使用包含),为此您需要将以下内容添加到您的 Extension-setup:

    Extension('testb', ['src/JUCE/testb.pyx'], ...
              libraries=[juce],#here the right name on your system
              library_dirs=[PATH_TO_JUCE_LIB_ON_YOUR_SYSTEM]
             }
    

    PS:如果您不喜欢 inplace-option 的结果,请咨询distutils-documentation 了解替代方案。

    编辑:JUCE 有一些进一步的依赖项需要提供给链接器。我认为最好的方法是为您的系统构建一个 c++ 示例(例如HelloWorld)并查看需要哪些库。

    通过查看Makefile on Linux,似乎至少需要以下库:freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0。也许你甚至需要先安装它们,我不认为它们是每个系统的默认设置。

    那么您的设置应该如下所示:

    Extension('testb', ['src/JUCE/testb.pyx'], ...
              libraries=['juce', 'x11', 'freetype2', ...], #all needed libraries
              library_dirs=[PATH_TO_JUCE, '/usr/X11R6/lib', '/usr/lib', ...] #all needed library paths
             }
    

    【讨论】:

    • 非常感谢您的回答,它似乎解决了我的枚举问题。它似乎也为我的其他问题提供了解决方案,但尽管我尽了最大努力,但我仍然遇到了麻烦。你能给我更多的细节吗?我有一个 JuceHeader.h(如 OP 中所见),它又导入了许多其他头文件,并且我在 *.a 文件中有 JUCE 库。那么我将如何使用这是 Cython?只需填写 library 和 library_dirs 会导致相同的错误。奇怪的是编译很顺利,在导入过程中我只得到一个 Symbol not found-error。
    • @meme 你能提供你的确切设置和确切的错误信息吗?您确定缺少的符号是图书馆提供的吗?
    • 谢谢,我得到了很多(?)进一步,但我正在运行一个相关的问题(在下面扩展)。你知道这可能是什么原因吗?
    猜你喜欢
    • 2014-10-21
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    相关资源
    最近更新 更多