iphonelazext: support of launching sim with hijacking the app output to the extension log dialog
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4412 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
bb0a3ea92c
commit
861501fa99
@ -21,11 +21,12 @@ interface
|
|||||||
uses
|
uses
|
||||||
Unix, BaseUnix, process,
|
Unix, BaseUnix, process,
|
||||||
Classes, SysUtils, contnrs,
|
Classes, SysUtils, contnrs,
|
||||||
Graphics, Controls, Forms, Dialogs, FileUtil,
|
Graphics, Controls, Forms, Dialogs, LazFileUtils,
|
||||||
{Lazarus Interface}
|
{Lazarus Interface}
|
||||||
LazIDEIntf, MenuIntf, ProjectIntf, IDEOptionsIntf, IDEMsgIntf,
|
LazIDEIntf, MenuIntf, ProjectIntf, IDEOptionsIntf, IDEMsgIntf
|
||||||
|
,IDEExternToolIntf
|
||||||
|
|
||||||
project_iphone_options, xcodetemplate,
|
,project_iphone_options, xcodetemplate, iphonelog_form,
|
||||||
|
|
||||||
iPhoneExtOptions, iPhoneExtStr, iPhoneBundle, lazfilesutils, iphonesimctrl;
|
iPhoneExtOptions, iPhoneExtStr, iPhoneBundle, lazfilesutils, iphonesimctrl;
|
||||||
|
|
||||||
@ -33,6 +34,12 @@ procedure Register;
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
procedure IDEMsg(const msg: string);
|
||||||
|
begin
|
||||||
|
IDEMessagesWindow.AddCustomMessage(mluProgress, msg);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
{ TiPhoneExtension }
|
{ TiPhoneExtension }
|
||||||
|
|
||||||
@ -47,10 +54,17 @@ type
|
|||||||
function ProjectBuilding(Sender: TObject): TModalResult;
|
function ProjectBuilding(Sender: TObject): TModalResult;
|
||||||
function ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult;
|
function ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult;
|
||||||
//procedure OnProjOptionsChanged(Sender: TObject; Restore: Boolean);
|
//procedure OnProjOptionsChanged(Sender: TObject; Restore: Boolean);
|
||||||
|
|
||||||
|
function GetXcodeProjDirName: string;
|
||||||
public
|
public
|
||||||
|
SimPID : Integer;
|
||||||
|
SimLogger : TPTYReader;
|
||||||
constructor Create;
|
constructor Create;
|
||||||
procedure UpdateXcode(Sender: TObject);
|
procedure UpdateXcode(Sender: TObject);
|
||||||
procedure SimRun(Sender: TObject);
|
procedure SimRun(Sender: TObject);
|
||||||
|
procedure SimTerminate(Sender: TObject);
|
||||||
|
procedure CloseProc;
|
||||||
|
procedure OnBytesRead(Sender: TObject; const buf: string);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -88,10 +102,10 @@ end;
|
|||||||
|
|
||||||
procedure TiPhoneExtension.FillBunldeInfo(forSimulator: Boolean; var info: TiPhoneBundleInfo);
|
procedure TiPhoneExtension.FillBunldeInfo(forSimulator: Boolean; var info: TiPhoneBundleInfo);
|
||||||
begin
|
begin
|
||||||
Info.AppID:=ProjOptions.AppID;
|
Info.AppID:=UTF8Decode(ProjOptions.AppID);
|
||||||
Info.DisplayName:=LazarusIDE.ActiveProject.Title;
|
Info.DisplayName:=UTF8Decode(LazarusIDE.ActiveProject.Title);
|
||||||
Info.iPlatform:=EnvOptions.GetSDKName(ProjOptions.SDK, forSimulator);
|
Info.iPlatform:=UTF8Decode(EnvOptions.GetSDKName(ProjOptions.SDK, forSimulator));
|
||||||
Info.SDKVersion:=ProjOptions.SDK;
|
Info.SDKVersion:=UTF8Decode(ProjOptions.SDK);
|
||||||
Info.MainNib:=UTF8Decode(ProjOptions.MainNib);
|
Info.MainNib:=UTF8Decode(ProjOptions.MainNib);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -111,7 +125,7 @@ var
|
|||||||
i : Integer;
|
i : Integer;
|
||||||
s : string;
|
s : string;
|
||||||
begin
|
begin
|
||||||
Space:=ProjOptions.SpaceName; // LazarusIDE.ActiveProject.CustomData.;
|
Space:=UTF8Decode(ProjOptions.SpaceName); // LazarusIDE.ActiveProject.CustomData.;
|
||||||
|
|
||||||
bundleName:=ExtractFileName(LazarusIDE.ActiveProject.ProjectInfoFile);
|
bundleName:=ExtractFileName(LazarusIDE.ActiveProject.ProjectInfoFile);
|
||||||
bundleName:=Copy(bundleName, 1, length(bundleName)-length(ExtractFileExt(bundleName)));
|
bundleName:=Copy(bundleName, 1, length(bundleName)-length(ExtractFileExt(bundleName)));
|
||||||
@ -122,13 +136,15 @@ begin
|
|||||||
|
|
||||||
FillBunldeInfo(true, Info);
|
FillBunldeInfo(true, Info);
|
||||||
|
|
||||||
CreateBundle(bundleName, Space, ExtractFileName(nm), Info, RealSpace, bundlepath, exepath);
|
CreateBundle(UTF8Decode(bundleName), Space
|
||||||
|
, UTF8Decode(ExtractFileName(nm))
|
||||||
|
, Info, RealSpace, bundlepath, exepath);
|
||||||
|
|
||||||
WriteIconTo( IncludeTrailingPathDelimiter(bundlepath)+'Icon.png');
|
WriteIconTo( UTF8Encode(IncludeTrailingPathDelimiter(bundlepath)+'Icon.png') );
|
||||||
|
|
||||||
CopySymLinks(
|
CopySymLinks(
|
||||||
ResolveProjectPath(ProjOptions.ResourceDir),
|
ResolveProjectPath(ProjOptions.ResourceDir),
|
||||||
bundlepath,
|
UTF8Encode(bundlepath),
|
||||||
// don't copy .xib files, they're replaced by compiled nibs
|
// don't copy .xib files, they're replaced by compiled nibs
|
||||||
'*.xib; '+ ProjOptions.ExcludeMask
|
'*.xib; '+ ProjOptions.ExcludeMask
|
||||||
);
|
);
|
||||||
@ -152,7 +168,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
EnumFilesAtDir(ResolveProjectPath(ProjOptions.ResourceDir), '*.xib', xiblist);
|
EnumFilesAtDir(ResolveProjectPath(ProjOptions.ResourceDir), '*.xib', xiblist);
|
||||||
for i:=0 to xiblist.Count-1 do begin
|
for i:=0 to xiblist.Count-1 do begin
|
||||||
dstpath:=IncludeTrailingPathDelimiter(bundlepath)+ChangeFileExt(ExtractFileName(xiblist[i]), '.nib');
|
dstpath:=UTF8Encode(IncludeTrailingPathDelimiter(bundlepath))+ChangeFileExt(ExtractFileName(xiblist[i]), '.nib');
|
||||||
ExecCmdLineNoWait(Format('ibtool --compile "%s" "%s"', [dstpath, xiblist[i]]));
|
ExecCmdLineNoWait(Format('ibtool --compile "%s" "%s"', [dstpath, xiblist[i]]));
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
@ -213,7 +229,7 @@ begin
|
|||||||
try
|
try
|
||||||
EnvOptions.GetSDKVersions(st);
|
EnvOptions.GetSDKVersions(st);
|
||||||
if st.Count=0 then
|
if st.Count=0 then
|
||||||
IDEMessagesWindow.AddMsg(strWNoSDK, '', 0)
|
IDEMsg(strWNoSDK)
|
||||||
else begin
|
else begin
|
||||||
sdkver:=st[0];
|
sdkver:=st[0];
|
||||||
ProjOptions.SDK:=sdkver;
|
ProjOptions.SDK:=sdkver;
|
||||||
@ -258,6 +274,7 @@ begin
|
|||||||
|
|
||||||
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneToXCode', strStartAtXcode, @UpdateXcode, nil);
|
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneToXCode', strStartAtXcode, @UpdateXcode, nil);
|
||||||
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneRunSim', strRunSimulator, @SimRun, nil);
|
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneRunSim', strRunSimulator, @SimRun, nil);
|
||||||
|
RegisterIDEMenuCommand(itmProjectWindowSection, 'mnuiPhoneTermSim', strTermSimulator, @SimTerminate, nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TiPhoneExtension.ProjectBuilding(Sender: TObject): TModalResult;
|
function TiPhoneExtension.ProjectBuilding(Sender: TObject): TModalResult;
|
||||||
@ -283,6 +300,20 @@ begin
|
|||||||
Result:=mrOk;
|
Result:=mrOk;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TiPhoneExtension.GetXcodeProjDirName: string;
|
||||||
|
var
|
||||||
|
dir : string;
|
||||||
|
projname : string;
|
||||||
|
ext : string;
|
||||||
|
begin
|
||||||
|
dir:=ResolveProjectPath('xcode');
|
||||||
|
dir:=dir+'/';
|
||||||
|
projname:=ExtractFileName(LazarusIDE.ActiveProject.MainFile.Filename);
|
||||||
|
ext:=ExtractFileExt(projname);
|
||||||
|
projname:=Copy(projname, 1, length(projname)-length(ext));
|
||||||
|
Result:=dir+projname+'.xcodeproj';
|
||||||
|
end;
|
||||||
|
|
||||||
function TiPhoneExtension.WriteIconTo(const FullName: String): Boolean;
|
function TiPhoneExtension.WriteIconTo(const FullName: String): Boolean;
|
||||||
var
|
var
|
||||||
icofile : string;
|
icofile : string;
|
||||||
@ -348,15 +379,12 @@ var
|
|||||||
projname : string;
|
projname : string;
|
||||||
|
|
||||||
ext : string;
|
ext : string;
|
||||||
exename : string;
|
|
||||||
tname : string;
|
tname : string;
|
||||||
plistname : string;
|
plistname : string;
|
||||||
|
|
||||||
Info : TiPhoneBundleInfo;
|
Info : TiPhoneBundleInfo;
|
||||||
name : string;
|
|
||||||
|
|
||||||
opt : string;
|
opt : string;
|
||||||
optSim: string;
|
|
||||||
begin
|
begin
|
||||||
// the create .plist would be used by XCode project
|
// the create .plist would be used by XCode project
|
||||||
// the simulator .plist in created with InstallAppToSim.
|
// the simulator .plist in created with InstallAppToSim.
|
||||||
@ -391,7 +419,11 @@ begin
|
|||||||
ForceDirectories(dir);
|
ForceDirectories(dir);
|
||||||
|
|
||||||
FillBunldeInfo(false, Info);
|
FillBunldeInfo(false, Info);
|
||||||
WriteDefInfoList( dir + plistname, tname, tname, Info);
|
WriteDefInfoList(
|
||||||
|
UTF8Decode(dir + plistname)
|
||||||
|
, UTF8Decode(tname)
|
||||||
|
, UTF8Decode(tname)
|
||||||
|
, Info);
|
||||||
|
|
||||||
|
|
||||||
projname:=ExtractFileName(LazarusIDE.ActiveProject.MainFile.Filename);
|
projname:=ExtractFileName(LazarusIDE.ActiveProject.MainFile.Filename);
|
||||||
@ -438,7 +470,7 @@ begin
|
|||||||
templates.Free;
|
templates.Free;
|
||||||
build.Free;
|
build.Free;
|
||||||
|
|
||||||
IDEMessagesWindow.AddMsg(Format(strXcodeUpdated,[projdir]), '', 0);
|
IDEMsg(Format(strXcodeUpdated,[projdir]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure SimRunDirect;
|
procedure SimRunDirect;
|
||||||
@ -450,8 +482,8 @@ begin
|
|||||||
try
|
try
|
||||||
path:=IncludeTrailingPathDelimiter(EnvOptions.SimBundle)+'Contents/MacOS/iPhone Simulator';
|
path:=IncludeTrailingPathDelimiter(EnvOptions.SimBundle)+'Contents/MacOS/iPhone Simulator';
|
||||||
EnvOptions.SubstituteMacros(path);
|
EnvOptions.SubstituteMacros(path);
|
||||||
t.CommandLine:='"'+path+'"';
|
t.Executable:=path;
|
||||||
t.CurrentDirectory:=UTF8Encode(GetSandBoxDir(ProjOptions.SpaceName));
|
t.CurrentDirectory:=UTF8Encode(GetSandBoxDir(UTF8Decode(ProjOptions.SpaceName)));
|
||||||
t.Execute;
|
t.Execute;
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
@ -474,11 +506,67 @@ end;
|
|||||||
procedure TiPhoneExtension.SimRun(Sender: TObject);
|
procedure TiPhoneExtension.SimRun(Sender: TObject);
|
||||||
var
|
var
|
||||||
err : string;
|
err : string;
|
||||||
|
pid : integer;
|
||||||
|
prj : string;
|
||||||
|
s : string;
|
||||||
begin
|
begin
|
||||||
|
CloseProc;
|
||||||
|
UpdateXcode(Sender);
|
||||||
|
// install Xcode project
|
||||||
|
prj := GetXcodeProjDirName;
|
||||||
|
IDEMsg('Build+Install Xcode project (xcodebuild)');
|
||||||
|
|
||||||
|
if not InstallXcodePrj(prj, 'iphonesimulator') then begin
|
||||||
|
IDEMsg('xcodebuild failed');
|
||||||
|
Exit;
|
||||||
|
end else
|
||||||
|
IDEMsg('xcodebuild successed, project installed');
|
||||||
|
|
||||||
|
IDEMsg('Running Simulator');
|
||||||
if not SimRunInstruct(err) then begin
|
if not SimRunInstruct(err) then begin
|
||||||
ShowMessage('Unable to run Simulator. '+err);
|
IDEMsg('Unable to run Simulator. '+err);
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
if not Assigned(iphonelogform) then
|
||||||
|
iphonelogform:=Tiphonelogform.Create(Application)
|
||||||
|
else
|
||||||
|
iphonelogform.AddNewSheet;
|
||||||
|
SimLogger:=TPTYReader.Create;
|
||||||
|
SimLogger.OnBytesRead:=@OnBytesRead;
|
||||||
|
|
||||||
|
IDEMsg('Launching the Application on the Simulator');
|
||||||
|
if RunAppOnSim( ProjOptions.AppID, 'booted', true, pid, s) then begin
|
||||||
|
SimPID:=pid;
|
||||||
|
LLDBRediretIO(SimPID, SimLogger.PTY.FileName);
|
||||||
|
iphonelogform.Show;
|
||||||
|
end else begin
|
||||||
|
IDEMsg('Failed to launch Application.');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
IDEMsg('Success. Application pid='+IntToStr(pid));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TiPhoneExtension.SimTerminate(Sender: TObject);
|
||||||
|
begin
|
||||||
|
CloseProc;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TiPhoneExtension.CloseProc;
|
||||||
|
begin
|
||||||
|
if SimPID>0 then begin
|
||||||
|
StopProc(SimPID);
|
||||||
|
SimPID:=-1;
|
||||||
|
SimLogger.Free;
|
||||||
|
SimLogger:=nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TiPhoneExtension.OnBytesRead(Sender: TObject; const buf: string);
|
||||||
|
begin
|
||||||
|
if not Assigned(iphonelogform) then Exit;
|
||||||
|
iphonelogform.LogMemo.Append(buf);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure Register;
|
procedure Register;
|
||||||
|
@ -19,7 +19,7 @@ unit iPhoneBundle;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils;
|
Classes, SysUtils, LazFileUtils;
|
||||||
|
|
||||||
const
|
const
|
||||||
platform_iPhoneSim = 'iphonesimulator';
|
platform_iPhoneSim = 'iphonesimulator';
|
||||||
@ -61,7 +61,6 @@ function RandomSpaceName: WideString;
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
FileUtil,
|
|
||||||
iPhoneExtOptions;
|
iPhoneExtOptions;
|
||||||
|
|
||||||
function RandomSpaceName: WideString;
|
function RandomSpaceName: WideString;
|
||||||
@ -253,7 +252,7 @@ begin
|
|||||||
]);
|
]);
|
||||||
if FileExists(InfoFileName) then DeleteFile(InfoFileName);
|
if FileExists(InfoFileName) then DeleteFile(InfoFileName);
|
||||||
|
|
||||||
fs:=TFileStream.Create(InfoFileName, fmCreate or fmOpenWrite);
|
fs:=TFileStream.Create(UTF8Encode(InfoFileName), fmCreate or fmOpenWrite);
|
||||||
try
|
try
|
||||||
if s<>'' then fs.Write(s[1], length(s));
|
if s<>'' then fs.Write(s[1], length(s));
|
||||||
finally
|
finally
|
||||||
|
@ -21,8 +21,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, MacroIntf,
|
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, MacroIntf,
|
||||||
CompOptsIntf,
|
iPhoneBundle, XMLConf, XcodeUtils, LazFileUtils, iphonesimctrl;
|
||||||
iPhoneBundle, XMLConf, XcodeUtils, FileUtil, iphonesimctrl;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
DefaultResourceDir = 'Resources';
|
DefaultResourceDir = 'Resources';
|
||||||
@ -247,7 +246,7 @@ end;
|
|||||||
function GetDefaultPlatformPath: WideString;
|
function GetDefaultPlatformPath: WideString;
|
||||||
begin
|
begin
|
||||||
result := '/Applications/Xcode.app/Contents/Developer/Platforms';
|
result := '/Applications/Xcode.app/Contents/Developer/Platforms';
|
||||||
if not DirectoryExistsUTF8(result) then
|
if not DirectoryExistsUTF8(UTF8Encode(result)) then
|
||||||
Result:='/Developer/Platforms';
|
Result:='/Developer/Platforms';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -266,9 +265,9 @@ end;
|
|||||||
constructor TiPhoneEnvironmentOptions.Create;
|
constructor TiPhoneEnvironmentOptions.Create;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
fPlatformsBaseDir := GetDefaultPlatformPath;
|
fPlatformsBaseDir := UTF8Encode(GetDefaultPlatformPath);
|
||||||
fSimAppsPath := GetDefaultSimAppPath;
|
fSimAppsPath := UTF8Encode(GetDefaultSimAppPath);
|
||||||
fSimBundle := GetDefaultSimBundlePath;
|
fSimBundle := UTF8Encode(GetDefaultSimBundlePath);
|
||||||
fCompilerPath := '/usr/local/bin/fpc';
|
fCompilerPath := '/usr/local/bin/fpc';
|
||||||
fVersions:=TStringList.Create;
|
fVersions:=TStringList.Create;
|
||||||
fDeviceList:=TList.Create;
|
fDeviceList:=TList.Create;
|
||||||
@ -444,7 +443,7 @@ begin
|
|||||||
if CustomData.Contains(optSDK) then fSDK:=CustomData.Values[optSDK];
|
if CustomData.Contains(optSDK) then fSDK:=CustomData.Values[optSDK];
|
||||||
if CustomData.Contains(optAppID) then fAppID:=CustomData.Values[optAppID];
|
if CustomData.Contains(optAppID) then fAppID:=CustomData.Values[optAppID];
|
||||||
fSpaceName:=CustomData.Values[optSpaceName];
|
fSpaceName:=CustomData.Values[optSpaceName];
|
||||||
if fSpaceName='' then fSpaceName:=RandomSpaceName;
|
if fSpaceName='' then fSpaceName:=UTF8Encode(RandomSpaceName);
|
||||||
if CustomData.Contains(optResourceDir) then fResourceDir:=CustomData.Values[optResourceDir]
|
if CustomData.Contains(optResourceDir) then fResourceDir:=CustomData.Values[optResourceDir]
|
||||||
else fResourceDir:=DefaultResourceDir;
|
else fResourceDir:=DefaultResourceDir;
|
||||||
if CustomData.Contains(optExcludeMask) then fExcludeMask:=CustomData.Values[optExcludeMask];
|
if CustomData.Contains(optExcludeMask) then fExcludeMask:=CustomData.Values[optExcludeMask];
|
||||||
|
@ -22,6 +22,7 @@ resourcestring
|
|||||||
striPhoneProject = 'iPhone Project';
|
striPhoneProject = 'iPhone Project';
|
||||||
strStartAtXcode = 'Update Xcode project';
|
strStartAtXcode = 'Update Xcode project';
|
||||||
strRunSimulator = 'Run iPhone Simulator';
|
strRunSimulator = 'Run iPhone Simulator';
|
||||||
|
strTermSimulator = 'Terminate Project App on Sim';
|
||||||
|
|
||||||
strPrjOptTitle = 'iPhone specific';
|
strPrjOptTitle = 'iPhone specific';
|
||||||
strPrjOptIsiPhone = 'is iPhone application project';
|
strPrjOptIsiPhone = 'is iPhone application project';
|
||||||
|
@ -12,9 +12,16 @@
|
|||||||
</SearchPaths>
|
</SearchPaths>
|
||||||
<Parsing>
|
<Parsing>
|
||||||
<SyntaxOptions>
|
<SyntaxOptions>
|
||||||
<UseAnsiStrings Value="False"/>
|
<CStyleOperator Value="False"/>
|
||||||
|
<AllowLabel Value="False"/>
|
||||||
|
<CPPInline Value="False"/>
|
||||||
</SyntaxOptions>
|
</SyntaxOptions>
|
||||||
</Parsing>
|
</Parsing>
|
||||||
|
<CodeGeneration>
|
||||||
|
<Optimizations>
|
||||||
|
<OptimizationLevel Value="0"/>
|
||||||
|
</Optimizations>
|
||||||
|
</CodeGeneration>
|
||||||
<Other>
|
<Other>
|
||||||
<CompilerMessages>
|
<CompilerMessages>
|
||||||
<IgnoredMessages idx5091="True" idx5060="True" idx5057="True" idx5024="True" idx4081="True" idx4080="True" idx4079="True" idx4055="True"/>
|
<IgnoredMessages idx5091="True" idx5060="True" idx5057="True" idx5024="True" idx4081="True" idx4080="True" idx4079="True" idx4055="True"/>
|
||||||
@ -25,7 +32,7 @@
|
|||||||
<Description Value="iPhone Development Lazarus extension"/>
|
<Description Value="iPhone Development Lazarus extension"/>
|
||||||
<License Value="LGPL"/>
|
<License Value="LGPL"/>
|
||||||
<Version Minor="8"/>
|
<Version Minor="8"/>
|
||||||
<Files Count="21">
|
<Files Count="22">
|
||||||
<Item1>
|
<Item1>
|
||||||
<Filename Value="ideext.pas"/>
|
<Filename Value="ideext.pas"/>
|
||||||
<HasRegisterProc Value="True"/>
|
<HasRegisterProc Value="True"/>
|
||||||
@ -114,6 +121,10 @@
|
|||||||
<Filename Value="res/buildscript.sh"/>
|
<Filename Value="res/buildscript.sh"/>
|
||||||
<Type Value="Text"/>
|
<Type Value="Text"/>
|
||||||
</Item21>
|
</Item21>
|
||||||
|
<Item22>
|
||||||
|
<Filename Value="iphonelog_form.pas"/>
|
||||||
|
<UnitName Value="iphonelog_form"/>
|
||||||
|
</Item22>
|
||||||
</Files>
|
</Files>
|
||||||
<RequiredPkgs Count="3">
|
<RequiredPkgs Count="3">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
@ -10,7 +10,7 @@ uses
|
|||||||
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
||||||
environment_iphone_options, project_iphone_options, iPhoneExtOptions,
|
environment_iphone_options, project_iphone_options, iPhoneExtOptions,
|
||||||
xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, xibfile, PlistFile,
|
xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, xibfile, PlistFile,
|
||||||
xcodeprojutils, iphonesimctrl, LazarusPackageIntf;
|
xcodeprojutils, iphonesimctrl, iphonelog_form, LazarusPackageIntf;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
63
components/iphonelazext/iphonelog_form.lfm
Normal file
63
components/iphonelazext/iphonelog_form.lfm
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
object iphonelogform: Tiphonelogform
|
||||||
|
Left = 443
|
||||||
|
Height = 342
|
||||||
|
Top = 233
|
||||||
|
Width = 501
|
||||||
|
Caption = 'iPhone Application Log'
|
||||||
|
ClientHeight = 342
|
||||||
|
ClientWidth = 501
|
||||||
|
OnCreate = FormCreate
|
||||||
|
OnShow = FormShow
|
||||||
|
LCLVersion = '1.7'
|
||||||
|
object PageControl1: TPageControl
|
||||||
|
Left = 0
|
||||||
|
Height = 316
|
||||||
|
Top = 26
|
||||||
|
Width = 501
|
||||||
|
ActivePage = LogSheet1
|
||||||
|
Align = alClient
|
||||||
|
TabIndex = 0
|
||||||
|
TabOrder = 0
|
||||||
|
object LogSheet1: TTabSheet
|
||||||
|
Caption = 'Log'
|
||||||
|
ClientHeight = 277
|
||||||
|
ClientWidth = 495
|
||||||
|
object Memo1: TMemo
|
||||||
|
Left = 0
|
||||||
|
Height = 277
|
||||||
|
Top = 0
|
||||||
|
Width = 495
|
||||||
|
Align = alClient
|
||||||
|
Font.Name = 'Monaco'
|
||||||
|
Lines.Strings = (
|
||||||
|
'Memo1'
|
||||||
|
''
|
||||||
|
''
|
||||||
|
''
|
||||||
|
)
|
||||||
|
ParentFont = False
|
||||||
|
ScrollBars = ssBoth
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object Panel1: TPanel
|
||||||
|
Left = 0
|
||||||
|
Height = 26
|
||||||
|
Top = 0
|
||||||
|
Width = 501
|
||||||
|
Align = alTop
|
||||||
|
ClientHeight = 26
|
||||||
|
ClientWidth = 501
|
||||||
|
TabOrder = 1
|
||||||
|
object chkStayOnTop: TCheckBox
|
||||||
|
Left = 8
|
||||||
|
Height = 18
|
||||||
|
Top = 5
|
||||||
|
Width = 94
|
||||||
|
Caption = 'Stay On Top'
|
||||||
|
OnChange = chkStayOnTopChange
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
81
components/iphonelazext/iphonelog_form.pas
Normal file
81
components/iphonelazext/iphonelog_form.pas
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
unit iphonelog_form;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
|
||||||
|
StdCtrls, ExtCtrls;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ Tiphonelogform }
|
||||||
|
|
||||||
|
Tiphonelogform = class(TForm)
|
||||||
|
chkStayOnTop: TCheckBox;
|
||||||
|
LogSheet1: TTabSheet;
|
||||||
|
Memo1: TMemo;
|
||||||
|
PageControl1: TPageControl;
|
||||||
|
Panel1: TPanel;
|
||||||
|
procedure chkStayOnTopChange(Sender: TObject);
|
||||||
|
procedure FormCreate(Sender: TObject);
|
||||||
|
procedure FormShow(Sender: TObject);
|
||||||
|
private
|
||||||
|
{ private declarations }
|
||||||
|
fLogMemo: TMemo;
|
||||||
|
public
|
||||||
|
{ public declarations }
|
||||||
|
function AddNewSheet: TTabSheet;
|
||||||
|
procedure CaptionLog(sh: TTabSheet);
|
||||||
|
property LogMemo: TMemo read fLogMemo;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
iphonelogform: Tiphonelogform = nil;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$R *.lfm}
|
||||||
|
|
||||||
|
{ Tiphonelogform }
|
||||||
|
|
||||||
|
procedure Tiphonelogform.chkStayOnTopChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
if chkStayOnTop.Checked
|
||||||
|
then Self.FormStyle:=fsStayOnTop
|
||||||
|
else Self.FormStyle:=fsNormal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Tiphonelogform.FormCreate(Sender: TObject);
|
||||||
|
begin
|
||||||
|
fLogMemo:=Memo1;
|
||||||
|
CaptionLog(LogSheet1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Tiphonelogform.FormShow(Sender: TObject);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Tiphonelogform.AddNewSheet: TTabSheet;
|
||||||
|
var
|
||||||
|
m : TMemo;
|
||||||
|
begin
|
||||||
|
Result:=PageControl1.AddTabSheet;
|
||||||
|
CaptionLog(Result);
|
||||||
|
m:=TMemo.Create(Result);
|
||||||
|
m.Parent:=Result;
|
||||||
|
m.Align:=Memo1.Align;
|
||||||
|
m.ScrollBars:=Memo1.ScrollBars;
|
||||||
|
m.Font.Assign(Memo1.Font);
|
||||||
|
PageControl1.ActivePage:=Result;
|
||||||
|
fLogMemo:=m;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Tiphonelogform.CaptionLog(sh: TTabSheet);
|
||||||
|
begin
|
||||||
|
sh.Caption:='Log '+FormatDateTime('hh-nn', now);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -5,9 +5,11 @@ unit iphonesimctrl;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
{$ifdef unix}
|
||||||
|
BaseUnix, Unix, termio,
|
||||||
|
{$endif}
|
||||||
Classes, SysUtils, process
|
Classes, SysUtils, process
|
||||||
, jsonparser, fpjson
|
, jsonparser, fpjson
|
||||||
{$ifdef unix}, BaseUnix{$endif} // for StopProc()
|
|
||||||
;
|
;
|
||||||
|
|
||||||
procedure RunSim(const SimName: string);
|
procedure RunSim(const SimName: string);
|
||||||
@ -26,6 +28,99 @@ type
|
|||||||
|
|
||||||
function ListDevice(lst: TList): Boolean;
|
function ListDevice(lst: TList): Boolean;
|
||||||
|
|
||||||
|
function InstallXcodePrj(const project, sdk: string): Boolean;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ TRWProcess }
|
||||||
|
|
||||||
|
TRWProcess = class(TObject)
|
||||||
|
protected
|
||||||
|
process : TProcess;
|
||||||
|
bytesread : integer;
|
||||||
|
stderrbytesread : integer;
|
||||||
|
outputstring : string;
|
||||||
|
stderrstring : string;
|
||||||
|
exitstatus : Integer;
|
||||||
|
procedure CloseProcess;
|
||||||
|
procedure ReadProc(TimeOut: Integer);
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
function WriteLn(const s: string): Boolean;
|
||||||
|
function ReadLn(var s: string): Boolean;
|
||||||
|
function HasLine: Boolean;
|
||||||
|
procedure Await(TimeOut: integer = -1);
|
||||||
|
procedure Run(const exename: string; const commands: array of string;
|
||||||
|
const curdir: string);
|
||||||
|
procedure Terminate(exitCode: integer);
|
||||||
|
function isRunning: Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
DEF_LLDB_EXENAME = 'lldb';
|
||||||
|
|
||||||
|
procedure LLDBRediretIO(const exename: string; pid, ttyfn: string); overload;
|
||||||
|
procedure LLDBRediretIO(const pid, ttyfn: string); overload;
|
||||||
|
procedure LLDBRediretIO(pid: integer; const ttyfn: string); overload;
|
||||||
|
|
||||||
|
{$ifdef unix}
|
||||||
|
type
|
||||||
|
Ptermios = ^termios;
|
||||||
|
Pwinsize = ^winsize;
|
||||||
|
|
||||||
|
function openpty(amaster:pcint; aslave:pcint;
|
||||||
|
name:Pchar; termp:Ptermios; winp:Pwinsize):longint;cdecl;external clib name 'openpty';
|
||||||
|
|
||||||
|
type
|
||||||
|
TReadEvent = procedure (Sender: TObject; const buf: string) of object;
|
||||||
|
{ TReadThread }
|
||||||
|
|
||||||
|
TReadThread = class(TThread)
|
||||||
|
protected
|
||||||
|
readfd: cint;
|
||||||
|
waitbuf: string;
|
||||||
|
fOnInputBytes: TReadEvent;
|
||||||
|
procedure Execute; override;
|
||||||
|
procedure DoInputBytes;
|
||||||
|
public
|
||||||
|
constructor Create(afd: cint);
|
||||||
|
property OnInputBytes: TReadEvent read fOnInputBytes write fOnInputBytes;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPTY }
|
||||||
|
|
||||||
|
TPTY = class(TObject)
|
||||||
|
private
|
||||||
|
fSlave : cint;
|
||||||
|
fMaster : cint;
|
||||||
|
fFileName : string;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
property Master: cint read fMaster;
|
||||||
|
property Slave: cint read fSlave;
|
||||||
|
property FileName: string read fFileName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPTYReader }
|
||||||
|
|
||||||
|
TPTYReader = class(TObject)
|
||||||
|
private
|
||||||
|
fPTY : TPTY;
|
||||||
|
fOnBytesRead: TReadEvent;
|
||||||
|
fThread : TReadThread;
|
||||||
|
fLog : string;
|
||||||
|
protected
|
||||||
|
procedure OnInput(Sender: TObject; const Buf: string);
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
property PTY: TPTY read fPTY;
|
||||||
|
property OnBytesRead: TReadEvent read fOnBytesRead write fOnBytesRead;
|
||||||
|
property Log: string read fLog;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
procedure RunSim(const SimName: string);
|
procedure RunSim(const SimName: string);
|
||||||
@ -147,5 +242,360 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function InstallXcodePrj(const project, sdk: string): Boolean;
|
||||||
|
var
|
||||||
|
outstr: string;
|
||||||
|
begin
|
||||||
|
writeln('project = ', project);
|
||||||
|
writeln('sdk = ', sdk);
|
||||||
|
Result:=RunCommand('xcodebuild', ['install', '-project' ,project, '-sdk',sdk], outstr);
|
||||||
|
if not Result then Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Const
|
||||||
|
READ_BYTES = 65536;
|
||||||
|
|
||||||
|
{ TRWProcess }
|
||||||
|
|
||||||
|
procedure TRWProcess.Run(const exename: string;
|
||||||
|
const commands: array of string; const curdir: string);
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
if Assigned(process) then CloseProcess;
|
||||||
|
|
||||||
|
process:=TProcess.create(nil);
|
||||||
|
process.Executable:=exename;
|
||||||
|
if curdir<>'' then process.CurrentDirectory:=curdir;
|
||||||
|
|
||||||
|
if high(commands)>=0 then
|
||||||
|
for i:=low(commands) to high(commands) do
|
||||||
|
begin
|
||||||
|
process.Parameters.add(commands[i]);
|
||||||
|
end;
|
||||||
|
process.Options := [poUsePipes];
|
||||||
|
|
||||||
|
process.Execute;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRWProcess.Terminate(exitCode: integer);
|
||||||
|
begin
|
||||||
|
if Assigned(process) then process.Terminate(exitCode);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRWProcess.isRunning: Boolean;
|
||||||
|
begin
|
||||||
|
Result:=Assigned(process) and (process.Running);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRWProcess.CloseProcess;
|
||||||
|
begin
|
||||||
|
process.Free;
|
||||||
|
process:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRWProcess.ReadProc(TimeOut: Integer);
|
||||||
|
var
|
||||||
|
numbytes : integer;
|
||||||
|
available : integer;
|
||||||
|
outputlength : integer;
|
||||||
|
stderrlength : integer;
|
||||||
|
stderrnumbytes : integer;
|
||||||
|
l : integer;
|
||||||
|
begin
|
||||||
|
outputlength:=0;
|
||||||
|
stderrbytesread:=0;
|
||||||
|
stderrlength:=0;
|
||||||
|
try
|
||||||
|
|
||||||
|
while process.Running do begin
|
||||||
|
// Only call ReadFromStream if Data from corresponding stream
|
||||||
|
// is already available, otherwise, on linux, the read call
|
||||||
|
// is blocking, and thus it is not possible to be sure to handle
|
||||||
|
// big data amounts bboth on output and stderr pipes. PM.
|
||||||
|
available:=process.Output.NumBytesAvailable;
|
||||||
|
if available > 0 then begin
|
||||||
|
while (BytesRead + available > length(outputstring)) do begin
|
||||||
|
outputlength:=length(outputstring) + READ_BYTES;
|
||||||
|
l:=length(outputstring);
|
||||||
|
Setlength(outputstring,outputlength);
|
||||||
|
FillChar(outputstring[l+1], length(outputstring)-l, #0);
|
||||||
|
end;
|
||||||
|
NumBytes := process.Output.Read(outputstring[1+bytesread], available);
|
||||||
|
if NumBytes > 0 then
|
||||||
|
Inc(BytesRead, NumBytes);
|
||||||
|
end
|
||||||
|
// The check for assigned(P.stderr) is mainly here so that
|
||||||
|
// if we use poStderrToOutput in p.Options, we do not access invalid memory.
|
||||||
|
else if assigned(process.stderr) and (process.StdErr.NumBytesAvailable > 0) then begin
|
||||||
|
available:=process.StdErr.NumBytesAvailable;
|
||||||
|
while (StderrBytesRead + available > length(stderrstring)) do begin
|
||||||
|
stderrlength:=length(stderrstring) + READ_BYTES;
|
||||||
|
l:=length(stderrstring);
|
||||||
|
Setlength(stderrstring,stderrlength);
|
||||||
|
FillChar(stderrstring[l+1], length(stderrstring)-l, #0);
|
||||||
|
end;
|
||||||
|
StderrNumBytes := process.StdErr.Read(stderrstring[1+StderrBytesRead], available);
|
||||||
|
if StderrNumBytes > 0 then
|
||||||
|
Inc(StderrBytesRead, StderrNumBytes);
|
||||||
|
end else begin
|
||||||
|
Sleep(100);
|
||||||
|
if TimeOut>0 then begin
|
||||||
|
TimeOut:=TimeOut-100;
|
||||||
|
if TimeOut<=0 then Exit;
|
||||||
|
// This is Exit, not Break to prevent reading "available"
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Get left output after end of execution
|
||||||
|
available:=process.Output.NumBytesAvailable;
|
||||||
|
while available > 0 do begin
|
||||||
|
if (BytesRead + available > outputlength) then begin
|
||||||
|
outputlength:=BytesRead + READ_BYTES;
|
||||||
|
Setlength(outputstring,outputlength);
|
||||||
|
end;
|
||||||
|
NumBytes := process.Output.Read(outputstring[1+bytesread], available);
|
||||||
|
if NumBytes > 0 then Inc(BytesRead, NumBytes);
|
||||||
|
available:=process.Output.NumBytesAvailable;
|
||||||
|
end;
|
||||||
|
|
||||||
|
setlength(outputstring,BytesRead);
|
||||||
|
while assigned(process.stderr) and (process.Stderr.NumBytesAvailable > 0) do begin
|
||||||
|
available:=process.Stderr.NumBytesAvailable;
|
||||||
|
if (StderrBytesRead + available > stderrlength) then begin
|
||||||
|
stderrlength:=StderrBytesRead + READ_BYTES;
|
||||||
|
Setlength(stderrstring,stderrlength);
|
||||||
|
end;
|
||||||
|
StderrNumBytes := process.StdErr.Read(stderrstring[1+StderrBytesRead], available);
|
||||||
|
if StderrNumBytes > 0 then Inc(StderrBytesRead, StderrNumBytes);
|
||||||
|
end;
|
||||||
|
|
||||||
|
setlength(stderrstring,StderrBytesRead);
|
||||||
|
exitstatus:=process.exitstatus;
|
||||||
|
except
|
||||||
|
on e : Exception do begin
|
||||||
|
setlength(outputstring,BytesRead);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TRWProcess.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TRWProcess.Destroy;
|
||||||
|
begin
|
||||||
|
CloseProcess;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRWProcess.WriteLn(const s: string): Boolean;
|
||||||
|
var
|
||||||
|
e : string;
|
||||||
|
begin
|
||||||
|
if not Assigned(process) or (not process.Running) then begin
|
||||||
|
Result:=false;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
process.Input.Write(s[1], length(s));
|
||||||
|
e:=LineEnding;
|
||||||
|
process.Input.Write(e[1], length(e));
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRWProcess.ReadLn(var s: string): Boolean;
|
||||||
|
var
|
||||||
|
bk: integer;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
s:='';
|
||||||
|
if not Assigned(process) or (outputstring='') then begin
|
||||||
|
Result:=false;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// read remaining bytes
|
||||||
|
if (not process.Running) and (process.Output.NumBytesAvailable>0) then
|
||||||
|
ReadProc(-1);
|
||||||
|
|
||||||
|
bk:=Pos(#10, outputstring);
|
||||||
|
if bk<=0 then bk:=Pos(#13, outputstring);
|
||||||
|
if not process.Running and (bk<=0) then begin
|
||||||
|
s:=outputstring;
|
||||||
|
outputstring:='';
|
||||||
|
bytesread:=0;
|
||||||
|
Result:=true;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
Result:=bk>0;
|
||||||
|
if not Result then Exit;
|
||||||
|
|
||||||
|
i:=bk;
|
||||||
|
if (bk<length(outputstring)) and (outputstring[bk+1] in [#10,#13])
|
||||||
|
and (outputstring[bk]<>outputstring[bk+1]) then
|
||||||
|
inc(i);
|
||||||
|
s:=Copy(outputstring, 1, bk-1);
|
||||||
|
outputstring:=Copy(outputstring, i+1, length(outputstring));
|
||||||
|
dec(bytesread, i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TRWProcess.HasLine: Boolean;
|
||||||
|
var
|
||||||
|
bk: integer;
|
||||||
|
begin
|
||||||
|
if not Assigned(process) or (outputstring='') then begin
|
||||||
|
Result:=false;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// read remaining bytes
|
||||||
|
if (not process.Running) and (process.Output.NumBytesAvailable>0) then
|
||||||
|
ReadProc(-1);
|
||||||
|
|
||||||
|
bk:=Pos(#10, outputstring);
|
||||||
|
if bk<=0 then bk:=Pos(#13, outputstring);
|
||||||
|
Result:=(process.Running and (bk>0))
|
||||||
|
or ((not process.Running) and (length(outputstring)>0));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TRWProcess.Await(TimeOut: integer);
|
||||||
|
begin
|
||||||
|
if not Assigned(process) or (not process.Running) then Exit;
|
||||||
|
ReadProc(TimeOut);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure LLDBRediretIO(const pid, ttyfn: string); overload;
|
||||||
|
begin
|
||||||
|
LLDBRediretIO(DEF_LLDB_EXENAME, pid, ttyfn);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure LLDBRediretIO(pid: integer; const ttyfn: string);
|
||||||
|
begin
|
||||||
|
LLDBRediretIO(DEF_LLDB_EXENAME, IntToStr(pid), ttyfn);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure LLDBRediretIO(const exename: string; pid, ttyfn: string);
|
||||||
|
var
|
||||||
|
p : TRWProcess;
|
||||||
|
cmd : array[0..1] of string;
|
||||||
|
s : string;
|
||||||
|
begin
|
||||||
|
cmd[0]:='-p';
|
||||||
|
cmd[1]:=pid;
|
||||||
|
|
||||||
|
s:='';
|
||||||
|
p := TRWProcess.Create;
|
||||||
|
try
|
||||||
|
p.Run(exename, cmd, '');
|
||||||
|
p.WriteLn('version');
|
||||||
|
p.WriteLn('breakpoint set --name main');
|
||||||
|
p.WriteLn('breakpoint command add 1');
|
||||||
|
p.WriteLn('p (int) dup2 ( (int) open("'+ttyfn+'",1), 2 )');
|
||||||
|
p.WriteLn('p (int) dup2 ( (int) open("'+ttyfn+'",1), 1 )');
|
||||||
|
p.WriteLn('detach');
|
||||||
|
p.WriteLn('DONE');
|
||||||
|
p.WriteLn('c');
|
||||||
|
|
||||||
|
repeat
|
||||||
|
p.Await(300);
|
||||||
|
while p.HasLine do begin
|
||||||
|
p.ReadLn(s);
|
||||||
|
if (Pos('Process', s)>0) and (Pos('detached',s)>0) then begin
|
||||||
|
p.Writeln('exit');
|
||||||
|
//p.Terminate;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
until not p.isRunning;
|
||||||
|
|
||||||
|
finally
|
||||||
|
p.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$ifdef unix}
|
||||||
|
{ TPTYReader }
|
||||||
|
|
||||||
|
procedure TPTYReader.OnInput(Sender: TObject; const Buf: string);
|
||||||
|
begin
|
||||||
|
fLog:=fLog+Buf;
|
||||||
|
if Assigned(OnBytesRead) then
|
||||||
|
OnBytesRead(Self, Buf);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TPTYReader.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
fPTY:=TPTY.Create;
|
||||||
|
fThread:=TReadThread.Create(fPTY.Master);
|
||||||
|
fThread.OnInputBytes:=OnInput;
|
||||||
|
fThread.Start;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TPTYReader.Destroy;
|
||||||
|
begin
|
||||||
|
fPTY.Free;
|
||||||
|
fThread.Terminate;
|
||||||
|
fThread.WaitFor;
|
||||||
|
fThread.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TPTY }
|
||||||
|
|
||||||
|
constructor TPTY.Create;
|
||||||
|
var
|
||||||
|
ttyname : string;
|
||||||
|
res : integer;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
SetLength(ttyname, 1024);
|
||||||
|
res:=openpty(@fMaster, @fSlave, @ttyname[1], nil, nil);
|
||||||
|
if res=0 then fFileName:=Copy(ttyname, 1, StrLen(@ttyname[1]));
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TPTY.Destroy;
|
||||||
|
begin
|
||||||
|
// Slave must be closed before Master!
|
||||||
|
fpclose(fSlave);
|
||||||
|
fpclose(fMaster);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TReadThread }
|
||||||
|
|
||||||
|
procedure TReadThread.Execute;
|
||||||
|
var
|
||||||
|
buf: string;
|
||||||
|
sz: integer;
|
||||||
|
begin
|
||||||
|
SetLength(buf, 1024);
|
||||||
|
while not Terminated do begin
|
||||||
|
sz:=FpRead(readfd, buf[1], length(Buf));
|
||||||
|
if sz>0 then begin
|
||||||
|
waitbuf:=copy(buf, 1, sz);
|
||||||
|
Synchronize(DoInputBytes);
|
||||||
|
waitbuf:='';
|
||||||
|
end else if sz<=0 then begin
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TReadThread.DoInputBytes;
|
||||||
|
begin
|
||||||
|
if Assigned(OnInputBytes) then OnInputBytes(Self, waitbuf);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TReadThread.Create(afd: cint);
|
||||||
|
begin
|
||||||
|
inherited Create(true);
|
||||||
|
readfd:=afd;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$endif}
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
{$ifdef Unix}BaseUnix,{$endif}
|
{$ifdef Unix}BaseUnix,{$endif}
|
||||||
Classes, SysUtils, FileUtil, Masks,
|
Classes, SysUtils, FileUtil, LazFileUtils, Masks,
|
||||||
LazIDEIntf, ProjectIntf, process;
|
LazIDEIntf, ProjectIntf, process;
|
||||||
|
|
||||||
function ResolveProjectPath(const path: string; project: TLazProject = nil): string;
|
function ResolveProjectPath(const path: string; project: TLazProject = nil): string;
|
||||||
@ -225,11 +225,11 @@ end;
|
|||||||
|
|
||||||
function ExecCmdLineStdOut(const CmdLineUtf8: AnsiString; var StdOut: string; var ErrCode: LongWord): Boolean;
|
function ExecCmdLineStdOut(const CmdLineUtf8: AnsiString; var StdOut: string; var ErrCode: LongWord): Boolean;
|
||||||
var
|
var
|
||||||
OurCommand : String;
|
//OurCommand : String;
|
||||||
OutputLines : TStringList;
|
//OutputLines : TStringList;
|
||||||
MemStream : TStringStream;
|
MemStream : TStringStream;
|
||||||
OurProcess : TProcess;
|
OurProcess : TProcess;
|
||||||
NumBytes : LongInt;
|
//NumBytes : LongInt;
|
||||||
begin
|
begin
|
||||||
// A temp Memorystream is used to buffer the output
|
// A temp Memorystream is used to buffer the output
|
||||||
MemStream := TStringStream.Create('');
|
MemStream := TStringStream.Create('');
|
||||||
|
@ -292,7 +292,6 @@ end;
|
|||||||
|
|
||||||
function ReadValByNode(valnode: TDomNode): TPListValue;
|
function ReadValByNode(valnode: TDomNode): TPListValue;
|
||||||
var
|
var
|
||||||
t : string;
|
|
||||||
tp : TPlistType;
|
tp : TPlistType;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
|
@ -7,7 +7,7 @@ object iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
|||||||
ClientWidth = 598
|
ClientWidth = 598
|
||||||
OnClick = FrameClick
|
OnClick = FrameClick
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
DesignLeft = 408
|
DesignLeft = 410
|
||||||
DesignTop = 201
|
DesignTop = 201
|
||||||
object chkisPhone: TCheckBox
|
object chkisPhone: TCheckBox
|
||||||
Left = 16
|
Left = 16
|
||||||
|
@ -19,7 +19,7 @@ unit project_iphone_options;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes,SysUtils,FileUtil,LResources,Forms,StdCtrls,CheckLst,Buttons, Dialogs,
|
Classes,SysUtils,FileUtil,LazFileUtils,LResources,Forms,StdCtrls,CheckLst,Buttons, Dialogs,
|
||||||
Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr,
|
Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr,
|
||||||
iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog, xibfile
|
iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog, xibfile
|
||||||
,CompOptsIntf;
|
,CompOptsIntf;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
unit xibfile;
|
unit xibfile;
|
||||||
|
|
||||||
{$mode objfpc}
|
{$mode objfpc}{$h+}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user