You’ve chosen the correct word - this is called embedding. I don’t know if Blender takes this exact approach (it could have evolved over 30 odd years). But it’s a lot more work for a new project to do it any other way:
If you want a lighter-weight one than CPython (good on you for avoiding unnecessary bloat for your users), I was under the impression a lot of games embed Lua.
In windows, It’s the same if you have the user install python or you use the embedded package. The embedded package does not have PIP, but you can add it yourself
PyConfig config;
PyConfig_InitPythonConfig(&config);
// set stuff like Python’s executable_path
Py_InitializeFromConfig
PyConfig_Clear(&config);
The time-consuming part is having two-way communication between your host application and Python. Anymore than a few functions, you might want to look into a library that helps automate bindings, I.e pybind11 or boost::python, I use the later. I used a decorator to mark functions to make the host app aware of a binding, I.e.
@command
def justdoit():
# get the application, document and modelspace
axApp = Ap.Application.acadApplication()
axDoc = axApp.activeDocument()
axModel = axDoc.modelSpace()
I’m interested in how you make out with macOS, I’ve been considering a port… someday