 Bienvenue, tout le monde. C'est difficile de passer après une grande chanson ce matin, mais mon objectif n'est pas éthique, mais technique. Donc, si je vous donne cette histoire aujourd'hui, c'est parce que je crois vraiment en CFFI pour improving la maintenabilité et la naissance robuste de l'extension de Python. Je veux partager avec vous ma connaissance et ma expérience afin de vous convaincre pour vous donner un travail à la CFFI la prochaine fois que vous avez besoin d'écrire une extension Python. Si vous étiez à la quenote Mondique, Armin Renature s'est dit que la CFFI alloguer la Python pour évoluer une étape plus tard. Je suis totalement d'accord avec IMM et cette parole réinforcée cette vision. Donc, qui est-je ? Je suis Jean-Sébastien Bevilacrois. J'écoute 3 softwares tous les jours et je suis un fan de l'écosystème et de la philosophie de OpenSouth. Vous pouvez trouver une grande partie de ma contribution sur GitHub. En plus, je travaille à Linaigra. C'est une compagnie française qui prouve 3 softwares et c'est cette compagnie qui me encourage à donner cette parole aujourd'hui. Si vous avez besoin d'aide pour un 3 softwares, juste contactez-vous. Nous serons heureux d'y aider. D'abord, pourquoi nous avons besoin d'une extension Python ? Je vais vous parler de ma utilisation. Un an plus tard, la nouvelle API Vulkan a été réalisée. Vulkan est une nouvelle API graphique qui va remplacer OpenGL dans le futur. C'est donc un API graphique de haut niveau. Vous pouvez créer 3 games avec ça et c'est cross compatible avec Windows, Linux et Android. En ce moment, j'ai appris OpenGL, développement et Vulkan. J'ai eu l'opportunité d'improver mon knowledge 3D et la knowledge de haut niveau. Bienvenue à vous ! Soudain, avec un C-language, vous pouvez avoir un système d'erreur, comme Segmentation Fold, et avec Python, c'est très difficile de traiter Segmentation Fold. Valgreen Tool peut vous aider, mais c'est toujours un task difficile que vous n'aurez pas appris. Je peux vous montrer. Pour écrire une extension Python dans un C, vous devez utiliser l'application C-Python. Ça vous permet de créer un module et d'adverter des fonctions et des classes. Donc après lire l'application C-Python, j'ai commencé ma extension C. C'était clair et j'ai perdu cette conflite, mais c'est toujours C. Nous devons combattre encore Maloch, Free, comme usual, mais, parce que c'est trop facile, l'application C-Python ajoute la quantité de référence et l'application cumbersome. Je l'ai presque donné plusieurs fois par rapport à l'aimment de Rock. Donc maintenant, nous allons voir une solution existante pour résoudre la complexité de la extension C, mais avant ça, nous allons voir l'application C-Python et l'application C-Python. De tout cas, je vais souvent utiliser l'application C-Python et l'application C-Python pour expliquer clairement ce que je veux dire par ces termes. L'application C-Python veut dire « application programming interface ». Et l'application C-Python veut dire « application binary interface ». L'application C-Python veut dire « humain use ». Si vous appelez une fonction, vous devez savoir le nom de l'application C-Python. Donc, en application C-Python, c'est tout expérimenté dans le code saut. L'application C-Python est très similaire, pensez-vous à l'application C-Python de l'application C-Python. C'est très clair que, quand vous écrivez l'application C-Python, vous utilisez l'application humaine. Puis, quand votre application C-Python est compagnie, l'application C-Python va accéder à l'application C-Python. Peut-être, vous vous inquiétez à l'application C-Python. Mais, accéder à l'application C-Python avec l'application C-Python vous permet d'utiliser un lien dynamiquement à l'époque. Les deux peuvent être utilisés dans un langage interprété comme Python, sans compilation. L'application C-Python peut être intéressant d'utiliser. Vous devez explicitement décrire l'interface binary comme vous le verrez après. Vous devez voir la solution existante pour facilement décrire l'extension Python. Comme je l'ai dit juste avant, vous pouvez le faire avec l'application C-Python mais c'est un task difficile. Le premier est Python. Python, comme vous le savez, je pense, vous utilisez un approche intéressant. Il peut exécuter directement votre code Python et vous pouvez ajouter des éléments de syntaxe de l'interface. C'est très bien mais comme vous pouvez le voir sur la table, quand vous commencez à ajouter un syntaxe de Python votre code Python n'est pas plus Python. Et donc vous perdez la compétition et Python devient une dépendance de l'interface. Vous devez prendre ça en compte avant de l'utiliser. Cette dépendance de l'interface peut être dangereuse. En plus, le premier objectif de Python est d'imprové la performance de la compétition C-Python. Python peut être compilée et TOS supporte l'application API et l'application API mod. Une autre solution bien connue est C-Types. C-Types est un built-in. C'est un très bon point parce que vous pouvez être sûr que C-Types est toujours disponible. Avec C-Types, vous n'avez pas besoin de compilations. Ça fonctionne seulement en l'application API mod. Vous êtes dynamiquement liés à un application de l'interface durant le type. Si vous avez un application de l'interface de la compétition C-Types, vous devez apprendre un nouveau API. Vous devez transmettre votre C-Header à l'application C-Types. Dans cet exemple, je déclare un point strict et reposé la fonction vector de la compétition C-Library. Comme vous pouvez le voir, c'est error-prone et cumbersome. Si vous avez un très gros libraire, ce sera pire et ça pourrait vous donner parce qu'on a misé un API. Une autre bonne partie. 7 ans auparavant, 2 très bonnes personnes Amin Rigo et Mathieu Fijiarski créé CFFI. Vous pouvez savoir ces names depuis qu'ils ont été occupés de PiPi2. Ce n'est pas un morceau. Pour l'information, PiPi is an alternative Python interpreter with aJite. Donc, à l'abord, CFFI a été un alternative to C-Types. It was working only on the API mode. Later, the API mode was added and revolutionised Python extension ecosystem. Before CFFI, to create an API mode extension for Python, you had to use the C-Pyton C-API or Cyton which at the time was working only with C-Pyton. With CFFI, extension are working with C-Pyton 2, 3 and PiPi without changing one line of your code. That's good. Now you understand API and API mode, I can show you how it works with CFFI. But just before that, let's introduce another concept of CFFI. This one is a lot simpler than API and API mode. In the inline mode, everything is set up every time you import your Python code. In the out-of-line mode now, you have a separate step of preparation and possibly compilation that produces a module which your main program can then import. Of course, inline mode is available only for API. Since API mode require compilation. Let's see some examples. These first examples show how to work with API and inline mode. This is the first feature supported by CFFI and it's exactly what C-Type is done for. So we can compare it to C-Types. Like you can see with CFFI, you just pass the C either to C-Def and open your library, that's all. No API to learn. CFFI syntax is clean and intuitive. Like I said, with C-Types, you declare manually the library structure. So I will just show you a small demo of the API mode. On this example, with the open non, I load the entire scene in space which contains printf function, cprintf function, like that. So to let CFFI know this function, I had to give it with C-Def. Then I create a char argument and I can pass it to the printf function. Then I print a string with our char argument. Let's try it. It works. So I print with a cprintf function, not with a Python printf function. Let's make a big difference. So like you can see, it's very simple to use. So CFFI goes one step further with its API mode now. Syntax is still similar, but you can notice a difference. We pass C code to CFFI with the set source function. Then you just ask CFFI to compile your module. Your pattern extension is robust, fast and easy to maintain. With this API mode, you can't have segmentation fault due to a mismatching API. You can if your code is not well-written. Moreover, it adds convenient features, like you can see. You can replace useless value by 3 dots, but I will not go into detail on this feature. So just a simple demo with API mode. I think I have a small problem with my talent. Let's continue. So now the very interesting part. I'm currently building a 3D engine with Python and the new Vulkan Graphic API. Like I said to you, I created a Vulkan wrapper directly in C with the Python C API. But if I'm here today, it's thanks to Armin Rigo. Because when I show him my Vulkan wrapper on ISE, he tells me you could have used CFFI. And then he explained me how to create packages of CFFI. It takes no more to meet a new challenge, write a Vulkan wrapper directly with CFFI. Was I ready to lose months of work? Yes. It's an odd decision because I spent a lot of time of my wrapper in C. But I definitely made the right choice. I'm going to show you why. So, like all engineer, we love statistics. The Vulkan API is huge. Android of functions, Android of strict, Android of constants. More than 5,000 lines of code just for the C header. And there is a XML descriptor. So, wrapping all this API in plain C is just madness. As you can see with these numbers. More than 60,000 lines for the generated C file. But I'm crazy enough to have done it. Whereas with CFFI, it's only simple and clean Python code. To give you an idea about time, it took me one month and a half for the C version. And only two weeks with CFFI. This time is only on my spare time. So, I think it would have taken only one weeks at full time with CFFI. And moreover, when I got an open DSU on GitHub, I can fix it in one hour maximum because it's just Python, clean and simple. The C version was too difficult to maintain. So, how it works. In both cases, I use a generator because the wrapper, like you saw, is very big. So, Kronos Group, the group behind Vulkan, did a very great job with Vulkan. It's open source and you can contribute easily to GitHub to the spec too. It provides an XML file that describes the API. So, my generator takes this XML file as input and generates the Vulkan wrapper as output. By doing a generator, I can update the wrapper in two minutes when a new relation of the API is released. So, basically, here are the steps. First, I load and pass XML definition. Then, I generate the data model. Then, I generate the Python module with Jinja2. Jinja2 is a template engine. I think you know it. It's very famous in the Python community. So, passing is done with XML2Dict package. XML2Dict is a Python module very good to pass an XML file without IDH. So, it transforms your XML into a hierarchical Python dictionary. So, the first step is done. We have a good data model. Is it to pass? So, we can pass it to the Jinja2 template. I focus only on this part because that's where the two modules differs. What you see here is the folder structure of the C extension. Like you can see, there are too much things involved. So, to keep code maintainable, I have to split it up. Line of code is a good indicator because you can see it's very huge, but what is more important is the complexity of the code. So, you can see it's very huge but what is more important is the complexity of the code. Like you can see, it's huge. Moreover, with C code you have to manage memory yourself and this is very, very error prone. Now, the same thing with CFFI. It's very different. Despite of its looks, what you see on screen means a lot. With CFFIs, I did not need to think about architecture. It was very obvious all in one file. One more point for CFFI. But you don't have to trust my words when I say CFFI is better. Let's see it in action and you will understand. Constant is the easier part and both cases are simple. In C, we just use the CPyton C API to add constant to our module but we have to take care about the variable type. With CFFI it's just Python and it's dynamically typed variable. But only with constant, you don't go far away. Next step is to create binding for strict. Here's the difficulty. But in Python, there is no strict concept. So there are classes which is similar. With CPyton you have to handle the new, the Dell in it get for each member and I don't handle the set. So you can't with my C wrapper you can't update an object after it is initialized. You have to use malloc to allocate memory for your object in the new. In Dell you must free your object and in it you have to pass each parameter with CPyton which can be tricky. And in get, you have to convert your C strict to Python object. I can assure you it takes me lot of time to figure out how to properly do it. Code is so long that I can't show you an example on screen. With CFFI now it's 40 line. CFFI handles for us object allocation and deletion. I just use plain Python to handle all strict initialization in a generic way. I repeat to be sure understand this generic new function works for all my strict. With CPyton API the step I showed you must be done for each strict and there are hundreds of strict in the Vulkan API. When you really realize these benefits you just fall in love with CFFI. So what I showed you until here is the API mod. Let's try the fast and robust API mod now. We are going to wrap a C library with the API out of line mod. This mod is robust and fast but you need compilation. I don't know if you know Shatter C. It's a library we are going to wrap. Shatter C is a free software done by Google and gives you the ability to compile GLSL language to spear v binary. GLSL and spear v if you just do some 3D development you may know this language. So I usually to create an extension with API mod I usually create a folder dedicated to CFFI that I name CFFI build and I recommend you to do so to keep a clean separation of concerns. So in this on the screen Shatter C.h contains functions signatures and strict. We just copy past the header provided by Google and CFFI handles it. I don't need to to modify it in this case. Pie Shatter C build folder is used to generate the Python extension. So next we have the pie Shatter C folder containing our wrapper and finally we'll take a look at the setup with a special feature of CFFI. So the definition first. Like you see we first read content of the Shatter C header and pass it to the cdf function that's all for the definition. Sometimes you need to rewrite your header but in that case the header is so clean that I can give it like that to CFFI. So 3 lines and CFFI knows how to handle this library it's very beautiful. So now the building part with this few lines we tell CFFI to compile the cells with statically linked library Shatter C combined and to name the extension Pie Shatter C. Shatter C combined is a static library that we have to compile before running this CFFI part. I don't show you how because it's not directly linked and related to CFFI. You can look on GitHub where you are interested in. Like you can see there is no C code involved we just tell CFFI to open a Python portal to the Shatter C library. Here again it looks like magic. So now we have to use it. Currently our extension is ready but we remain dependent of CFFI. It means that for example if you want to pass a pointer to a function you have to use the CFFI to access this function. But when using your wrapper your users shouldn't need to know CFFI it's just a dependency. So we are going to write a small Python code especially for that. This code is located in Pie Shatter C init and is loaded automatically when you import your module. So this is the init file. So first we load our extension which contains CFFI and lib modules. So the lib modules contains all functions and strict related to our library. And if CFFI is used to interface with our library. Let's examine the compile into spearv function. Remember the Shatter C library allows you to compile GLSL to spearv so this is this function. All functions defined in our extension can be accessed through lib the lib object. If you take a look at the compile line here the third line we can pass pure Python type like int or string and CFFI converts it for us. It's clean and intuitive. A small note with Python 3 string must be byte. Next Shatter C returns a pointer to us we have to tell CFFI to convert it to a byte Python object. Like that I can use it in my program with namepy or something else. So we first get back the pointer and the length but we can't directly copy the data to a byte in Python because byte type is immutable. So we have to copy data into a byte array, a temporary byte array and pass it to the object. You should take a look at the ffi1memove function. It's very similar to the memcopy c function but directly in Python. So here I'm doing memory manipulation directly in Python. Good, that's good CFFI. So in bonus CFFI provides set up tools extension you just add the entry CFFI modules and your extension will be built by set up tools. It's a good way to package your module. So let's see the example. Ok, so we can enjoy the result. Let's play a simple game, very simple just for the demo. So like you will see I'm using the new shiny Vulcan API with Vulcan wrapper and the byte Shatter C wrapper to convert GLSL code and put it inside the graphic card. So this simple game is written fully with Python and make use of the new shiny Vulcan API. So very very simple game. Not impressive but we can do impressive thing now. Before finishing this talk I have to thank two very special persons. Without them this talk will not exist so please welcome the sponsors of CFFI Armory Ringo and Machete Fijalski. I think they did a lot for our Python community and they are very valuable persons because I talked with them yesterday, very nice. And thank you so much for your incredible work. You make the greatness of Python and you deserve our respect. Thank you again. So I hope that like me you can try this talk. If one day you need to use a C library or you need to improve performance of your code, please think about CFFI and thank you for your attention and have a nice day. If you have question. Do we have any questions? Thank you for the talk. Just a quick one. So the demo was Python 2, right? Not 3 because 3 takes bytes not strings. Can you repeat please what was using Python 2, is that correct? With Python 3. 3.6. Because strings are passed as bytes. Yes. Thank you. Is this only interfacing to C or can you interface to C++ as well? So currently I think it's only C but you can, when you have a C++ library because PyShadow C is a C++ library you can do a C either for your C++ library et then you use it with CFFI. Hi, how about interfacing in existing libraries that does its own garbage collection? I will come because I don't understand from it. Good question, maybe I mean can help us because it's very specific. So garbage collection well you need to do it completely manually, it's a story. However garbage whatever garbage collection is needed by your C library you need to do it manually. There is no automatic garbage collection at the level of CFFI simply. Hi, is there any specific pain with handling callbacks functions, stuff like that? With the recent version of CFFI there is a very good feature about callbacks so you can I handle them. With the Vulkan wrapper back if you know Vulkan IPI I don't know and I handle them I can generate them automatically so you can take a look on my GitHub. If you need callback with CFFI it's a good example. If there are no more questions I can't see any last minute things. Alright, thank you very much for your talk. Let's give a hand to John Sebastian. Thank you.