Skip to content

Document how to embed Cython modules in C/C++ applications #3510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
scoder opened this issue Apr 14, 2020 · 11 comments
Open

Document how to embed Cython modules in C/C++ applications #3510

scoder opened this issue Apr 14, 2020 · 11 comments

Comments

@scoder
Copy link
Contributor

scoder commented Apr 14, 2020

The documentation on embedding is inherently lacking. Even the one in the CPython docs is incomplete at best.

There are some hints in the Wiki, there's the --embed option to the cython and cythonize frontends, the embedding demo, the PyImport_AppendInittab() function in CPython and the documentation of the module init function in CPython.

All of these are incomplete and none of them gives the whole picture in one place. There should be a dedicated documentation page in the Cython docs for this, and the documentation in the CPython docs is also worth improving.

@scoder scoder changed the title Document embedding Document how to embed Cython modules in C/C++ applications Apr 14, 2020
@scoder
Copy link
Contributor Author

scoder commented Apr 14, 2020

I created a stub page in https://github.com/cython/cython/blob/master/docs/src/tutorial/embedding.rst – improvements welcome!

@brightening-eyes
Copy link

hi,
the distribution of the embedded application should be documented as well, like how python modules are searched, in order to copy them beside the compiled executable. something like wxpython for example.

@scoder
Copy link
Contributor Author

scoder commented Apr 24, 2020

Sure, investigation and PRs welcome.

@jokoon
Copy link

jokoon commented Jun 1, 2020

https://github.com/cython/cython/blob/master/Demos/embed/Makefile#L38

I think this embedded.c file got removed...

@da-woods
Copy link
Contributor

da-woods commented Jun 1, 2020

@jokoon No - it's created by Cythonizing the embedded.pyx file, 4 lines later:

embedded.c: embedded.pyx
@$(PYTHON) $(CYTHON) --embed embedded.pyx

@jokoon
Copy link

jokoon commented Jun 1, 2020

Oh ok.

I'm still unsure if that .msc can be used in visual studio.

I'm also confused if a cython module requires compilation each time it's edited, or if cython effectively still interprets a .py script at runtime though python runtime. I'm guessing cython acts as some kind of glue, but I'm not sure I understand.

The context being I want to use python a scripting language for a game, and I don't know if cython can help for this or not.

@TeamSpen210
Copy link
Contributor

Cython translates your code into a set of C functions which use Python's C-API to do all the operations. Cython doesn't really help in executing scripts at runtime, though you could use it to make the extension modules to provide access to your game in Python code. You'd really want to just use eval(), or the direct C-API function which does the same.

@scoder
Copy link
Contributor Author

scoder commented Jun 2, 2020 via email

@da-woods
Copy link
Contributor

da-woods commented Nov 26, 2022

FWIW I have a working example of how to call PyInit_* on a multi-phase init module therefore avoiding the need to use PyImport_AppendInittab. Essentially it's running through the multi-phase init steps manually. I'm not sure if we want to put it in any updated embedding docs, but it's posted below in case anyone wants to document it properly:

I suspect this comes under

Most importantly, DO NOT call the module init function instead of importing the module. This is not the right way to initialise an extension module. (It was always wrong but used to work before, but since Python 3.5, it is wrong and no longer works.)

though

#include <Python.h>

#include "embed_example.h"

int main() {
    int result = 1;
    PyObject *spec = NULL, *spec_globals = NULL, *mod = NULL;
    Py_Initialize();
    PyObject *maybe_mod = PyInit_embed_example();
    if (!maybe_mod) goto bad;
    if (Py_IS_TYPE(maybe_mod, &PyModuleDef_Type)) {
        // multi-phase init
        spec_globals = PyDict_New();
        if (!spec_globals) goto bad;
        PyObject *res = PyRun_String(
            "import importlib.machinery as im\n"
            // Note that Cython doesn't actually use the loader
            // so it can be None. It'd be better to
            // provide something more useful though.
            "spec = im.ModuleSpec('embed_example', None)\n",
            Py_file_input, spec_globals, spec_globals);
        Py_XDECREF(res); // don't use res whether or not it's set
        if (!res) goto bad;
        spec = PyDict_GetItemString(spec_globals, "spec");
        if (!spec) goto bad;               
        
        mod = PyModule_FromDefAndSpec(
            (PyModuleDef*)maybe_mod,
            spec);
        if (!mod) goto bad;
        int execRes = PyModule_ExecDef(mod, (PyModuleDef*)maybe_mod);
        if (execRes) goto bad;
    } else {
        mod = maybe_mod;
    }
    
    func(); // cdef public in the module being embedded.
    
    result = 0;
    if (0) {
        bad:
        PyErr_Print();
    }
    // The moduledef isn't an owned reference so doesn't get decref'd
    Py_XDECREF(mod);
    Py_XDECREF(spec);
    Py_XDECREF(spec_globals);
    Py_Finalize();
    return result;    
}

I remain sceptical of whether embedding Cython in C/C++ applications is actually useful (because people expect it to embed their module and all its dependencies), but multi-phase init is definitely something that people fight with, and additional ways to work with it are probably good.

@sohampirale
Copy link

Is this open?
Can I work on this?

@da-woods
Copy link
Contributor

da-woods commented Oct 5, 2024

@sohampirale yes I think the documentation here could still be improved. I couldn't tell you exactly what needs doing though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants