@@ -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 ;
208211end ;
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+
210259procedure TPyCustomEmbeddableDistribution.DoZipProgressEvt (Sender: TObject; FileName: string;
211260 Header: TZipHeader; Position: Int64);
212261begin
@@ -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
316359var
@@ -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