Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 6 additions & 53 deletions Modules/DelphiFMX/ModuleSpecs.pas
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,10 @@ TPythonLog = class
class procedure Log(const AText: string);
end;

TPythonEngineModuleAdapter = class(TPythonEngine)
private
{$IFDEF LINUX}
function CheckForHostSymbols(): boolean;
procedure LoadSymbols();
{$ENDIF}
public
procedure LoadDll();
end;
const
MODULE_DEFS_JSON_FILE = 'moduledefs.json';
MODULE_DEFS_LOG_FILE = 'moduledefs.log';
UNABLE_LOAD_MODULE_DEFS_MSG = 'Unable to load module definitions from %s file.';

implementation

Expand All @@ -56,10 +51,8 @@ class function TModulePaths.GetModuleDefsDir: string;
{ TPythonLoad }

class function TPythonLoad.GetModuleDefsJSONFilePath: string;
const
MODULE_DEFS_JSON = 'moduledefs.json';
begin
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_JSON, false);
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_JSON_FILE, false);
end;

class function TPythonLoad.TryLoadVerFromModuleDefs(const APythonEngine: TPythonEngine): boolean;
Expand Down Expand Up @@ -110,10 +103,8 @@ class function TPythonLoad.TryLoadVerFromModuleDefs(const APythonEngine: TPython
{ TPythonLog }

class function TPythonLog.GetModuleDefsLogFilePath: string;
const
MODULE_DEFS_LOG = 'moduledefs.log';
begin
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_LOG, false);
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_LOG_FILE, false);
end;

class procedure TPythonLog.Log(const AText: string);
Expand All @@ -135,42 +126,4 @@ class procedure TPythonLog.Log(const AText: string);
end;
end;

{ TPythonEngineModuleAdapter }

{$IFDEF LINUX}
function TPythonEngineModuleAdapter.CheckForHostSymbols: boolean;
type
TPy_IsInitialized = function: integer; cdecl;
begin
if not ModuleIsLib then
Exit(false);

var LPy_IsInitialized := GetProcAddress(0, 'Py_IsInitialized');
Result := Assigned(LPy_IsInitialized)
and (TPy_IsInitialized(LPy_IsInitialized)() <> 0);
end;

procedure TPythonEngineModuleAdapter.LoadSymbols;
begin
BeforeLoad();
FDLLHandle := 0;
AfterLoad();
end;
{$ENDIF}

procedure TPythonEngineModuleAdapter.LoadDll;
begin
//If host has symbols, we load symbols from host
{$IFDEF LINUX}
if CheckForHostSymbols() then begin
TPythonLog.Log('*** USING HOST SYMBOLS ***');
PythonHome := String.Empty;
ProgramName := String.Empty;
DllPath := String.Empty;
LoadSymbols();
end else
{$ENDIF}
inherited LoadDll();
end;

end.
1 change: 0 additions & 1 deletion Modules/DelphiFMX/PythonVersionIndex.inc

This file was deleted.

27 changes: 19 additions & 8 deletions Modules/DelphiFMX/uMain.pas
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,35 @@ implementation
uses
System.SysUtils, ModuleSpecs, WrapDelphi, WrapDelphiFMX;

type
TPythonEngine = class(PythonEngine.TPythonEngine)
end;

var
gEngine : TPythonEngineModuleAdapter;
gEngine : TPythonEngine;
gModule : TPythonModule;
gDelphiWrapper : TPyDelphiWrapper;

// This must match the pattern "PyInit_[ProjectName]"
// So if the project is named DelphiFMX then
// the function must be PyInit_DelphiFMX
function PyInit_DelphiFMX: PPyObject;
var
LMsg: string;
begin
try
gEngine := TPythonEngineModuleAdapter.Create(nil);
gEngine := TPythonEngine.Create(nil);
gEngine.AutoFinalize := False;
gEngine.UseLastKnownVersion := False;

if not TPythonLoad.TryLoadVerFromModuleDefs(gEngine) then
Exit(gEngine.ReturnNone);
if not TPythonLoad.TryLoadVerFromModuleDefs(gEngine)
and not gEngine.HasHostSymbols() then
begin
LMsg := Format(UNABLE_LOAD_MODULE_DEFS_MSG, [MODULE_DEFS_JSON_FILE]);
WriteLn('An error has occurred: ' + LMsg);
TPythonLog.Log(LMsg);
Exit(nil);
end;

gModule := TPythonModule.Create(nil);
gModule.Engine := gEngine;
Expand All @@ -38,15 +50,14 @@ function PyInit_DelphiFMX: PPyObject;
gDelphiWrapper.Engine := gEngine;
gDelphiWrapper.Module := gModule;

gEngine.LoadDll();
Result := gModule.Module;
gEngine.LoadDllInExtensionModule();
except
on E: Exception do begin
WriteLn('An error occurred: ' + E.Message);
WriteLn('An error has occurred: ' + E.Message);
TPythonLog.Log(E.Message);
Result := gEngine.ReturnNone;
end;
end;
Result := gModule.Module;
end;

initialization
Expand Down
5 changes: 3 additions & 2 deletions Modules/DelphiVCL/DelphiVCL.dpr
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ library DelphiVCL;
uses
SysUtils,
Classes,
uMain in 'uMain.pas';
uMain in 'uMain.pas',
ModuleSpecs in 'ModuleSpecs.pas';

{$I Definition.Inc}
{$I ..\..\Source\Definition.Inc}

exports
// This must match the pattern "PyInit_[ProjectName]"
Expand Down
129 changes: 129 additions & 0 deletions Modules/DelphiVCL/ModuleSpecs.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
unit ModuleSpecs;

interface

uses
PythonEngine;

type
TModulePaths = class
public
class function GetModuleDir(): string;
class function GetModuleDefsDir(): string;
end;

TPythonLoad = class
private
class function GetModuleDefsJSONFilePath(): string;
public
class function TryLoadVerFromModuleDefs(const APythonEngine: TPythonEngine): boolean;
end;

TPythonLog = class
private
class function GetModuleDefsLogFilePath(): string;
public
class procedure Log(const AText: string);
end;

const
MODULE_DEFS_JSON_FILE = 'moduledefs.json';
MODULE_DEFS_LOG_FILE = 'moduledefs.log';
UNABLE_LOAD_MODULE_DEFS_MSG = 'Unable to load module definitions from %s file.';

implementation

uses
System.SysUtils, System.IOUtils, System.JSON;

{ TModulePaths }

class function TModulePaths.GetModuleDir: string;
begin //Avoid invalid chars error on MacOS
Result := ExtractFilePath(GetModuleName(HInstance));
end;

class function TModulePaths.GetModuleDefsDir: string;
begin
Result := TDirectory.GetParent(ExcludeTrailingPathDelimiter(GetModuleDir()));
end;

{ TPythonLoad }

class function TPythonLoad.GetModuleDefsJSONFilePath: string;
begin
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_JSON_FILE, false);
end;

class function TPythonLoad.TryLoadVerFromModuleDefs(const APythonEngine: TPythonEngine): boolean;
begin
//Load Python using the moduledefs.json file - it cracks the single version limitation
var LFilePath := GetModuleDefsJSONFilePath();
if TFile.Exists(LFilePath) then begin
var LJson := TJSONObject.ParseJSONValue(TFile.ReadAllText(LFilePath));
if not Assigned(LJson) then
Exit(false);

var LPythonHome := String.Empty;
if LJson.TryGetValue<string>('python_home', LPythonHome) then begin
APythonEngine.PythonHome := LPythonHome;
end;

var LPythonBin := String.Empty;
if LJson.TryGetValue<string>('python_bin', LPythonBin) then begin
APythonEngine.ProgramName := LPythonBin;
end;

var LPythonLib := String.Empty;
if LJson.TryGetValue<string>('python_lib', LPythonLib) then begin
APythonEngine.DllPath := LPythonLib;
end;

var LPythonSharedLib := String.Empty;
if LJson.TryGetValue<string>('python_shared_lib', LPythonSharedLib) then begin
APythonEngine.DllName := LPythonSharedLib;
end;

var LPythonVer: string;
if LJson.TryGetValue<string>('python_ver', LPythonVer) then begin
for var I := Low(PYTHON_KNOWN_VERSIONS) to High(PYTHON_KNOWN_VERSIONS) do begin
if (PYTHON_KNOWN_VERSIONS[I].RegVersion = LPythonVer) then begin
APythonEngine.RegVersion := PYTHON_KNOWN_VERSIONS[I].RegVersion;
if LPythonSharedLib.IsEmpty() then
APythonEngine.DllName := PYTHON_KNOWN_VERSIONS[I].DllName;
TPythonLog.Log(Format('Module has been set to Python %s using the module defs file', [APythonEngine.RegVersion]));
Exit(true);
end;
end;
end;
end;
Result := false;
end;

{ TPythonLog }

class function TPythonLog.GetModuleDefsLogFilePath: string;
begin
Result := TPath.Combine(TModulePaths.GetModuleDefsDir(), MODULE_DEFS_LOG_FILE, false);
end;

class procedure TPythonLog.Log(const AText: string);
begin
try
TFile.AppendAllText(GetModuleDefsLogFilePath(),
DateTimeToStr(Now())
+ ': '
+ AText
+ sLineBreak);
except
on E: Exception do
TFile.AppendAllText(TPath.Combine(
GetCurrentDir(), 'dump.txt', false), E.Message
+ sLineBreak
+ 'while dumping: '
+ AText
+ sLineBreak);
end;
end;

end.
1 change: 0 additions & 1 deletion Modules/DelphiVCL/PythonVersionIndex.inc

This file was deleted.

Loading