The operating system is Windows 10.
I downloaded the installer for Python 3.12.3 from https://www.python.org/downloads/.
During custom installation, I chose a install location: D:ProgramsPythonPython312
After installation, I confirmed that the D:ProgramsPythonPython312
directory exists, and that python.exe
is in it. No Windows environment variables were changed by the installation.
I did not establish any Python virtual environments.
In Visual Studio 2017, I created a new C++ Windows console application project, named runpy
. I changed the project settings so that it can find headers and libraries for the Python version I installed. The following changes are sufficient for the app to compile and link.
- In C/C++ > General > Additional Include Directories, added:
D:ProgramsPythonPython312include
- In Linker > General > Additional Library Directories, added:
D:ProgramsPythonPython312libs
Also, I manually copied python312_d.dll
to the output directory of the app. i.e., from D:ProgramsPythonPython312
to D:workrunpyx64Debug
. I will make that a postbuild step in the project later. That is sufficient for the app to run.
I attempted to embed Python in the C++ app with the following code.
// Precompiled header includes other stuff not relevant to embedding Python.
#include "stdafx.h"
// Standard stuff
#include <iostream> // std::cout
// Python
#include <Python.h>
void on_PyStatusException( PyStatus const & status )
{
std::cout << "PyStatus.func: " << ( status.func ? status.func : "n/a" ) << std::endl;
std::cout << "PyStatus.err_msg: " << ( status.err_msg ? status.err_msg : "n/a" ) << std::endl;
Py_ExitStatusException( status );
}
int main( int argc, char * argv[] )
{
printf( "Howdy this is a C++ app that embeds Pythonn");
PyStatus status;
PyConfig config;
//------------------------------
// Sets config.isolated to 1, and other stuff.
// But not sufficient by itself.
PyConfig_InitIsolatedConfig( &config );
// Unknown if important. Returns a successful status.
status = PyConfig_Read( &config );
// Provide an explicit path to the Python executable. Returns a successful status.
wchar_t * pythonPath = L"D:\Programs\Python\Python312\python.exe";
status = PyConfig_SetString( &config, &config.executable, pythonPath );
//------------------------------
// Does *not* work. Returns a failure status.
status = Py_InitializeFromConfig( &config );
if ( PyStatus_Exception( status ) )
{
on_PyStatusException( status );
}
//------------------------------
// Cleanup.
PyConfig_Clear( &config );
return 0;
}
However, Py_InitializeFromConfig()
fails with the following output.
Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'python'
isolated = 1
environment = 0
user site = 0
safe_path = 1
import site = 1
is in build tree = 0
stdlib dir = 'D:workrunpyLib'
sys._base_executable = 'D:\Programs\Python\Python312\python.exe'
sys.base_prefix = 'D:\work\runpy'
sys.base_exec_prefix = 'D:\work\runpy'
sys.platlibdir = 'DLLs'
sys.executable = 'D:\Programs\Python\Python312\python.exe'
sys.prefix = 'D:\work\runpy'
sys.exec_prefix = 'D:\work\runpy'
sys.path = [
'D:\work\runpy\x64\Debug\python312_d.zip',
'D:\work\runpy',
'D:\work\runpy\Lib',
'D:\work\runpy\x64\Debug',
]
PyStatus.func: init_fs_encoding
PyStatus.err_msg: failed to get the Python codec of the filesystem encoding
Several of the Python path configuration settings in the above output are clearly wrong. They point to the directory of the runpy
app, instead of to Python stuff. What other PyConfig
properties should I establish so that Py_InitializeFromConfig()
will succeed?
I have been following examples in other StackOverflow posts and the https://docs.python.org documentation, but I cannot find the correct combination.
2
Answers
As @AhmedAEK suggested, setting
PyConfig.home
instead ofPyConfig.executable
was the essential thing so that the subsequent call ofPy_InitializeFromConfig()
succeeds. Because I am using a later version of Python, I callPyConfig_SetString( &config, &config.home, value )
instead ofPy_SetPythonHome()
.The following is my latest successful attempt to embed Python in the C++ app.
The following is the output.
Python needs to know where its standard library is located, you need to call Py_SetPythonHome, passing the path of the folder that contains
python.exe
, before callingPy_InitializeFromConfig
.Actually
python.exe
itself is not needed, only theLib
andDLLs
folders are needed for an embedded interpreter.To make a smaller package, you can zip compress the entire
Lib
folder, as python can load.py
files from.zip
files, but the.pyd
files inDLLs
folder needs to be shipped along with your executable.if you set
config.site_import = 0;
you will disable the loading of thesite
package, which makes some of the libraries obsolete and can be removed for even smaller package, so long as you aren’t using anything you are deleting, which is not recommended unless you know exactly what you are doing.