2017-07-30 8 views
0

En ce moment j'essaye de faire fonctionner le framework audio JUCE à partir de Cython. En tant que tel, je veux d'abord obtenir un exemple petit et simple en cours d'exécution en montrant un AlertWindow à travers le cadre JUCE, mais pour le moment, je semble avoir deux petits problèmes: 1. J'ai un problème avec l'appel d'une énumération de la JUCE framework 2. Je ne sais pas comment inclure tout le cadre de compilation et de liaison.Comment appeler JUCE en utilisant Cython?

Mon setup.py (appelé avec "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) 
) 

Mon testb.pyx (problème 1 est ici):

# 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") 

De plus, je continuellement obtenir ce type d'erreurs, qui sont autant que je sache causé par le fait que le reste du cadre n'est pas compilé et inclus/lié. Comment ferais-je cela?

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 

En outre, avec le drapeau de --inplace, tous les fichiers compilés se jetés dans mon dossier principal, qui ne semble pas très échelonnable, en particulier avec les cadres plus larges. Comment puis-je m'assurer que tous les fichiers .so finissent par être facilement référencés? Ou y a-t-il de meilleures façons de gérer cela?


Ok, donc avec l'aide de @ead j'ai pu obtenir un peu plus loin. Le code se présente maintenant comme suit:

# 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) 
) 

Et mon dossier 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 

Et l'exemple compile maintenant très bien. Cependant, quand j'importer le package résultant je reçois l'erreur suivante:

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 

Ce qui semble être lié à Cocoa (here) ou CoreGraphics (here) (que je crois aussi est le successeur de cacao). Alors, comment pourrais-je résoudre cela? Dois-je inclure le framework CoreGraphics et si oui, comment? (Simplement ajouter le drapeau -Cadre CoreGraphics résultats dans clang: Erreur: Argument inconnu: '-Cadre CoreGraphics de malheureusement)

Merci d'avance pour vos réponses!

Répondre

1

Pour votre premier problème: Si votre ENUM et la fonction sont définies comme

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

alors vous devez importer les ENUM valeurs cython avec ENUM nom-type et il devrait ressembler à:

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

Ensuite, il peut être appelé via do_it(bar1) ou do_it(bar2) quelque part dans votre code cython. En fait, je l'ai appris de this question here on SO il y a quelque temps, donc vous pouvez envisager de le voter.

Le deuxième problème est que vous devez lier à la juce-bibliothèque (utilisez en ce moment, vous ne le comprend), pour cela, vous devez ajouter ce qui suit à votre 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 : Si vous n'aimez pas les résultats avec l'option inplace, veuillez consulter le distutils-documentation pour les alternatives.

Édition: JUCE a d'autres dépendances qui doivent être fournies à l'éditeur de liens. Je pense que le meilleur moyen est de construire l'un des exemples C++ (par exemple HelloWorld) pour votre système et de voir quelles bibliothèques sont nécessaires.

En regardant dans le Makefile on Linux, il semble que les bibliothèques suivantes sont nécessaires: freetype2 libcurl x11 xext xinerama webkit2gtk-4.0 gtk+-x11-3.0. Peut-être que vous avez même besoin de les installer en premier, je ne pense pas qu'ils sont par défaut sur tous les systèmes.

Ensuite, votre configuration devrait ressembler à:

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 
     } 
+0

Merci beaucoup pour votre réponse, il semble avoir résolu mon problème avec les énumérations. Il semble également offrir une solution à mon autre problème, mais malgré tous mes efforts, j'ai toujours des problèmes avec ça. Pourriez-vous me donner plus de détails? J'ai un JuceHeader.h (comme vu dans l'OP) qui à son tour importe beaucoup d'autres en-têtes, et j'ai la librairie JUCE dans un fichier * .a. Comment puis-je utiliser ceci est Cython? Il suffit de remplir les bibliothèques et library_dirs pour obtenir la même erreur. La partie étrange est que la compilation se passe bien, et je reçois seulement un symbole non trouvé-erreur lors de l'importation. –

+1

@meme pourriez-vous fournir votre configuration exacte et le message d'erreur exact? Êtes-vous sûr que le symbole manquant est fourni par la bibliothèque? – ead

+0

Merci, j'ai beaucoup (?) Plus loin, mais je cours dans un problème connexe (qui est prolongé ci-dessous). Savez-vous ce qui pourrait causer cela? –