Embed Python2 and Python3 interpreters, choose which one to use at runtime

290 views Asked by At

Is there a good way to embed both a Python2 and a Python3 interpreter into a C program and then running either one or the other with the decision occurring at runtime?

Here's an example attempt:

Makefile:

all: main


main: main.c librun_in_py2.so librun_in_py3.so
    g++ main.c -lrun_in_py2 -lrun_in_py3 -L. -Wl,-rpath -Wl,$$ORIGIN -o main

librun_in_py2.so: run_in_py2.c
    g++ $$(python2.7-config --cflags --ldflags) -shared -fPIC $< -o $@

librun_in_py3.so: run_in_py3.c
    g++ $$(python3.4-config --cflags --ldflags) -shared -fPIC $< -o $@

clean:
    @-rm main *.so

main.c

void run_in_py2(const char* const str);
void run_in_py3(const char* const str);

static const char str2[] = "from time import time,ctime\n"
                           "import sys\n"
                           "print sys.version_info\n"
                           "print 'Today is',ctime(time())\n";

static const char str3[] = "from time import time,ctime\n"
                           "import sys\n"
                           "print(sys.version_info)\n"
                           "print('Today is', ctime(time()))\n";
int main(int argc, char* [])
{
    if (argc == 2)
        run_in_py2(str2);
    else
        run_in_py3(str3);
}

run_in_py2.c

#include <Python.h>

void run_in_py2(const char* const str)
{
    Py_Initialize();
    PyRun_SimpleString(str);
    Py_Finalize();
}

run_in_py3.c:

#include <Python.h>

void run_in_py3(const char* const str)
{
   Py_Initialize();
    PyRun_SimpleString(str);
    Py_Finalize();
}

Because of the order of library linking the result is always the same:

$ ./main
sys.version_info(major=2, minor=7, micro=9, releaselevel='final', serial=0)
('Today is', 'Thu Jun  4 10:59:29 2015')

Since the names are the same it looks like the linker resolves everything with the Python 2 interpreter. Is there some way to isolate the names or to encourage the linker to be lazier in resolving them? If possible, it'd be ideal to get the linker to confirm that all names can be resolved and but put off symbol resolution until the appropriate linker can be chosen.

A highly related question asks about running two independent embedded interpreters at the same time:

Multiple independent embedded Python Interpreters on multiple operating system threads invoked from C/C++ program

The suggestion there is to use two separate processes but I suspect there's a simpler answer to this question.

The reason behind the question is that I thought I understood from a conversation with someone way back when that there was a program that did this. And now I'm just curious about how it would be done.

0

There are 0 answers