I've been using a custom build as a replacement for virtualenv for a while now, and it's brillant. It takes longer to build, but it actually works, and it never screws up.
Part of this in a simple python wrapper that adds some specific folders to the library path, which I've found very useful. The code for it is trivial:
#include <stdio.h>
#include <n/text/StringUtils.h>
#include <Python.h>
int main(int argc, char *argv[]) {
/* Setup */
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
/* Add local path */
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
/* Custom path */
char *cwd = nrealpath(argv[0]);
char *libdir = nstrpath(cwd, "python_lib", NULL);
PyList_Append(path, PyString_FromString(libdir));
free(cwd);
free(libdir);
/* Run the 'main' module */
int rtn = Py_Main(argc, argv); // <-- Notice the command line arguments.
Py_Finalize();
return rtn;
}
So, moving to python3 is good right? So...
I dutifully replaced the call to PyString_FromString() with PyByte_FromString() and tried to recompile, but it raises errors:
/Users/doug/env/src/main.c:8:21: error: incompatible pointer types passing 'char *' to parameter of type 'wchar_t *' (aka 'int *')
[-Werror,-Wincompatible-pointer-types]
Py_SetProgramName(argv[0]);
^~~~~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/pythonrun.h:25:45: note: passing argument to parameter here
PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
^
/Users/doug/env/src/main.c:10:23: error: incompatible pointer types passing 'char **' to parameter of type 'wchar_t **' (aka 'int **')
[-Werror,-Wincompatible-pointer-types]
PySys_SetArgv(argc, argv);
^~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/sysmodule.h:12:47: note: passing argument to parameter here
PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
^
/Users/doug/env/src/main.c:24:27: error: incompatible pointer types passing 'char **' to parameter of type 'wchar_t **' (aka 'int **')
[-Werror,-Wincompatible-pointer-types]
int rtn = Py_Main(argc, argv);
^~~~
/Users/doug/projects/py-sdl2/py3/include/python3.3m/pythonrun.h:148:45: note: passing argument to parameter 'argv' here
PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
^
3 errors generated.
make[2]: *** [CMakeFiles/python.dir/src/main.c.o] Error 1
make[1]: *** [CMakeFiles/python.dir/all] Error 2
make: *** [all] Error 2
As you can see from the error, wchar_t is used instead of char *.
How are you supposed to use this api?
I see there are a few examples of doing this, for example: http://svn.python.org/projects/python/tags/r32rc2/Python/frozenmain.c
seriously?
My 29 line program has to become a 110 line monster full of #ifdefs?
Am I misunderstanding, or has the python3 c api really become this ridiculously difficult to use?
Surely I'm missing some obvious convenience function which does this for you, in a simple, portable and cross platform way?
The Python/C API allows for compiled pieces of code to be called from Python programs or executed within the CPython interpreter. This process of producing compiled code for use by CPython is generally known as "extending" Python and the compiled pieces of code to be used are known as "extension modules".
Command line utilities are tools that you can run on the command line of a computer. We most often see these on Linux and MacOS computers using the 'bash' shell, but Windows users have options like CMD, git-bash and powershell too. These tools allow you to instruct the computer to do things using text alone.
The official recommended way of converting from char
to wchar_t
is by using Py_DecodeLocale
. Like this:
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
Py_SetProgramName(program);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With