Skip to content

Commit

Permalink
Don't hard-code Python dir.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas FitzRoy-Dale authored and Nicholas FitzRoy-Dale committed Aug 5, 2024
1 parent 88e4590 commit d541544
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 35 deletions.
33 changes: 10 additions & 23 deletions Windows/EmbedPython.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <Windows.h>
#include <string>

#define PY_SSIZE_T_CLEAN

Expand All @@ -18,9 +19,11 @@ FILE* logFile = nullptr;

struct NewPythonThreadStartupInfo
{
const wchar_t* pythonInstallDir;
const std::wstring pythonInstallDir;
void(*onStart)(void *);
void *param;

NewPythonThreadStartupInfo(const std::wstring pythonInstallDir, void(*onStart)(void *), void *param) : pythonInstallDir(pythonInstallDir), onStart(onStart), param(param) {}
};

static PyObject* PythonWriteImpl(PyObject* self, PyObject* args)
Expand Down Expand Up @@ -68,25 +71,13 @@ static DWORD WINAPI PythonThread(LPVOID lpParam)
PyConfig config;
PyConfig_InitIsolatedConfig(&config);

config.home = (wchar_t *)info->pythonInstallDir;
// TODO: Do we need this copy?
config.home = new wchar_t[info->pythonInstallDir.size() + 1];
wcscpy_s(config.home, info->pythonInstallDir.size() + 1, info->pythonInstallDir.c_str());

OutputDebugString(L"Initializing Python from config...\n");
OutputDebugString(config.home);

#if 0
size_t maxLen = wcslen(info->pythonInstallDir) + wcslen(pythonZipSuffix) + 2;
auto pythonZip = new wchar_t[maxLen];

swprintf_s(pythonZip, maxLen, L"%s\\%s", info->pythonInstallDir, pythonZipSuffix);
PyConfig_SetString(&config, &config.pythonpath_env, pythonZip);

delete[] pythonZip;

auto pythonExePath = new wchar_t[wcslen(info->pythonInstallDir) + wcslen(pythonExeSuffix) + 2];
swprintf_s(pythonExePath, wcslen(info->pythonInstallDir) + wcslen(pythonExeSuffix) + 2, L"%s\\%s", info->pythonInstallDir, pythonExeSuffix);
PyConfig_SetString(&config, &config.executable, pythonExePath);
#endif


Py_InitializeFromConfig(&config);

// Ensure that we have sys.stdout and sys.stderr objects. These may not exist if running from a GUI.
Expand Down Expand Up @@ -154,13 +145,9 @@ static DWORD WINAPI PythonThread(LPVOID lpParam)
}


void InitEmbedPython(const wchar_t *pythonInstallDir, void(*onStart)(void *), wchar_t *logFilename, void *param)
void InitEmbedPython(const std::wstring pythonInstallDir, void(*onStart)(void *), wchar_t *logFilename, void *param)
{
NewPythonThreadStartupInfo* info = new NewPythonThreadStartupInfo();

info->pythonInstallDir = pythonInstallDir;
info->onStart = onStart;
info->param = param;
NewPythonThreadStartupInfo* info = new NewPythonThreadStartupInfo(pythonInstallDir, onStart, param);

if (logFilename)
{
Expand Down
4 changes: 2 additions & 2 deletions Windows/EmbedPython.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#pragma once
#include <string>


void InitEmbedPython(const wchar_t* pythonInstallDir, void(*onStart)(void*), wchar_t* logFilename, void* param);
void InitEmbedPython(const std::wstring pythonInstallDir, void(*onStart)(void*), wchar_t* logFilename, void* param);
void StopEmbedPythonThread();
11 changes: 6 additions & 5 deletions Windows/Rime.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,15 @@
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(PythonLibs);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<DelayLoadDLLs>python3.dll;python312.dll</DelayLoadDLLs>
<AdditionalLibraryDirectories>$(PythonLibs);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
<ProjectReference />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
Expand All @@ -125,6 +124,8 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand Down
61 changes: 56 additions & 5 deletions Windows/RimePython.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#include <Windows.h>
#include <string>
#include <optional>
#include <shellapi.h>
#include "PathCch.h"



#define PY_SSIZE_T_CLEAN

Expand Down Expand Up @@ -80,19 +86,64 @@ static void OnPythonThreadStarted(void *data)
return;
}

PyRun_SimpleFileEx(fp, "launch.py", 1);
// We read launch.py and run it as a string so as to avoid passing FILE pointers from the launcher to the Python library.
// This is because the Nuget version of the Python library we are using includes only a release build. Building
// a debug build of the rest of the project results in FILE structures that are incompatible with the release build
// and cause weird crashes deep inside msvcrt.
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = new char[size + 1];
fread(buffer, 1, size, fp);
buffer[size] = 0;

fclose(fp);

PyRun_SimpleString(buffer);

delete[] buffer;
}

static std::optional<std::wstring> getPythonDir()
{
// Try to find the Python install dir as either below the executable or below the cwd.
// 1. Try below the executable.
wchar_t pythonInstallDir[MAX_PATH];

GetModuleFileNameW(NULL, pythonInstallDir, MAX_PATH);
PathCchRemoveFileSpec(pythonInstallDir, MAX_PATH);
wcscat_s(pythonInstallDir, MAX_PATH, L"\\python");

if (GetFileAttributesW(pythonInstallDir) == INVALID_FILE_ATTRIBUTES)
{
// 2. Try below the cwd.
GetCurrentDirectoryW(MAX_PATH, pythonInstallDir);
wcscat_s(pythonInstallDir, MAX_PATH, L"\\python");

if (GetFileAttributesW(pythonInstallDir) == INVALID_FILE_ATTRIBUTES)
{
OutputDebugString(L"Python not found\n");
return nullptr;
}
}

return std::wstring(pythonInstallDir);
}

const wchar_t *launchPySuffix = L"launch.py";

void *StartRimeServer(void(*OnServerStartedFn)(void*), void* data)
{
auto pythonInstallDir = L"C:\\Users\\wzddm\\source\\rime-release-test\\rime-windows\\python";
auto pythonInstallDir = getPythonDir();
if (!pythonInstallDir.has_value())
{
return nullptr;
}

size_t maxLen = wcslen(pythonInstallDir) + wcslen(launchPySuffix) + 2;
size_t maxLen = pythonInstallDir->size() + wcslen(launchPySuffix) + 2;
auto launchPy = new wchar_t[maxLen];

swprintf_s(launchPy, maxLen, L"%s\\%s", pythonInstallDir, launchPySuffix);
swprintf_s(launchPy, maxLen, L"%s\\%s", pythonInstallDir->c_str(), launchPySuffix);

OnRimeServerStartedStruct* onRimeServerStarted = new OnRimeServerStartedStruct();
onRimeServerStarted->OnServerStarted = OnServerStartedFn;
Expand All @@ -106,7 +157,7 @@ void *StartRimeServer(void(*OnServerStartedFn)(void*), void* data)
CreateDirectoryW(LogPath, NULL);
wcscat_s(LogPath, MAX_PATH, L"\\rime.log");

InitEmbedPython(pythonInstallDir, OnPythonThreadStarted, LogPath, onRimeServerStarted);
InitEmbedPython(pythonInstallDir.value(), OnPythonThreadStarted, LogPath, onRimeServerStarted);

return onRimeServerStarted;
}
Expand Down

0 comments on commit d541544

Please sign in to comment.