Skip to content

Commit 6990825

Browse files
committed
Creating and unsing symlinks for Python executables on Android
Former-commit-id: 3e5cdf8fea3d0a4fa78e877cf20b48a3bf827fd5 [formerly 7b538941ba6a3768ec2f62a6e0993fcd205e9928] [formerly 8d63c08ce847897597064600a506fa98d8c5d38f [formerly 3f135bfb32c433a2c7234eb0f3f26bd05ccf3afe]] [formerly 5495cfc6eb2a8013e52c99167ccea9206164b123 [formerly 2e47991fac5414c85d79d7865ecbabaead0360f1] [formerly 59c963dc69211fc282a75be9f6540f7973661d1a [formerly 6e3de818e0c534e763bf1dc389593d66c961edc3]]] Former-commit-id: 88492d8e226f4bb7eb039637d6178751ff476a21 [formerly 9db9ceb264968b137f7ae7ccf0768d3ce4fc1460] [formerly 0226825ef52e48d3b07eafff70fd1f90af16273d [formerly 2025c4ef47c6144d304c1617cd0a8494f1d2dcf9]] Former-commit-id: 5dae70aeb04a1cad7bfcd8410a17c5f278f84959 [formerly a4131db8ee53a605bb4776272e00e83e4d84c3bf] Former-commit-id: d4516d50c4f62c9ffa59a445d8f78a1dbf4155e7 Former-commit-id: b0b75a9
1 parent e2720c6 commit 6990825

1 file changed

Lines changed: 63 additions & 26 deletions

File tree

src/Embeddable/PyEnvironment.Embeddable.pas

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ TPyCustomEmbeddableDistribution = class(TPyDistribution)
6868
{$IFDEF POSIX}
6969
function FileIsExecutable(const AFilePath: string): boolean;
7070
{$ENDIF POSIX}
71+
procedure CreateSymlink(const ASymlink, ATarget: string);
7172
protected
7273
function EnvironmentExists(): boolean;
7374
/// <summary>
@@ -79,6 +80,7 @@ TPyCustomEmbeddableDistribution = class(TPyDistribution)
7980
/// An embeddable distribution will be used as an "image".
8081
/// </summary>
8182
procedure CreateEnvironment(const ACancelation: ICancelation); virtual;
83+
procedure CreateSymLinks(); virtual;
8284
procedure LoadSettings(const ACancelation: ICancelation); virtual;
8385
protected
8486
function GetEnvironmentPath(): string;
@@ -167,11 +169,12 @@ implementation
167169
System.IOUtils,
168170
System.Character,
169171
System.StrUtils,
172+
System.RegularExpressions,
170173
PyTools.ExecCmd,
171174
PyEnvironment.Exception,
172175
PyEnvironment.Path
173176
{$IFDEF POSIX}
174-
, Posix.SysStat, Posix.Stdlib, Posix.String_, Posix.Errno
177+
, Posix.SysStat, Posix.Stdlib, Posix.String_, Posix.Errno, Posix.Unistd
175178
{$ENDIF}
176179
;
177180

@@ -207,6 +210,52 @@ procedure TPyCustomEmbeddableDistribution.CreateEnvironment(const ACancelation:
207210
end;
208211
end;
209212

213+
procedure TPyCustomEmbeddableDistribution.CreateSymlink(const ASymlink,
214+
ATarget: string);
215+
var
216+
LExistingTarget: string;
217+
begin
218+
LExistingTarget := String.Empty;
219+
if TFile.Exists(ATarget) then begin
220+
//There is a bug with TFile.Exists and TFile.GetSymLinkTarget for Android
221+
//So we recreate it every time
222+
DeleteFile(ASymlink);
223+
224+
if not TFile.CreateSymLink(ASymlink, ATarget) then
225+
raise ESymlinkFailed.CreateFmt('Failed to create the symlink: %s -> %s', [ASymlink, ATarget]);
226+
end;
227+
end;
228+
229+
procedure TPyCustomEmbeddableDistribution.CreateSymLinks;
230+
var
231+
LTargetInterpreter: string;
232+
LTargetLauncher: string;
233+
LSymlinkInterpreter: string;
234+
LSynlinkLauncher: string;
235+
begin
236+
{$IFNDEF ANDROID}
237+
Exit;
238+
{$ENDIF ANDROID}
239+
//Real file names
240+
LTargetInterpreter := TPath.Combine(
241+
TPath.GetLibraryPath(),
242+
String.Format('libpython%s.so', [PythonVersion]));
243+
LTargetLauncher := TPath.Combine(
244+
TPath.GetLibraryPath(),
245+
String.Format('libpythonlauncher%s.so', [PythonVersion]));
246+
//Symlink names
247+
LSymlinkInterpreter := TPath.Combine(
248+
TPath.Combine(GetEnvironmentPath(), 'lib'),
249+
String.Format('libpython%s.so', [PythonVersion]));
250+
LSynlinkLauncher := TPath.Combine(
251+
TPath.Combine(GetEnvironmentPath(), 'bin'),
252+
String.Format('python%s', [PythonVersion]));
253+
//Creates the interpreter symlink
254+
CreateSymlink(LSymlinkInterpreter, LTargetInterpreter);
255+
//Creates the launcher symlink
256+
CreateSymlink(LSynlinkLauncher, LTargetLauncher);
257+
end;
258+
210259
procedure TPyCustomEmbeddableDistribution.DoZipProgressEvt(Sender: TObject; FileName: string;
211260
Header: TZipHeader; Position: Int64);
212261
begin
@@ -247,8 +296,10 @@ function TPyCustomEmbeddableDistribution.FindExecutable: string;
247296
begin
248297
Result := TDirectory.GetFiles(APath, 'python*', TSearchOption.soTopDirectoryOnly,
249298
function(const Path: string; const SearchRec: TSearchRec): boolean
299+
var
300+
LFileName: string;
250301
begin
251-
var LFileName: string := SearchRec.Name;
302+
LFileName := SearchRec.Name;
252303
if LFileName.EndsWith('m') then //3.7 and lower contain a "m" as sufix.
253304
LFileName := LFileName.Remove(Length(LFileName) - 1);
254305

@@ -274,14 +325,6 @@ function TPyCustomEmbeddableDistribution.FindExecutable: string;
274325
Exit(Result)
275326
else
276327
Exit(String.Empty);
277-
{$ELSEIF DEFINED(ANDROID)}
278-
//Let's try it in the library path first
279-
//we should place it in the library path in Android
280-
Result := TPath.GetLibraryPath();
281-
LFiles := DoSearch(Result);
282-
if LFiles <> nil then
283-
Exit(LFiles[Low(LFiles)]);
284-
Result := TPath.Combine(GetEnvironmentPath(), 'bin');
285328
{$ELSE}
286329
Result := TPath.Combine(GetEnvironmentPath(), 'bin');
287330
{$ENDIF}
@@ -303,14 +346,14 @@ function TPyCustomEmbeddableDistribution.FindSharedLibrary: string;
303346
LSearch: string;
304347
begin
305348
LFile := TPath.Combine(APath, ALibName);
306-
if not TFile.Exists(LFile) then begin
307-
LSearch := ALibName.Replace(TPath.GetExtension(ALibName), '') + '*' + TPath.GetExtension(ALibName);
308-
Result := TDirectory.GetFiles(
309-
APath,
310-
LSearch, //Python <= 3.7 might contain a "m" as sufix.
311-
TSearchOption.soTopDirectoryOnly);
312-
end else
313-
Result := [LFile];
349+
if TFile.Exists(LFile) then
350+
Exit(TArray<string>.Create(LFile));
351+
352+
LSearch := ALibName.Replace(TPath.GetExtension(ALibName), '') + '*' + TPath.GetExtension(ALibName);
353+
Result := TDirectory.GetFiles(
354+
APath,
355+
LSearch, //Python <= 3.7 might contain a "m" as sufix.
356+
TSearchOption.soTopDirectoryOnly);
314357
end;
315358

316359
var
@@ -327,14 +370,6 @@ function TPyCustomEmbeddableDistribution.FindSharedLibrary: string;
327370

328371
{$IFDEF MSWINDOWS}
329372
LPath := GetEnvironmentPath();
330-
{$ELSEIF DEFINED(ANDROID)}
331-
//Let's try it in the library path first - we should place it in the library path in Android
332-
LPath := TPath.GetLibraryPath();
333-
LFiles := DoSearch(LLibName, LPath);
334-
if LFiles <> nil then
335-
Exit(LFiles[Low(LFiles)]);
336-
//Try to find it in the environment folder
337-
LPath := TPath.Combine(GetEnvironmentPath(), 'lib');
338373
{$ELSEIF DEFINED(MACOS)}
339374
//Let's try it in the library path first
340375
LPath := TPyEnvironmentPath.ResolvePath(TPyEnvironmentPath.ENVIRONMENT_PATH);
@@ -385,6 +420,8 @@ function TPyCustomEmbeddableDistribution.Setup(const ACancelation: ICancelation)
385420
CreateEnvironment(ACancelation);
386421
end;
387422

423+
CreateSymLinks();
424+
388425
LoadSettings(ACancelation);
389426

390427
Result := true;

0 commit comments

Comments
 (0)