* pas2jni: Detect the default units path.

git-svn-id: trunk@32084 -
This commit is contained in:
yury 2015-10-17 20:36:29 +00:00
parent ab4c8623ec
commit 9193954d1c

View File

@ -36,9 +36,13 @@ type
TPPUParser = class TPPUParser = class
private private
FOnCheckItem: TOnCheckItem; FOnCheckItem: TOnCheckItem;
FDefaultSearchPathAdded: boolean;
function FindUnit(const AName: string): string; function FindUnit(const AName: string): string;
function ReadUnit(const AName: string): string; function ReadUnit(const AName: string): string;
function InternalParse(const AUnitName: string): TUnitDef; function InternalParse(const AUnitName: string): TUnitDef;
procedure AddSearchPath(const ASearchPath: string);
function ReadProcessOutput(const AExeName, AParams: string; var AOutput, AError: string): integer;
procedure AddDefaultSearchPath(const ACPU, AOS: string);
public public
SearchPath: TStringList; SearchPath: TStringList;
Units: TDef; Units: TDef;
@ -112,31 +116,9 @@ end;
{ TPPUParser } { TPPUParser }
constructor TPPUParser.Create(const ASearchPath: string); constructor TPPUParser.Create(const ASearchPath: string);
var
i, j: integer;
s, d: string;
sr: TSearchRec;
begin begin
SearchPath:=TStringList.Create; SearchPath:=TStringList.Create;
SearchPath.Delimiter:=';'; AddSearchPath(ASearchPath);
SearchPath.DelimitedText:=ASearchPath;
i:=0;
while i < SearchPath.Count do begin
s:=SearchPath[i];
if (Pos('*', s) > 0) or (Pos('?', s) > 0) then begin
d:=ExtractFilePath(s);
j:=FindFirst(s, faDirectory, sr);
while j = 0 do begin
if (sr.Name <> '.') and (sr.Name <> '..') then
SearchPath.Add(d + sr.Name);
j:=FindNext(sr);
end;
FindClose(sr);
SearchPath.Delete(i);
end
else
Inc(i);
end;
Units:=TDef.Create(nil, dtNone); Units:=TDef.Create(nil, dtNone);
end; end;
@ -171,68 +153,31 @@ begin
end; end;
function TPPUParser.ReadUnit(const AName: string): string; function TPPUParser.ReadUnit(const AName: string): string;
procedure _ReadOutput(o: TInputPipeStream; var s: string);
var
i, j: integer;
begin
with o do
while NumBytesAvailable > 0 do begin
i:=NumBytesAvailable;
j:=Length(s);
SetLength(s, j + i);
ReadBuffer(s[j + 1], i);
end;
end;
var var
p: TProcess;
s, un, err: ansistring; s, un, err: ansistring;
ec: integer; ec: integer;
begin begin
un:=FindUnit(AName); un:=FindUnit(AName);
p:=TProcess.Create(nil); if ppudumpprog = '' then begin
try ppudumpprog:='ppudump';
if ppudumpprog = '' then begin // Check for ppudump in the same folder as pas2jni
ppudumpprog:='ppudump'; s:=ExtractFilePath(ParamStr(0));
// Check for ppudump in the same folder as pas2jni if s <> '' then begin
s:=ExtractFilePath(ParamStr(0)); s:=s + ppudumpprog + ExtractFileExt(ParamStr(0));
if s <> '' then begin if FileExists(s) then
s:=s + ppudumpprog + ExtractFileExt(ParamStr(0)); ppudumpprog:=s;
if FileExists(s) then
ppudumpprog:=s;
end;
end; end;
p.Executable:=ppudumpprog; end;
p.Parameters.Add('-Fj'); ec:=ReadProcessOutput(ppudumpprog, '-Fj' + LineEnding + un, s, err);
p.Parameters.Add(un); if Copy(s, 1, 1) <> '[' then begin
p.Options:=[poUsePipes, poNoConsole]; ec:=-1;
p.ShowWindow:=swoHIDE; err:='Output of ppudump is not in JSON format.' + LineEnding + 'Probably old version of ppudump has been used.';
p.StartupOptions:=[suoUseShowWindow]; end;
try if ec <> 0 then begin
p.Execute; if err = '' then
except if Length(s) < 300 then
raise Exception.CreateFmt('Unable to run "%s".'+LineEnding+'%s', [p.Executable, Exception(ExceptObject).Message]); err:=s;
end; raise Exception.CreateFmt('Error reading contents of unit "%s" using "%s".'+LineEnding+'Error code: %d'+LineEnding+'%s', [un, ppudumpprog, ec, err]);
s:='';
err:='';
repeat
_ReadOutput(p.Output, s);
_ReadOutput(p.Stderr, err);
until not p.Running and (p.Output.NumBytesAvailable = 0) and (p.Stderr.NumBytesAvailable = 0);
ec:=p.ExitStatus;
if Copy(s, 1, 1) <> '[' then begin
ec:=-1;
err:='Output of ppudump is not in JSON format.' + LineEnding + 'Probably old version of ppudump has been used.';
end;
if ec <> 0 then begin
if err = '' then
if Length(s) < 300 then
err:=s;
raise Exception.CreateFmt('Error reading contents of unit "%s" using "%s".'+LineEnding+'Error code: %d'+LineEnding+'%s', [un, ppudumpprog, ec, err]);
end;
finally
p.Free;
end; end;
Result:=s; Result:=s;
{$ifopt D+} {$ifopt D+}
@ -602,8 +547,16 @@ begin
Result.PPUVer:=junit.Integers['Version']; Result.PPUVer:=junit.Integers['Version'];
Result.CPU:=junit.Strings['TargetCPU']; Result.CPU:=junit.Strings['TargetCPU'];
Result.OS:=junit.Strings['TargetOS']; Result.OS:=junit.Strings['TargetOS'];
j:=Length(Result.CPU);
if AnsiLowerCase(Copy(Result.OS, Length(Result.OS) - j, j + 1)) = AnsiLowerCase('-' + Result.CPU) then
Result.OS:=Copy(Result.OS, 1, Length(Result.OS) - j - 1);
Result.IntfCRC:=junit.Strings['InterfaceCRC']; Result.IntfCRC:=junit.Strings['InterfaceCRC'];
if not FDefaultSearchPathAdded then begin
FDefaultSearchPathAdded:=True;
AddDefaultSearchPath(AnsiLowerCase(Result.CPU), AnsiLowerCase(Result.OS));
end;
if junit.Find('Units') <> nil then if junit.Find('Units') <> nil then
with junit.Arrays['Units'] do begin with junit.Arrays['Units'] do begin
SetLength(deref, Count); SetLength(deref, Count);
@ -641,5 +594,121 @@ begin
end; end;
end; end;
procedure TPPUParser.AddSearchPath(const ASearchPath: string);
var
i, j: integer;
s, d: string;
sr: TSearchRec;
sl: TStringList;
begin
sl:=TStringList.Create;
try
sl.Delimiter:=';';
sl.DelimitedText:=ASearchPath;
i:=0;
while i < sl.Count do begin
s:=sl[i];
if (Pos('*', s) > 0) or (Pos('?', s) > 0) then begin
d:=ExtractFilePath(s);
j:=FindFirst(s, faDirectory, sr);
while j = 0 do begin
if (sr.Name <> '.') and (sr.Name <> '..') then
sl.Add(d + sr.Name);
j:=FindNext(sr);
end;
FindClose(sr);
sl.Delete(i);
end
else
Inc(i);
end;
SearchPath.AddStrings(sl);
finally
sl.Free;
end;
end;
function TPPUParser.ReadProcessOutput(const AExeName, AParams: string; var AOutput, AError: string): integer;
procedure _ReadOutput(o: TInputPipeStream; var s: string);
var
i, j: integer;
begin
with o do
while NumBytesAvailable > 0 do begin
i:=NumBytesAvailable;
j:=Length(s);
SetLength(s, j + i);
ReadBuffer(s[j + 1], i);
end;
end;
var
p: TProcess;
begin
AOutput:='';
AError:='';
p:=TProcess.Create(nil);
try
p.Executable:=AExeName;
p.Parameters.Text:=AParams;
p.Options:=[poUsePipes, poNoConsole];
p.ShowWindow:=swoHIDE;
p.StartupOptions:=[suoUseShowWindow];
try
p.Execute;
except
raise Exception.CreateFmt('Unable to run "%s".'+LineEnding+'%s', [p.Executable, Exception(ExceptObject).Message]);
end;
repeat
_ReadOutput(p.Output, AOutput);
_ReadOutput(p.Stderr, AError);
until not p.Running and (p.Output.NumBytesAvailable = 0) and (p.Stderr.NumBytesAvailable = 0);
Result:=p.ExitStatus;
finally
p.Free;
end;
end;
procedure TPPUParser.AddDefaultSearchPath(const ACPU, AOS: string);
var
fpc, s, e: string;
sl: TStringList;
i, j: integer;
begin
try
fpc:=ExtractFilePath(ppudumpprog) + 'fpc' + ExtractFileExt(ppudumpprog);
if not FileExists(fpc) then
exit;
// Find the compiler binary
if ReadProcessOutput(fpc, '-P' + ACPU + LineEnding + '-T' + AOS + LineEnding + '-PB', s, e) <> 0 then
exit;
fpc:=Trim(s);
// Get units path from the compiler output
ReadProcessOutput(fpc, '-P' + ACPU + LineEnding + '-T' + AOS + LineEnding + '-vt' + LineEnding + '.', s, e);
sl:=TStringList.Create;
try
sl.Text:=s;
s:='';
for i:=0 to sl.Count - 1 do begin
s:=sl[i];
j:=Pos(':', s);
if j > 0 then begin
s:=Trim(Copy(s, j + 1, MaxInt));
s:=ExcludeTrailingPathDelimiter(s);
if (Copy(s, Length(s) - 3, 4) = DirectorySeparator + 'rtl') and DirectoryExists(s) then begin
AddSearchPath(ExtractFilePath(s) + '*');
exit;
end;
end;
end;
finally
sl.Free;
end;
except
// Ignore exceptions
end;
end;
end. end.