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:
skalogryz
2015-12-20 03:54:35 +00:00
parent a8dc2255dc
commit f8f909c0c0
13 changed files with 590 additions and 163 deletions

View File

@ -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

View File

@ -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;

View File

@ -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.';

View File

@ -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"/>

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View 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.

View File

@ -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

View File

@ -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

View File

@ -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.