You've already forked lazarus-ccr
iphonelazext: update in Xcode project generation, using pbx files rather than a text template. Updates project options dialog to compare changes and mark project as modified, if necessary
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4404 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -51,7 +51,6 @@ type
|
||||
constructor Create;
|
||||
procedure UpdateXcode(Sender: TObject);
|
||||
procedure SimRun(Sender: TObject);
|
||||
//procedure isProjectClicked(Sender: TObject);
|
||||
end;
|
||||
|
||||
var
|
||||
@ -349,6 +348,7 @@ var
|
||||
projname : string;
|
||||
|
||||
ext : string;
|
||||
exename : string;
|
||||
tname : string;
|
||||
plistname : string;
|
||||
|
||||
@ -358,7 +358,6 @@ var
|
||||
opt : string;
|
||||
optSim: string;
|
||||
begin
|
||||
FillBunldeInfo(false, Info);
|
||||
// the create .plist would be used by XCode project
|
||||
// the simulator .plist in created with InstallAppToSim.
|
||||
// they differ with SDKs used
|
||||
@ -367,43 +366,32 @@ begin
|
||||
|
||||
tname:=ExtractFileName( LazarusIDE.ActiveProject.MainFile.Filename);
|
||||
tname:=ChangeFileExt(tname, '');
|
||||
plistname:=tname+'.plist';
|
||||
plistname:='info.plist';
|
||||
|
||||
build.Add('INFOPLIST_FILE','"'+plistname+'"');
|
||||
build.Add('PRODUCT_NAME','"'+tname+'"');
|
||||
build.Add('SDKROOT',EnvOptions.GetSDKName(ProjOptions.SDK, false));
|
||||
build.Add('FPC_COMPILER_PATH','"'+EnvOptions.CompilerPath+'"');
|
||||
build.Add('FPC_MAIN_FILE','"'+LazarusIDE.ActiveProject.MainFile.Filename+'"');
|
||||
opt :=
|
||||
' -XR'+EnvOptions.GetSDKFullPath(ProjOptions.SDK, false)+' ' +
|
||||
' -FD'+IncludeTrailingPathDelimiter(EnvOptions.PlatformsBaseDir)+'iPhoneOS.platform/Developer/usr/bin ' +
|
||||
EnvOptions.CommonOpt;
|
||||
optSim :=
|
||||
' -XR'+EnvOptions.GetSDKFullPath(ProjOptions.SDK, true)+' ' +
|
||||
' -FD'+IncludeTrailingPathDelimiter(EnvOptions.PlatformsBaseDir)+'iPhoneSimulator.platform/Developer/usr/bin ' +
|
||||
EnvOptions.CommonOpt;
|
||||
opt:='';
|
||||
|
||||
with LazarusIDE.ActiveProject.LazCompilerOptions do begin
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(OtherUnitFiles, '-Fu', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(IncludePath, '-Fi', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(ObjectPath, '-Fo', '\"');
|
||||
opt:=opt + ' ' +BreakPathsStringToOption(Libraries, '-Fl', '\"');
|
||||
optSim:=optSim + ' ' +BreakPathsStringToOption(OtherUnitFiles, '-Fu', '\"');
|
||||
optSim:=optSim + ' ' +BreakPathsStringToOption(IncludePath, '-Fi', '\"');
|
||||
optSim:=optSim + ' ' +BreakPathsStringToOption(ObjectPath, '-Fo', '\"');
|
||||
optSim:=optSim + ' ' +BreakPathsStringToOption(Libraries, '-Fl', '\"');
|
||||
end;
|
||||
|
||||
build.Add('FPC_CUSTOM_OPTIONS','"'+opt+'"');
|
||||
build.Add('"FPC_CUSTOM_OPTIONS[sdk=iphonesimulator*]"','"'+optSim+'"');
|
||||
|
||||
dir:=ResolveProjectPath('xcode');
|
||||
dir:=dir+'/';
|
||||
|
||||
name:=ExtractFileName(GetProjectExeName(LazarusIDE.ActiveProject));
|
||||
// not using executable name. It's driven by product name
|
||||
//exename:=ExtractFileName(GetProjectExeName(LazarusIDE.ActiveProject));
|
||||
//name:=exename;
|
||||
ForceDirectories(dir);
|
||||
WriteDefInfoList( dir + GetProjectPlistName(LazarusIDE.ActiveProject),
|
||||
name, name, Info);
|
||||
|
||||
FillBunldeInfo(false, Info);
|
||||
WriteDefInfoList( dir + plistname, tname, tname, Info);
|
||||
|
||||
|
||||
projname:=ExtractFileName(LazarusIDE.ActiveProject.MainFile.Filename);
|
||||
@ -417,32 +405,30 @@ begin
|
||||
proj:=TStringList.Create;
|
||||
templates:=nil;
|
||||
try
|
||||
if not FileExists(projname) then begin
|
||||
templates:=TStringList.Create;
|
||||
templates:=TStringList.Create;
|
||||
|
||||
if WriteIconTo( IncludeTrailingPathDelimiter(dir)+'Icon.png') then begin
|
||||
templates.Values['icon']:=XCodeProjectTemplateIcon;
|
||||
templates.Values['iconid']:=XCodeProjectTemplateIconID;
|
||||
templates.Values['iconfile']:=XCodeIconFile;
|
||||
templates.Values['iconfileref']:=XCodeIconFileRef;
|
||||
end else begin
|
||||
templates.Values['icon']:='';
|
||||
templates.Values['iconid']:='';
|
||||
templates.Values['iconfile']:='';
|
||||
templates.Values['iconfileref']:='';
|
||||
end;
|
||||
if WriteIconTo( IncludeTrailingPathDelimiter(dir)+'Icon.png') then begin
|
||||
templates.Values['icon']:=XCodeProjectTemplateIcon;
|
||||
templates.Values['iconid']:=XCodeProjectTemplateIconID;
|
||||
templates.Values['iconfile']:=XCodeIconFile;
|
||||
templates.Values['iconfileref']:=XCodeIconFileRef;
|
||||
end else begin
|
||||
templates.Values['icon']:='';
|
||||
templates.Values['iconid']:='';
|
||||
templates.Values['iconfile']:='';
|
||||
templates.Values['iconfileref']:='';
|
||||
end;
|
||||
|
||||
//todo:
|
||||
templates.Values['bundle']:=tname+'.app';
|
||||
templates.Values['plist']:=plistname;
|
||||
templates.Values['targetname']:=tname;
|
||||
templates.Values['productname']:=tname;
|
||||
//todo:
|
||||
templates.Values['bundle']:=tname+'.app';
|
||||
templates.Values['plist']:=plistname;
|
||||
templates.Values['targetname']:=tname; // Target and Product name must match
|
||||
templates.Values['productname']:=tname;
|
||||
templates.Values['mainfile']:=LazarusIDE.ActiveProject.MainFile.Filename;
|
||||
templates.Values['projoptions']:=opt;
|
||||
|
||||
proj.Text:=XCodeProjectTemplate;
|
||||
end else
|
||||
proj.LoadFromFile(projname);
|
||||
|
||||
PrepareTemplateFile(proj, templates, build);
|
||||
// Xcode project updated (/Users/dmitry/FPC_Laz/iphonelazext/tests/xcode/test_xcodetemplate.xcodeproj)
|
||||
PrepareTemplateFile(proj, templates);
|
||||
proj.SaveToFile(projname);
|
||||
except
|
||||
on e: exception do
|
||||
@ -453,7 +439,7 @@ begin
|
||||
templates.Free;
|
||||
build.Free;
|
||||
|
||||
IDEMessagesWindow.AddMsg(strXcodeUpdated, '', 0);
|
||||
IDEMessagesWindow.AddMsg(Format(strXcodeUpdated,[projdir]), '', 0);
|
||||
end;
|
||||
|
||||
procedure SimRunDirect;
|
||||
@ -496,15 +482,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{procedure TiPhoneExtension.isProjectClicked(Sender: TObject);
|
||||
begin
|
||||
if not Assigned(Sender) or not Assigned(LazarusIDE.ActiveProject) then Exit;
|
||||
TIDEMenuCommand(Sender).Checked:=not TIDEMenuCommand(Sender).Checked;
|
||||
ProjOptions.isiPhoneApp:=TIDEMenuCommand(Sender).Checked;
|
||||
ProjOptions.Save;
|
||||
end;}
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
// IDE integration is done in constructor
|
||||
|
@ -21,6 +21,7 @@ interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, IDEOptionsIntf, LazIDEIntf, ProjectIntf, MacroIntf,
|
||||
CompOptsIntf,
|
||||
iPhoneBundle, XMLConf, XcodeUtils, FileUtil, iphonesimctrl;
|
||||
|
||||
const
|
||||
@ -40,8 +41,11 @@ type
|
||||
fResourceDir : String;
|
||||
fExcludeMask : String;
|
||||
fMainNib : String;
|
||||
fResFiles : TStrings;
|
||||
public
|
||||
//constructor Create; override;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
class function GetGroupCaption: String; override;
|
||||
class function GetInstance: TAbstractIDEOptions; override;
|
||||
function Load: Boolean;
|
||||
@ -54,6 +58,7 @@ type
|
||||
property ResourceDir: String read fResourceDir write fResourceDir;
|
||||
property ExcludeMask: String read fExcludeMask write fExcludeMask;
|
||||
property MainNib: String read fMainNib write fMainNib;
|
||||
property ResFiles: TStrings read fResFiles;
|
||||
end;
|
||||
|
||||
{ TiPhoneEnvironmentOptions }
|
||||
@ -149,6 +154,7 @@ const
|
||||
optResourceDir = 'iPhone/ResourceDir';
|
||||
optExcludeMask = 'iPhone/ExcludeMask';
|
||||
optMainNib = 'iPhone/MainNib';
|
||||
optResFiles = 'iPhone/ResFiles';
|
||||
|
||||
function EnvOptions: TiPhoneEnvironmentOptions;
|
||||
begin
|
||||
@ -403,14 +409,22 @@ begin
|
||||
fAppID:='com.mycompany.myapplication';
|
||||
fSpaceName:='';
|
||||
DataWritten:=false;
|
||||
fResFiles.Clear;
|
||||
end;
|
||||
|
||||
constructor TiPhoneProjectOptions.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
fResFiles := TStringList.Create;
|
||||
Reset;
|
||||
end;
|
||||
|
||||
destructor TiPhoneProjectOptions.Destroy;
|
||||
begin
|
||||
fResFiles.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class function TiPhoneProjectOptions.GetGroupCaption: String;
|
||||
begin
|
||||
Result:='iPhone';
|
||||
@ -435,24 +449,42 @@ begin
|
||||
else fResourceDir:=DefaultResourceDir;
|
||||
if CustomData.Contains(optExcludeMask) then fExcludeMask:=CustomData.Values[optExcludeMask];
|
||||
if CustomData.Contains(optMainNib) then fMainNib:=CustomData.Values[optMainNib];
|
||||
if CustomData.Contains(optResFiles) then ResFiles.Text:=CustomData.Values[optResFiles];
|
||||
end;
|
||||
end;
|
||||
|
||||
function TiPhoneProjectOptions.Save: Boolean;
|
||||
const
|
||||
BoolStr : array[Boolean] of String = ('false', 'true');
|
||||
var
|
||||
modflag: Boolean;
|
||||
begin
|
||||
Result:=True;
|
||||
{do not write iPhone related info to non-iPhone projects}
|
||||
if DataWritten or fisiPhone then
|
||||
with LazarusIDE.ActiveProject do begin
|
||||
CustomData.Values[optisIPhone] := BoolStr[fisiPhone];
|
||||
CustomData.Values[optSDK]:=fSDK;
|
||||
CustomData.Values[optAppID]:=fAppID;
|
||||
CustomData.Values[optSpaceName]:=fSpaceName;
|
||||
CustomData.Values[optResourceDir]:=fResourceDir;
|
||||
CustomData.Values[optExcludeMask]:=fExcludeMask;
|
||||
CustomData.Values[optMainNib]:=fMainNib;
|
||||
|
||||
modflag:=false;
|
||||
modflag:=(CustomData.Values[optisIPhone] <> BoolStr[fisiPhone])
|
||||
or (CustomData.Values[optSDK]<>fSDK)
|
||||
or (CustomData.Values[optAppID]<>fAppID)
|
||||
or (CustomData.Values[optSpaceName]<>fSpaceName)
|
||||
or (CustomData.Values[optResourceDir]<>fResourceDir)
|
||||
or (CustomData.Values[optExcludeMask]<>fExcludeMask)
|
||||
or (CustomData.Values[optMainNib]<>fMainNib)
|
||||
or (CustomData.Values[optResFiles]<>ResFiles.Text);
|
||||
|
||||
if modflag then begin
|
||||
LazarusIDE.ActiveProject.Modified:=true;
|
||||
CustomData.Values[optisIPhone] := BoolStr[fisiPhone];
|
||||
CustomData.Values[optSDK]:=fSDK;
|
||||
CustomData.Values[optAppID]:=fAppID;
|
||||
CustomData.Values[optSpaceName]:=fSpaceName;
|
||||
CustomData.Values[optResourceDir]:=fResourceDir;
|
||||
CustomData.Values[optExcludeMask]:=fExcludeMask;
|
||||
CustomData.Values[optMainNib]:=fMainNib;
|
||||
CustomData.Values[optResFiles]:=ResFiles.Text;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -30,7 +30,7 @@ resourcestring
|
||||
strPtrOptAppID = 'Application ID';
|
||||
strPtrOptAppIDHint = 'It''s recommended by Apple to use domain-structured identifier i.e. "com.mycompany.myApplication"';
|
||||
|
||||
strXcodeUpdated = 'Xcode project updated';
|
||||
strXcodeUpdated = 'Xcode project updated (%s)';
|
||||
|
||||
strWNoSDKSelected = 'Warning: SDK is not selected using %s';
|
||||
strWNoSDK = 'Warning: No SDK available. Linking might fail.';
|
||||
|
@ -1,12 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<Package Version="4">
|
||||
<Name Value="iphonelazext"/>
|
||||
<AddToProjectUsesSection Value="True"/>
|
||||
<Type Value="DesignTime"/>
|
||||
<Author Value="Dmitry 'skalogryz' Boyarintsev"/>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<SearchPaths>
|
||||
<OtherUnitFiles Value="pbx"/>
|
||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Parsing>
|
||||
@ -16,15 +17,15 @@
|
||||
</Parsing>
|
||||
<Other>
|
||||
<CompilerMessages>
|
||||
<IgnoredMessages idx4055="True" idx4079="True" idx4080="True" idx4081="True" idx5024="True" idx5057="True" idx5060="True"/>
|
||||
<IgnoredMessages idx5091="True" idx5060="True" idx5057="True" idx5024="True" idx4081="True" idx4080="True" idx4079="True" idx4055="True"/>
|
||||
</CompilerMessages>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
<CustomOptions Value="-Sm -dPACKAGE_PATH:='$(PkgDir)'"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Description Value="iPhone Development Lazarus extension"/>
|
||||
<License Value="LGPL"/>
|
||||
<Version Minor="7"/>
|
||||
<Files Count="14">
|
||||
<Version Minor="8"/>
|
||||
<Files Count="21">
|
||||
<Item1>
|
||||
<Filename Value="ideext.pas"/>
|
||||
<HasRegisterProc Value="True"/>
|
||||
@ -68,22 +69,52 @@
|
||||
</Item10>
|
||||
<Item11>
|
||||
<Filename Value="lazfilesutils.pas"/>
|
||||
<UnitName Value="lazfilesutils"/>
|
||||
<UnitName Value="LazFilesUtils"/>
|
||||
</Item11>
|
||||
<Item12>
|
||||
<Filename Value="xcodeutils.pas"/>
|
||||
<UnitName Value="xcodeutils"/>
|
||||
<UnitName Value="XcodeUtils"/>
|
||||
</Item12>
|
||||
<Item13>
|
||||
<Filename Value="newxibdialog.pas"/>
|
||||
<UnitName Value="newxibdialog"/>
|
||||
<UnitName Value="newXibDialog"/>
|
||||
</Item13>
|
||||
<Item14>
|
||||
<Filename Value="xibfile.pas"/>
|
||||
<UnitName Value="xibfile"/>
|
||||
</Item14>
|
||||
<Item15>
|
||||
<Filename Value="pbx/pbxcontainer.pas"/>
|
||||
<AddToUsesPkgSection Value="False"/>
|
||||
<UnitName Value="pbxcontainer"/>
|
||||
</Item15>
|
||||
<Item16>
|
||||
<Filename Value="pbx/pbxfile.pas"/>
|
||||
<AddToUsesPkgSection Value="False"/>
|
||||
<UnitName Value="pbxfile"/>
|
||||
</Item16>
|
||||
<Item17>
|
||||
<Filename Value="pbx/xcodeproj.pas"/>
|
||||
<AddToUsesPkgSection Value="False"/>
|
||||
<UnitName Value="xcodeproj"/>
|
||||
</Item17>
|
||||
<Item18>
|
||||
<Filename Value="plistfile.pas"/>
|
||||
<UnitName Value="PlistFile"/>
|
||||
</Item18>
|
||||
<Item19>
|
||||
<Filename Value="pbx/xcodeprojutils.pas"/>
|
||||
<UnitName Value="xcodeprojutils"/>
|
||||
</Item19>
|
||||
<Item20>
|
||||
<Filename Value="iphonesimctrl.pas"/>
|
||||
<UnitName Value="iphonesimctrl"/>
|
||||
</Item20>
|
||||
<Item21>
|
||||
<Filename Value="res/buildscript.sh"/>
|
||||
<Type Value="Text"/>
|
||||
</Item21>
|
||||
</Files>
|
||||
<Type Value="DesignTime"/>
|
||||
<RequiredPkgs Count="3">
|
||||
<Item1>
|
||||
<PackageName Value="LCL"/>
|
||||
|
@ -10,7 +10,7 @@ uses
|
||||
ideext, iPhoneExtStr, iPhoneBundle, XCodeProject,
|
||||
environment_iphone_options, project_iphone_options, iPhoneExtOptions,
|
||||
xcodetemplate, LazFilesUtils, XcodeUtils, newXibDialog, xibfile, PlistFile,
|
||||
LazarusPackageIntf;
|
||||
xcodeprojutils, iphonesimctrl, LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -25,7 +25,8 @@ uses
|
||||
|
||||
function ResolveProjectPath(const path: string; project: TLazProject = nil): string;
|
||||
|
||||
function BreakPathsStringToOption(const Paths, Switch: String; const Quotes: string = '"'; project: TLazProject = nil): String;
|
||||
function BreakPathsStringToOption(const Paths, Switch: String;
|
||||
const Quotes: string = '"'; project: TLazProject = nil; AResolvePath: Boolean = false): String;
|
||||
|
||||
function RelativeToFullPath(const BasePath, Relative: string): String;
|
||||
function NeedQuotes(const path: string): Boolean;
|
||||
@ -152,7 +153,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function BreakPathsStringToOption(const Paths, Switch, Quotes: String; project: TLazProject): String;
|
||||
function BreakPathsStringToOption(const Paths, Switch, Quotes: String; project: TLazProject; AResolvePath: Boolean): String;
|
||||
var
|
||||
i, j : Integer;
|
||||
fixed : String;
|
||||
@ -168,7 +169,7 @@ begin
|
||||
if Paths[i]=';' then begin
|
||||
fixed:=Trim(Copy(paths,j, i-j) );
|
||||
if fixed<>'' then begin
|
||||
fixed:=ResolveProjectPath(fixed, project);
|
||||
if AResolvePath then fixed:=ResolveProjectPath(fixed, project);
|
||||
Result:=Result+' ' + Switch + QuoteStrIfNeeded(fixed, quotes);
|
||||
end;
|
||||
j:=i+1;
|
||||
@ -176,7 +177,7 @@ begin
|
||||
|
||||
fixed:=Trim(Copy(paths,j, length(paths)-j+1) );
|
||||
if fixed<>'' then begin
|
||||
fixed:=ResolveProjectPath(fixed, project);
|
||||
if AResolvePath then fixed:=ResolveProjectPath(fixed, project);
|
||||
Result:=Result+' ' + Switch + QuoteStrIfNeeded(fixed, quotes);
|
||||
end;
|
||||
end;
|
||||
|
@ -85,10 +85,14 @@ type
|
||||
TPBXKeyValue = class(TFPHashObjectList)
|
||||
protected
|
||||
function AddVal(const name: string; atype: TPBXValueType): TPBXValue;
|
||||
function GetValStr(const name: string): string;
|
||||
procedure AddValStr(const name, avalue: string);
|
||||
public
|
||||
function AddStr(const name: string; const avalue: string = ''): TPBXValue;
|
||||
function AddStrArray(const name: string): TPBXValue;
|
||||
function AddKeyVal(const name: string): TPBXValue;
|
||||
// it must be "public, not published"
|
||||
property Str[const name: string]: string read GetValStr write AddValStr;
|
||||
end;
|
||||
|
||||
TPBXFileInfo = record
|
||||
@ -135,10 +139,16 @@ procedure PBXWriteStrArray( w: TPBXWriter; list: TPBXStringArray );
|
||||
procedure PBXWriteKeyValue( w: TPBXWriter; kv: TPBXKeyValue );
|
||||
procedure PBXWriteObj(pbx: PBXObject; w: TPBXWriter; WriteEmpty: TStrings);
|
||||
|
||||
{ assigns reference IDs to each object in the list. "ID" is 24 charactewr long hex-string }
|
||||
procedure PBXAssignRef(list: TList);
|
||||
|
||||
{ Returns the list of objects that should populate the "objects" section of pbx file }
|
||||
procedure PBXGatherObjects(obj: TObject; srz: TList);
|
||||
|
||||
procedure PBXKeyValsCopy(src, dst: TPBXKeyValue);
|
||||
procedure PBXValueCopy(src, dst: TPBXValue);
|
||||
procedure PBXStringArrayCopy(src, dst: TPBXStringArray);
|
||||
|
||||
implementation
|
||||
|
||||
var
|
||||
@ -170,6 +180,48 @@ begin
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
procedure PBXStringArrayCopy(src, dst: TPBXStringArray);
|
||||
begin
|
||||
if not Assigned(src) or not Assigned(dst) then Exit;
|
||||
src.Assign(dst);
|
||||
end;
|
||||
|
||||
procedure PBXValueCopy(src, dst: TPBXValue);
|
||||
var
|
||||
dv : TPBXValue;
|
||||
begin
|
||||
if not Assigned(src) or not Assigned(dst) then Exit;
|
||||
dst.valType:=src.valType;
|
||||
case dst.valType of
|
||||
vtString: dst.str:=src.str;
|
||||
vtArrayOfStr: begin
|
||||
if not Assigned(dst.arr) then dst.arr:=TPBXStringArray.Create;
|
||||
PBXStringArrayCopy(src.arr, dst.arr);
|
||||
end;
|
||||
vtKeyVal: begin
|
||||
if not Assigned(dst.keyval) then dst.keyval:=TPBXKeyValue.Create(true);
|
||||
PBXKeyValsCopy(src.keyval, dst.keyval);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure PBXKeyValsCopy(src, dst: TPBXKeyValue);
|
||||
var
|
||||
svl : TPBXValue;
|
||||
nm : string;
|
||||
i : Integer;
|
||||
dvl : TPBXValue;
|
||||
begin
|
||||
if not Assigned(src) or not Assigned(dst) then Exit;
|
||||
for i:=0 to src.Count-1 do begin
|
||||
nm:=src.NameOfIndex(i);
|
||||
svl:=TPBXValue(src.Items[i]);
|
||||
dvl:=dst.AddVal(nm, svl.valType);
|
||||
PBXValueCopy(svl, dvl);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TestContainer(const buf: string);
|
||||
var
|
||||
c : TPBXContainer;
|
||||
@ -215,6 +267,11 @@ end;
|
||||
|
||||
{ TPBXKeyValue }
|
||||
|
||||
procedure TPBXKeyValue.AddValStr(const name, AValue: string);
|
||||
begin
|
||||
AddStr(name, Avalue);
|
||||
end;
|
||||
|
||||
function TPBXKeyValue.AddVal(const name: string; atype: TPBXValueType): TPBXValue;
|
||||
begin
|
||||
Result:=TPBXValue.Create;
|
||||
@ -226,6 +283,16 @@ begin
|
||||
Add(name, Result);
|
||||
end;
|
||||
|
||||
function TPBXKeyValue.GetValStr(const name: string): string;
|
||||
var
|
||||
vl : TPBXValue;
|
||||
begin
|
||||
vl:=TPBXValue(Self.Find(name));
|
||||
if not Assigned(vl)
|
||||
then Result:=''
|
||||
else Result:=vl.str;
|
||||
end;
|
||||
|
||||
function TPBXKeyValue.AddStr(const name: string; const avalue: string): TPBXValue;
|
||||
begin
|
||||
Result:=AddVal(name, vtString);
|
||||
@ -242,6 +309,7 @@ begin
|
||||
Result:=AddVal(name, vtKeyVal);
|
||||
end;
|
||||
|
||||
|
||||
{ TPBXReref }
|
||||
|
||||
constructor TPBXReref.Create(ainstance: TObject; const apropname, aref: string);
|
||||
@ -666,8 +734,8 @@ begin
|
||||
vl:=IntToStr(GetInt64Prop(pbx, p^[i]));
|
||||
isstr:=(vl<>'') or (WriteEmpty.indexOf(nm)>=0);
|
||||
end else if p^[i].PropType.Kind = tkBool then begin
|
||||
vl:=IntToStr(GetOrdProp(pbx, p^[i]));
|
||||
isstr:=true;
|
||||
isstr:=PtrUInt(p^[i].Default)<>PtrUInt(p^[i].GetProc);
|
||||
if isstr then vl:=IntToStr(GetOrdProp(pbx, p^[i]));
|
||||
end;
|
||||
|
||||
if isstr then begin
|
||||
|
@ -17,7 +17,8 @@ interface
|
||||
* {} - is an object (just like json) *
|
||||
* escaping characters with C-style escaping: *
|
||||
* * quotes (") *
|
||||
* * line breaks (note OSX is typically using \n, unline Unix \r) *
|
||||
* * line breaks (note OSX is typically using \n, unlike Unix \r) *
|
||||
* *
|
||||
* *
|
||||
* PBXScanner - scans through the file *
|
||||
* PBXParser - parses the file, returning a higher level entities of the file: *
|
||||
@ -177,6 +178,7 @@ var
|
||||
i : Integer;
|
||||
k : Integer;
|
||||
begin
|
||||
Result:='';
|
||||
k:=0;
|
||||
for i:=1 to length(v) do begin
|
||||
if not (v[i] in IdentName) then begin
|
||||
@ -435,6 +437,7 @@ begin
|
||||
LastComment:='';
|
||||
Name:='';
|
||||
Value:='';
|
||||
Result:=etError;
|
||||
case fState of
|
||||
stInit :
|
||||
case scanner.FetchToken of
|
||||
@ -700,6 +703,7 @@ var
|
||||
lvl : Integer;
|
||||
tk : TPBXEntity;
|
||||
begin
|
||||
Result:=false;
|
||||
if not Assigned(p) then Exit;
|
||||
lvl:=p.Level;
|
||||
while (p.Level>=lvl) do begin
|
||||
|
@ -17,10 +17,15 @@ unit xcodeproj;
|
||||
* * any objects within key-value tables are freed *
|
||||
* Alternative solution - implement ref counting! *
|
||||
* *
|
||||
* PBXShellScriptBuildPhase - the give script must be using MacOS line breaks *
|
||||
* which are \n (#13). Using unix line breaks \r (#10) will cause issues *
|
||||
* in Xcode. *
|
||||
--------------------------------------------------------------------------------}
|
||||
|
||||
interface
|
||||
|
||||
{$ifdef fpc}{$mode delphi}{$endif}
|
||||
|
||||
uses
|
||||
Classes, SysUtils,
|
||||
typinfo, pbxcontainer;
|
||||
@ -49,10 +54,16 @@ type
|
||||
fdefaultConfigurationIsVisible: string;
|
||||
fdefaultConfigurationName: string;
|
||||
fbuildConfigurations: TPBXObjectsList;
|
||||
|
||||
function GetConfigItem(i: integer): XCBuildConfiguration;
|
||||
function GetCount: integer;
|
||||
public
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
function addConfig(const aname: string): XCBuildConfiguration;
|
||||
// Count and Items are just for convenience. MUST NOT BE in "published" section
|
||||
property Count: integer read GetCount;
|
||||
property Items[i: integer]: XCBuildConfiguration read GetConfigItem; default;
|
||||
published
|
||||
property buildConfigurations: TPBXObjectsList read fbuildConfigurations;
|
||||
property defaultConfigurationIsVisible: string read fdefaultConfigurationIsVisible write fdefaultConfigurationIsVisible;
|
||||
@ -76,17 +87,19 @@ type
|
||||
|
||||
{ PBXFileReference }
|
||||
|
||||
// these files might not be physically present in for the project.
|
||||
// i.e. a bundle .app file doesn't physically exists until it's actual "built" by the xcode
|
||||
PBXFileReference = class(PBXObject)
|
||||
private
|
||||
FexplicitFileType: string;
|
||||
FincludeInIndex: string;
|
||||
FincludeInIndex: Boolean;
|
||||
FlastKnownFileType: string;
|
||||
Fname: string;
|
||||
Fpath: string;
|
||||
FsourceTree: string;
|
||||
published
|
||||
property explicitFileType: string read FexplicitFileType write FexplicitFileType;
|
||||
property includeInIndex: string read FincludeInIndex write FincludeInIndex;
|
||||
property includeInIndex: Boolean read FincludeInIndex write FincludeInIndex;
|
||||
property lastKnownFileType: string read flastKnownFileType write flastKnownFileType;
|
||||
property name: string read Fname write Fname;
|
||||
property path: string read Fpath write Fpath;
|
||||
@ -135,6 +148,7 @@ type
|
||||
foutputPaths: TPBXStringArray;
|
||||
fshellpath: string;
|
||||
fshellScript: string;
|
||||
fshowEnvVarsInLog: Boolean;
|
||||
public
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
@ -143,6 +157,7 @@ type
|
||||
property outputPaths: TPBXStringArray read foutputPaths;
|
||||
property shellPath: string read fshellpath write fshellPath;
|
||||
property shellScript: string read fshellScript write fshellScript;
|
||||
property showEnvVarsInLog: Boolean read fshowEnvVarsInLog write fshowEnvVarsInLog default true;
|
||||
end;
|
||||
|
||||
{ PBXGroup }
|
||||
@ -197,10 +212,27 @@ type
|
||||
property dependencies: TPBXObjectsList read fdependencies;
|
||||
property name: string read fname write fname;
|
||||
property productName: string read fproductName write fproductName; // = ttestGame;
|
||||
property productReference: PBXObject read fproductReference write fproductReference; // = 0AFA6EAD19F60EFE004C8FD9 /* ttestGame.app */;
|
||||
property productReference: PBXObject read fproductReference write fproductReference; // producut resulting file
|
||||
property productType: string read fproductType write fproductType; // = "com.apple.product-type.application";
|
||||
end;
|
||||
|
||||
{ PBXLegacyTarget }
|
||||
|
||||
PBXLegacyTarget = class(PBXObject)
|
||||
private
|
||||
fpassBuildSettingsInEnvironment : Boolean;
|
||||
fbuildArgumentsString : string;
|
||||
fbuildToolPath : string;
|
||||
fbuildWorkingDirectory : string;
|
||||
public
|
||||
constructor Create; override;
|
||||
published
|
||||
property buildArgumentsString: string read fbuildArgumentsString write fbuildArgumentsString;
|
||||
property buildToolPath: string read fbuildToolPath write fbuildToolPath;
|
||||
property buildWorkingDirectory: string read fbuildWorkingDirectory write fbuildWorkingDirectory;
|
||||
property passBuildSettingsInEnvironment: Boolean read fpassBuildSettingsInEnvironment write fpassBuildSettingsInEnvironment;
|
||||
end;
|
||||
|
||||
{ PBXTargetDependency }
|
||||
|
||||
// mmgt:
|
||||
@ -285,19 +317,28 @@ const
|
||||
//FILETYPE_SCRIPT = 'text.script.sh';
|
||||
FILETYPE_EXEC = 'compiled.mach-o.executable';
|
||||
FILETYPE_MACHO = FILETYPE_EXEC;
|
||||
FILETYPE_BUNDLE = 'wrapper.application';
|
||||
FILETYPE_PLIST = 'text.plist.xml';
|
||||
FILETYPE_OBJC = 'sourcecode.c.objc';
|
||||
|
||||
function FileRefCreate(const afilename: string; const filetype: string = ''): PBXFileReference;
|
||||
|
||||
const
|
||||
GROUPSRC_ABSOLUTE = '<absolute>';
|
||||
GROUPSRC_GROUP = '<group>';
|
||||
SRCTREE_ABSOLUTE = '<absolute>'; // path is absolute path
|
||||
SRCTREE_GROUP = '<group>'; // path is relative to the parent group
|
||||
SRCTREE_PRODUCT = 'BUILT_PRODUCTS_DIR'; // path is relative to the product build directory
|
||||
SRCTREE_PROJECT = 'SOURCE_ROOT'; // path is relative for .xcodeproj directory location
|
||||
SRCTREE_DEV = 'DEVELOPER_DIR'; // path is relative to developer dir
|
||||
SRCTREE_SDK = 'SDKROOT'; // path is relative to selected SDK dir
|
||||
|
||||
function GroupCreate(const aname: string; const srcTree: string = GROUPSRC_GROUP): PBXGroup;
|
||||
function GroupCreate(const aname: string; const srcTree: string = SRCTREE_GROUP): PBXGroup;
|
||||
//todo: need a rountine to update the path whenever the project is saved
|
||||
function GroupCreateRoot(const projectfolder: string = ''): PBXGroup;
|
||||
|
||||
const
|
||||
PRODTYPE_TOOL = 'com.apple.product-type.tool';
|
||||
PRODTYPE_APP = 'com.apple.product-type.application'; // use it for OSX / iOS app targets
|
||||
// prodtype of app type should have productReference to the result bundle! (.app) file
|
||||
|
||||
//
|
||||
// PBXSourcesBuildPhase (sources) - is part of a PBXNativeTarget
|
||||
@ -309,9 +350,38 @@ const
|
||||
//0AA67B671A04929900CF0DD7 /* CopyFiles */,
|
||||
//);
|
||||
|
||||
const
|
||||
TARGET_IOS_8_0 = '8.0';
|
||||
TARGET_IOS_8_1 = '8.1';
|
||||
|
||||
procedure ConfigIOS(cfg: XCBuildConfiguration; const targetiOS: string);
|
||||
|
||||
const
|
||||
CFG_SDKROOT = 'SDKROOT';
|
||||
CFG_IOSTRG = 'IPHONEOS_DEPLOYMENT_TARGET';
|
||||
CFG_DEVICE = 'TARGET_DEVICE_FAMILY';
|
||||
CFG_DEVICE_ALL = '1,2';
|
||||
CFG_DEVICE_IPHONE = '1';
|
||||
CFG_DEVICE_IPAD = '2';
|
||||
|
||||
implementation
|
||||
|
||||
procedure ConfigIOS(cfg: XCBuildConfiguration; const targetiOS: string);
|
||||
begin
|
||||
if not Assigned(cfg) then Exit;
|
||||
cfg.buildSettings.AddStr(CFG_IOSTRG, targetiOS);
|
||||
cfg.buildSettings.AddStr(CFG_SDKROOT, 'iphoneos');
|
||||
cfg.buildSettings.AddStr(CFG_DEVICE, CFG_DEVICE_ALL);
|
||||
end;
|
||||
|
||||
{ PBXLegacyTarget }
|
||||
|
||||
constructor PBXLegacyTarget.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
fpassBuildSettingsInEnvironment:=true;
|
||||
end;
|
||||
|
||||
{ PBXTargetDependency }
|
||||
|
||||
destructor PBXTargetDependency.Destroy;
|
||||
@ -388,12 +458,22 @@ begin
|
||||
targets.Add(Result);
|
||||
Result._headerComment:=aname;
|
||||
Result.name:=aname;
|
||||
// productName?
|
||||
// productReference - is a resulting file
|
||||
Result.productName:=aname;
|
||||
end;
|
||||
|
||||
{ XCConfigurationList }
|
||||
|
||||
function XCConfigurationList.GetConfigItem(i: integer): XCBuildConfiguration;
|
||||
begin
|
||||
if (i<0) or (i>=fbuildConfigurations.Count) then Result:=nil
|
||||
else Result:=XCBuildConfiguration(fbuildConfigurations[i]);
|
||||
end;
|
||||
|
||||
function XCConfigurationList.GetCount: integer;
|
||||
begin
|
||||
Result:=fbuildConfigurations.Count;
|
||||
end;
|
||||
|
||||
constructor XCConfigurationList.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
@ -406,7 +486,8 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function XCConfigurationList.AddConfig(const aname: string): XCBuildConfiguration;
|
||||
function XCConfigurationList.addConfig(const aname: string
|
||||
): XCBuildConfiguration;
|
||||
begin
|
||||
Result:=XCBuildConfiguration.Create;
|
||||
Result.name:=aname;
|
||||
@ -448,7 +529,7 @@ begin
|
||||
fchildren.Add(Result);
|
||||
Result.name:=aname;
|
||||
Result._headerComment:=aname;
|
||||
Result.sourceTree:=GROUPSRC_GROUP;
|
||||
Result.sourceTree:=SRCTREE_GROUP;
|
||||
end;
|
||||
|
||||
function PBXGroup.findGroup(const aname: string): PBXGroup;
|
||||
@ -536,7 +617,7 @@ begin
|
||||
p.buildConfigurationList._headerComment:='Build configuration list for PBXProject';
|
||||
p.buildConfigurationList.defaultConfigurationIsVisible:='0';
|
||||
|
||||
cfg:=p.buildConfigurationList.addConfig('Default');
|
||||
cfg:=p.buildConfigurationList.addConfig('Debug');
|
||||
cfg:=p.buildConfigurationList.addConfig('Release');
|
||||
// default name must be present
|
||||
p.buildConfigurationList.defaultConfigurationName:='Release';
|
||||
@ -609,7 +690,7 @@ end;
|
||||
|
||||
function GroupCreateRoot(const projectfolder: string): PBXGroup;
|
||||
begin
|
||||
Result:=GroupCreate('', GROUPSRC_ABSOLUTE);
|
||||
Result:=GroupCreate('', SRCTREE_GROUP);
|
||||
Result.path:=projectfolder;
|
||||
Result._headerComment:=projectfolder;
|
||||
end;
|
||||
|
55
components/iphonelazext/pbx/xcodeprojutils.pas
Normal file
55
components/iphonelazext/pbx/xcodeprojutils.pas
Normal file
@ -0,0 +1,55 @@
|
||||
unit xcodeprojutils;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, xcodeproj;
|
||||
|
||||
// proj name is used for ".xcodeprj" bundle-directory
|
||||
// hostdir is the hosting directory for the project
|
||||
// prj - the content of the project
|
||||
function ProjectWriteStruct(prj: PBXProject; const projName: string; const HostDir: string): Boolean;
|
||||
|
||||
const
|
||||
ProjExt = '.xcodeproj';
|
||||
ProjFileName = 'project.pbxproj';
|
||||
|
||||
implementation
|
||||
|
||||
function ProjectWriteStruct(prj: PBXProject; const projName: string; const HostDir: string): Boolean;
|
||||
var
|
||||
prjdir : string;
|
||||
s : string;
|
||||
fs : TFileStream;
|
||||
fn : string;
|
||||
begin
|
||||
if HostDir = ''
|
||||
then prjdir:=IncludeTrailingPathDelimiter(GetCurrentDir)+projName+ProjExt
|
||||
else prjdir:=IncludeTrailingPathDelimiter(HostDir)+projName+ProjExt;
|
||||
|
||||
Result:=ForceDirectories(prjdir);
|
||||
if not Result then Exit;
|
||||
fn:=IncludeTrailingPathDelimiter(prjdir)+ProjFileName;
|
||||
|
||||
s:=ProjectWrite(prj);
|
||||
|
||||
try
|
||||
fs:=TFileStream.Create(fn, fmCreate);
|
||||
try
|
||||
if length(s)>0 then begin
|
||||
fs.Write(s[1], length(s));
|
||||
fs.Size:=length(s);
|
||||
end;
|
||||
Result:=true;
|
||||
finally
|
||||
fs.Free;
|
||||
end;
|
||||
except
|
||||
Result:=false;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -1,57 +1,59 @@
|
||||
inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
Height = 474
|
||||
Width = 620
|
||||
ClientHeight = 474
|
||||
ClientWidth = 620
|
||||
object iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
Left = 0
|
||||
Height = 466
|
||||
Top = 0
|
||||
Width = 598
|
||||
ClientHeight = 466
|
||||
ClientWidth = 598
|
||||
OnClick = FrameClick
|
||||
TabOrder = 0
|
||||
DesignLeft = 513
|
||||
DesignTop = 97
|
||||
object chkisPhone: TCheckBox[0]
|
||||
DesignLeft = 408
|
||||
DesignTop = 201
|
||||
object chkisPhone: TCheckBox
|
||||
Left = 16
|
||||
Height = 18
|
||||
Top = 16
|
||||
Width = 199
|
||||
Width = 191
|
||||
Caption = 'is iPhone application project'
|
||||
OnChange = chkisPhoneChange
|
||||
TabOrder = 0
|
||||
end
|
||||
object lblAppID: TLabel[1]
|
||||
object lblAppID: TLabel
|
||||
Left = 16
|
||||
Height = 18
|
||||
Height = 16
|
||||
Top = 88
|
||||
Width = 87
|
||||
Width = 89
|
||||
Caption = 'Application ID'
|
||||
ParentColor = False
|
||||
end
|
||||
object edtAppID: TEdit[2]
|
||||
object edtAppID: TEdit
|
||||
Left = 112
|
||||
Height = 22
|
||||
Top = 85
|
||||
Width = 490
|
||||
Width = 468
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
TabOrder = 1
|
||||
Text = 'com.mycompany.myapp'
|
||||
end
|
||||
object lblAppIDHint: TLabel[3]
|
||||
object lblAppIDHint: TLabel
|
||||
Left = 16
|
||||
Height = 14
|
||||
Height = 12
|
||||
Top = 117
|
||||
Width = 493
|
||||
Width = 497
|
||||
Caption = 'It''s recommended by Apple to use domain-structured name, i.e. com.mycompany.myApplication as ID'
|
||||
Font.Height = -10
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object lblSDKVer: TLabel[4]
|
||||
object lblSDKVer: TLabel
|
||||
Left = 16
|
||||
Height = 18
|
||||
Height = 16
|
||||
Top = 51
|
||||
Width = 80
|
||||
Width = 79
|
||||
Caption = 'SDK version:'
|
||||
ParentColor = False
|
||||
end
|
||||
object cmbSDKs: TComboBox[5]
|
||||
object cmbSDKs: TComboBox
|
||||
Left = 112
|
||||
Height = 20
|
||||
Top = 48
|
||||
@ -61,12 +63,12 @@ inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
Style = csDropDownList
|
||||
TabOrder = 2
|
||||
end
|
||||
object edtResDir: TEdit[6]
|
||||
object edtResDir: TEdit
|
||||
AnchorSideRight.Control = btnShowInFinder
|
||||
Left = 120
|
||||
Height = 22
|
||||
Top = 174
|
||||
Width = 355
|
||||
Width = 332
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
BorderSpacing.Right = 10
|
||||
OnChange = edtResDirChange
|
||||
@ -74,56 +76,56 @@ inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
TabOrder = 3
|
||||
Text = 'Resources'
|
||||
end
|
||||
object Label1: TLabel[7]
|
||||
object Label1: TLabel
|
||||
Left = 16
|
||||
Height = 18
|
||||
Height = 16
|
||||
Top = 176
|
||||
Width = 89
|
||||
Caption = 'Resources dir:'
|
||||
ParentColor = False
|
||||
end
|
||||
object edtExclude: TEdit[8]
|
||||
object edtExclude: TEdit
|
||||
Left = 120
|
||||
Height = 22
|
||||
Top = 224
|
||||
Width = 482
|
||||
Width = 460
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
OnChange = edtExcludeChange
|
||||
TabOrder = 4
|
||||
Text = '.svn'
|
||||
end
|
||||
object Label2: TLabel[9]
|
||||
object Label2: TLabel
|
||||
Left = 16
|
||||
Height = 18
|
||||
Height = 16
|
||||
Top = 224
|
||||
Width = 81
|
||||
Width = 82
|
||||
Caption = 'Ignore mask:'
|
||||
ParentColor = False
|
||||
end
|
||||
object Label3: TLabel[10]
|
||||
object Label3: TLabel
|
||||
Left = 16
|
||||
Height = 14
|
||||
Height = 12
|
||||
Top = 200
|
||||
Width = 364
|
||||
Width = 359
|
||||
Caption = 'It''s recommended to set resource dir as a relative (to project .lpr file) path'
|
||||
Font.Height = -10
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object Label4: TLabel[11]
|
||||
object Label4: TLabel
|
||||
Left = 16
|
||||
Height = 18
|
||||
Height = 16
|
||||
Top = 256
|
||||
Width = 54
|
||||
Width = 56
|
||||
Caption = 'Nib files:'
|
||||
ParentColor = False
|
||||
end
|
||||
object nibFilesBox: TCheckListBox[12]
|
||||
object nibFilesBox: TCheckListBox
|
||||
Left = 120
|
||||
Height = 180
|
||||
Height = 76
|
||||
Top = 256
|
||||
Width = 482
|
||||
Anchors = [akTop, akLeft, akRight, akBottom]
|
||||
Width = 460
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
ItemHeight = 0
|
||||
OnClickCheck = nibFilesBoxClickCheck
|
||||
OnItemClick = nibFilesBoxItemClick
|
||||
@ -132,54 +134,71 @@ inherited iPhoneProjectOptionsEditor: TiPhoneProjectOptionsEditor
|
||||
PopupMenu = nibsPopup
|
||||
TabOrder = 5
|
||||
end
|
||||
object Label5: TLabel[13]
|
||||
object Label5: TLabel
|
||||
AnchorSideTop.Control = nibFilesBox
|
||||
AnchorSideTop.Side = asrBottom
|
||||
Left = 120
|
||||
Height = 14
|
||||
Top = 436
|
||||
Width = 246
|
||||
Height = 12
|
||||
Top = 332
|
||||
Width = 247
|
||||
Caption = 'The checked one is the main Nib of the application'
|
||||
Font.Height = -10
|
||||
ParentColor = False
|
||||
ParentFont = False
|
||||
end
|
||||
object btnShowInFinder: TButton[14]
|
||||
Left = 485
|
||||
object btnShowInFinder: TButton
|
||||
Left = 462
|
||||
Height = 20
|
||||
Top = 176
|
||||
Width = 117
|
||||
Width = 118
|
||||
Anchors = [akTop, akRight]
|
||||
AutoSize = True
|
||||
Caption = 'Show in Finder'
|
||||
OnClick = btnShowInFinderClick
|
||||
TabOrder = 6
|
||||
end
|
||||
object btnAddXib: TButton[15]
|
||||
object btnAddXib: TButton
|
||||
AnchorSideLeft.Control = btnRemoveXib
|
||||
AnchorSideRight.Control = btnRemoveXib
|
||||
AnchorSideRight.Side = asrBottom
|
||||
Left = 40
|
||||
Height = 20
|
||||
Top = 283
|
||||
Width = 74
|
||||
Width = 77
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
AutoSize = True
|
||||
Caption = 'Add'
|
||||
OnClick = btnAddXibClick
|
||||
TabOrder = 7
|
||||
end
|
||||
object btnRemoveXib: TButton[16]
|
||||
object btnRemoveXib: TButton
|
||||
Left = 40
|
||||
Height = 20
|
||||
Top = 312
|
||||
Width = 74
|
||||
Width = 77
|
||||
AutoSize = True
|
||||
Caption = 'Remove'
|
||||
OnClick = btnRemoveXibClick
|
||||
TabOrder = 8
|
||||
end
|
||||
object nibsPopup: TPopupMenu[17]
|
||||
object memResFiles: TMemo
|
||||
Left = 120
|
||||
Height = 106
|
||||
Top = 352
|
||||
Width = 458
|
||||
Anchors = [akTop, akLeft, akRight, akBottom]
|
||||
ScrollBars = ssVertical
|
||||
TabOrder = 9
|
||||
end
|
||||
object Label6: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 352
|
||||
Width = 90
|
||||
Caption = 'Included Files:'
|
||||
ParentColor = False
|
||||
end
|
||||
object nibsPopup: TPopupMenu
|
||||
OnPopup = nibsPopupPopup
|
||||
left = 160
|
||||
top = 272
|
||||
|
@ -21,7 +21,8 @@ interface
|
||||
uses
|
||||
Classes,SysUtils,FileUtil,LResources,Forms,StdCtrls,CheckLst,Buttons, Dialogs,
|
||||
Menus,IDEOptionsIntf,ProjectIntf,LazIDEIntf,iPhoneExtStr,
|
||||
iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog, xibfile;
|
||||
iPhoneExtOptions, Controls, LazFilesUtils, XcodeUtils, newXibDialog, xibfile
|
||||
,CompOptsIntf;
|
||||
|
||||
type
|
||||
|
||||
@ -32,6 +33,8 @@ type
|
||||
btnAddXib:TButton;
|
||||
btnRemoveXib:TButton;
|
||||
Label5:TLabel;
|
||||
Label6: TLabel;
|
||||
memResFiles: TMemo;
|
||||
mnuDump:TMenuItem;
|
||||
mnuOpenIB:TMenuItem;
|
||||
nibFilesBox:TCheckListBox;
|
||||
@ -72,8 +75,8 @@ type
|
||||
SelXibFile : String;
|
||||
ResDirChanged : Boolean;
|
||||
|
||||
fOnChanged : TNotifyEvent;
|
||||
procedure DoChanged;
|
||||
//fOnChanged : TNotifyEvent;
|
||||
//procedure DoChanged;
|
||||
|
||||
procedure RefreshXIBList;
|
||||
|
||||
@ -86,7 +89,7 @@ type
|
||||
procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
|
||||
procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
|
||||
procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
|
||||
property OnChanged: TNotifyEvent read fOnChanged write fOnChanged;
|
||||
//property OnChanged: TNotifyEvent read fOnChanged write fOnChanged;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -281,10 +284,10 @@ begin
|
||||
mnuDump.Enabled:=SelXibFile<>''
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.DoChanged;
|
||||
begin
|
||||
if Assigned(fOnChanged) then fOnChanged(Self);
|
||||
end;
|
||||
//procedure TiPhoneProjectOptionsEditor.DoChanged;
|
||||
//begin
|
||||
//if Assigned(fOnChanged) then fOnChanged(Self);
|
||||
//end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.RefreshXIBList;
|
||||
var
|
||||
@ -513,7 +516,7 @@ procedure TiPhoneProjectOptionsEditor.ReadSettings(AOptions: TAbstractIDEOptions
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
with TiPhoneProjectOptions(AOptions) do
|
||||
with ProjOptions do
|
||||
begin
|
||||
Load;
|
||||
chkisPhone.Checked:=isIPhoneApp;
|
||||
@ -526,14 +529,16 @@ begin
|
||||
edtAppID.Text:=AppID;
|
||||
edtResDir.Text:=ResourceDir;
|
||||
edtExclude.Text:=ExcludeMask;
|
||||
memResFiles.Text:=ResFiles.Text;
|
||||
end;
|
||||
|
||||
RefreshXIBList;
|
||||
if TiPhoneProjectOptions(AOptions).MainNib<>'' then begin
|
||||
i:=nibFilesBox.Items.IndexOf(TiPhoneProjectOptions(AOptions).MainNib);
|
||||
if ProjOptions.MainNib<>'' then begin
|
||||
i:=nibFilesBox.Items.IndexOf(ProjOptions.MainNib);
|
||||
if i>=0 then nibFilesBox.Checked[i]:=True;
|
||||
end;
|
||||
SetControlsEnabled(chkisPhone.Checked); // is iPhone project
|
||||
|
||||
end;
|
||||
|
||||
procedure TiPhoneProjectOptionsEditor.WriteSettings(AOptions: TAbstractIDEOptions);
|
||||
@ -548,7 +553,7 @@ begin
|
||||
Break;
|
||||
end;
|
||||
|
||||
with TiPhoneProjectOptions(AOptions) do
|
||||
with ProjOptions do
|
||||
begin
|
||||
isIPhoneApp:=chkisPhone.Checked;
|
||||
SDK:=cmbSDKs.Caption;
|
||||
@ -556,14 +561,16 @@ begin
|
||||
ResourceDir:=edtResDir.Text;
|
||||
ExcludeMask:=edtExclude.Text;
|
||||
MainNib:=amainnib;
|
||||
ResFiles.Text:=memResFiles.Text;
|
||||
Save;
|
||||
DoChanged;
|
||||
end;
|
||||
DoOnChange;
|
||||
end;
|
||||
|
||||
class function TiPhoneProjectOptionsEditor.SupportedOptionsClass: TAbstractIDEOptionsClass;
|
||||
begin
|
||||
Result:=TiPhoneProjectOptions;
|
||||
//Result:=TiPhoneProjectOptions;
|
||||
Result:=TLazCompilerOptions;
|
||||
end;
|
||||
|
||||
const
|
||||
|
@ -19,9 +19,13 @@ unit xcodetemplate;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, contnrs;
|
||||
Classes, SysUtils, contnrs, xcodeproj;
|
||||
|
||||
procedure PrepareTemplateFile(Src, TemplateValues: TStrings; BuildSettings: TFPStringHashTable);
|
||||
procedure PrepareTemplateFile_(Src, TemplateValues: TStrings; BuildSettings: TFPStringHashTable);
|
||||
procedure PrepareTemplateFile(Src, TemplateValues: TStrings);
|
||||
procedure UpdateBldConfig(const proj: PBXProject; optName, optVal: string);
|
||||
procedure UpdateMainFile(const proj: PBXProject; mainfile: string);
|
||||
procedure UpdateCompileOpts(const proj: PBXProject; options: string);
|
||||
|
||||
const
|
||||
XCodeProjectTemplateIconID : AnsiString ='0AE3FFA610F3C9AF00A9B007,';
|
||||
@ -141,10 +145,10 @@ const
|
||||
' COPY_PHASE_STRIP = YES;'#10+
|
||||
' FPC_OUTPUT_FILE = $BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH;'#10+
|
||||
' FPC_COMPILER_OPTIONS = "-Parm -o$FPC_OUTPUT_FILE $FPC_CUSTOM_OPTIONS";'#10+
|
||||
' "FPC_COMPILER_OPTIONS[sdk=iphonesimulator*]" = "-Tiphonesim -Pi386 -o$FPC_OUTPUT_FILE $FPC_CUSTOM_OPTIONS";'#10+
|
||||
' "FPC_COMPILER_OPTIONS[sdk=iphonesimulator*]" = "-Tiphonesim -Pi386 -o$FPC_OUTPUT_FILE $FPC_CUSTOM_OPTIONS";'#10+
|
||||
' FPC_COMPILER_PATH = ;'#10+
|
||||
' FPC_CUSTOM_OPTIONS = ;'#10+
|
||||
' "FPC_CUSTOM_OPTIONS[sdk=iphonesimulator*]" = ;'#10+
|
||||
' "FPC_CUSTOM_OPTIONS[sdk=iphonesimulator*]" = ;'#10+
|
||||
' FPC_MAIN_FILE = ;'#10+
|
||||
' SDKROOT = iphoneos2.0;'#10+
|
||||
' VALID_ARCHS = "armv6 armv7";'#10+
|
||||
@ -199,6 +203,41 @@ const
|
||||
' rootObject = 0A52AE8310F0D05300478C4F /* Project object */;'#10+
|
||||
'}'#10;
|
||||
|
||||
BuildScript =
|
||||
'## start'#13
|
||||
+'echo "compiling FPC project"'#13
|
||||
+''#13
|
||||
+'export RESULT_EXE=${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'#13
|
||||
+'export IOSHEADERS='#13
|
||||
+'cd $FPC_MAIN_DIR'#13
|
||||
+'#rm $RESULT_EXE'#13
|
||||
+'export TargetCPU=${PLATFORM_PREFERRED_ARCH}'#13
|
||||
+''#13
|
||||
+'if [ "${PLATFORM_NAME}" == "iphonesimulator" ]; then'#13
|
||||
+' export TargetOS="iphonesim"'#13
|
||||
+'fi'#13
|
||||
+'export Target=${TargetCPU}-${TargetOS}'#13
|
||||
+''#13
|
||||
+'pwd'#13
|
||||
+'echo ${RESULT_EXE}'#13
|
||||
+''#13
|
||||
+'${FPC_DIR}fpc -T${TargetOS} -P${TargetCPU} -MDelphi -Scghi -O1 -l -dIPHONEALL \'#13
|
||||
+' ${FPC_CUSTOM_OPTIONS} \'#13
|
||||
//-Fu~/iOS_6_0 -Fu.
|
||||
+'-Filib/${Target} -FUlib/${Target} \'#13
|
||||
+'-XR${SDKROOT} -FD${PLATFORM_DEVELOPER_BIN_DIR} $FPC_MAIN_FILE \'#13
|
||||
+' -o${RESULT_EXE}'#13
|
||||
+'export RES=$?'#13
|
||||
+''#13
|
||||
+'if [ $RES != 0 ]; then'#13
|
||||
+' exit $RES'#13
|
||||
+'fi'#13
|
||||
+''#13
|
||||
+'echo ${RESULT_EXE}'#13
|
||||
+''#13
|
||||
+'exit $FPCRES'#13;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
function GetValueName(const Source: String; idx: Integer): String;
|
||||
@ -244,7 +283,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure PrepareTemplateFile(Src, TemplateValues: TStrings; BuildSettings: TFPStringHashTable);
|
||||
procedure PrepareTemplateFile_(Src, TemplateValues: TStrings; BuildSettings: TFPStringHashTable);
|
||||
//todo: Better code to update XCode project file!
|
||||
var
|
||||
i, j : Integer;
|
||||
@ -286,6 +325,119 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure UpdateBldConfig(const proj: PBXProject; optName, optVal: string);
|
||||
var
|
||||
trg : PBXNativeTarget;
|
||||
cfg : XCBuildConfiguration;
|
||||
i : integer;
|
||||
j : integer;
|
||||
begin
|
||||
for i:=0 to proj.targets.Count-1 do begin
|
||||
trg := PBXNativeTarget(proj.targets[i]);
|
||||
for j:=0 to trg.buildConfigurationList.Count-1 do begin
|
||||
cfg:=XCBuildConfiguration(trg.buildConfigurationList.buildConfigurations[j]);
|
||||
cfg.buildSettings.str[optName]:=optVal;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure UpdateCompileOpts(const proj: PBXProject; options: string);
|
||||
var
|
||||
opt : string;
|
||||
begin
|
||||
//UpdateBldConfig(proj, 'FPC_CUSTOM_OPTIONS', options);
|
||||
UpdateBldConfig(proj, 'FPC_CUSTOM_OPTIONS', '');
|
||||
|
||||
opt:=options;
|
||||
opt:=StringReplace(opt,'$(TargetCPU)','$arch',[rfReplaceAll, rfIgnoreCase]);
|
||||
opt:=StringReplace(opt,'$(TargetOS)','iphone',[rfReplaceAll, rfIgnoreCase]);
|
||||
UpdateBldConfig(proj, 'FPC_CUSTOM_OPTIONS[sdk=iphoneos*]', opt);
|
||||
|
||||
opt:=options;
|
||||
opt:=StringReplace(opt,'$(TargetCPU)','$arch',[rfReplaceAll, rfIgnoreCase]);
|
||||
opt:=StringReplace(opt,'$(TargetOS)','iphonesim',[rfReplaceAll, rfIgnoreCase]);
|
||||
UpdateBldConfig(proj, 'FPC_CUSTOM_OPTIONS[sdk=iphonesimulator*]', opt);
|
||||
end;
|
||||
|
||||
procedure UpdateMainFile(const proj: PBXProject; mainfile: string);
|
||||
begin
|
||||
UpdateBldConfig(proj, 'FPC_MAIN_FILE', mainfile);
|
||||
UpdateBldConfig(proj, 'FPC_MAIN_DIR', ExtractFileDir(mainfile));
|
||||
end;
|
||||
|
||||
procedure PrepareTemplateFile(Src, TemplateValues: TStrings);
|
||||
var
|
||||
prj : PBXProject;
|
||||
trg : PBXNativeTarget;
|
||||
cfg : XCBuildConfiguration;
|
||||
fr : PBXFileReference;
|
||||
grp : PBXGroup;
|
||||
scr : PBXShellScriptBuildPhase;
|
||||
i : integer;
|
||||
plist : string;
|
||||
targetName : string;
|
||||
bundle : string;
|
||||
main : string;
|
||||
begin
|
||||
prj:=ProjectCreate3_2;
|
||||
|
||||
targetName:=TemplateValues.Values['targetname'];
|
||||
bundle:=TemplateValues.Values['bundle'];
|
||||
plist:=TemplateValues.Values['plist'];
|
||||
if plist='' then plist:='info.plist';
|
||||
main:=TemplateValues.Values['mainfile'];
|
||||
|
||||
trg:=ProjectAddTarget(prj, targetName);
|
||||
for i:=0 to prj.buildConfigurationList.Count-1 do begin
|
||||
cfg:=prj.buildConfigurationList[i];
|
||||
ConfigIOS(cfg, TARGET_IOS_8_1);
|
||||
// Enable Build Active Architecture Only When Debugging
|
||||
if cfg.name='Debug' then cfg.buildSettings.AddStr('ONLY_ACTIVE_ARCH','YES');
|
||||
end;
|
||||
|
||||
// adding application type
|
||||
trg.productName:=TemplateValues.Values['productname'];
|
||||
trg.productType:=PRODTYPE_APP;
|
||||
|
||||
// target configuration
|
||||
trg.buildConfigurationList:=XCConfigurationList.Create;
|
||||
// Debug
|
||||
cfg:=trg.buildConfigurationList.addConfig('Debug');
|
||||
cfg.buildSettings.AddStr('INFOPLIST_FILE', '$(SRCROOT)/'+plist);
|
||||
cfg.buildSettings.AddStr('PRODUCT_NAME', trg.productName);
|
||||
// Build
|
||||
cfg:=trg.buildConfigurationList.addConfig('Release');
|
||||
cfg.buildSettings.AddStr('INFOPLIST_FILE', '$(SRCROOT)/'+plist);
|
||||
cfg.buildSettings.AddStr('PRODUCT_NAME', trg.productName);
|
||||
|
||||
trg.buildConfigurationList.defaultConfigurationName:='Debug';
|
||||
|
||||
// Adding the ".app" directory for the bundle and bind it to the target
|
||||
fr:=FileRefCreate(bundle, FILETYPE_MACHO);
|
||||
fr.sourceTree:= SRCTREE_PRODUCT;
|
||||
trg.productReference:=fr;
|
||||
|
||||
// Creating "content" for the directory. It should also contain .plist
|
||||
grp:=prj.mainGroup.addSubGroup(targetName); // name must match to the target name!
|
||||
grp:=grp.addSubGroup('Supporting Files'); // name must match!
|
||||
|
||||
// creating a reference to info.plist. It's located at "xcode" folder.
|
||||
// Thus at the same directar as .xcodeproj dir
|
||||
fr:=FileRefCreate(plist, FILETYPE_PLIST );
|
||||
fr.sourceTree:=SRCTREE_PROJECT;
|
||||
|
||||
fr.path:=plist;
|
||||
grp.children.Add( fr );
|
||||
|
||||
scr:=TargetAddRunScript(trg);
|
||||
scr.shellScript:=BuildScript;
|
||||
scr.showEnvVarsInLog:=true;
|
||||
|
||||
UpdateMainFile(prj, main);
|
||||
UpdateCompileOpts(prj, TemplateValues.Values['projoptions']);
|
||||
|
||||
src.Text:=ProjectWrite(prj);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Reference in New Issue
Block a user