2014-11-10 02:30:09 +00:00
unit xcodeproj;
{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* by Dmitry Boyarintsev - Oct 2 0 1 4 *
* *
* license: free for use, but please leave a note to the origin of the library *
* *
* PBXcontainer unit is a library to read/ write the pbx formatter file as a *
* whole The file structure is made to keep the reference in a complex objects *
* *
* Memory Management. *
* Cocoa is reference - counted library , thus the usage of an object *
* controlled natively by ref counting. *
* A bit trickier for pascal *
* Following rules are applied *
* * read - only property objects are freed by the host ( obviously) *
* * other "freeing" operations are noted at "mmgr" comments *
* * any objects within key- value tables are freed *
* Alternative solution - implement ref counting! *
* *
2015-12-20 03:54:35 +00:00
* 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. *
2014-11-10 02:30:09 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
interface
2015-12-20 03:54:35 +00:00
{$ifdef fpc} {$mode delphi} {$endif}
2014-11-10 02:30:09 +00:00
uses
Classes, SysUtils,
typinfo, pbxcontainer;
type
{ XCBuildConfiguration }
XCBuildConfiguration = class( PBXObject)
private
fname : string ;
fbuildSettings: TPBXKeyValue;
public
constructor Create; override ;
destructor Destroy; override ;
published
property buildSettings : TPBXKeyValue read fbuildSettings;
property name : string read fname write fname;
end ;
{ XCConfigurationList }
// mmgr: XCConfigurationList frees
// * content of buildConfigurations
XCConfigurationList = class( PBXObject)
private
fdefaultConfigurationIsVisible: string ;
fdefaultConfigurationName: string ;
fbuildConfigurations: TPBXObjectsList;
2015-12-20 03:54:35 +00:00
function GetConfigItem( i: integer ) : XCBuildConfiguration;
function GetCount: integer ;
2014-11-10 02:30:09 +00:00
public
constructor Create; override ;
destructor Destroy; override ;
function addConfig( const aname: string ) : XCBuildConfiguration;
2016-01-18 06:49:24 +00:00
function findConfig( const aname: string ; aforce: Boolean = false ) : XCBuildConfiguration;
2015-12-20 03:54:35 +00:00
// 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 ;
2014-11-10 02:30:09 +00:00
published
property buildConfigurations: TPBXObjectsList read fbuildConfigurations;
property defaultConfigurationIsVisible: string read fdefaultConfigurationIsVisible write fdefaultConfigurationIsVisible;
property defaultConfigurationName: string read fdefaultConfigurationName write fdefaultConfigurationName;
end ;
{ PBXContainerItemProxy }
PBXContainerItemProxy = class( PBXObject)
private
FcontainerPortal : PBXObject;
fproxyType : string ;
fremoteGlobalIDString: string ;
fremoteInfo: string ;
published
property containerPortal: PBXObject read fcontainerPortal write fcontainerPortal; // Object = 0AFA6EA519F60EFD004C8FD9 /* Project object */;
property proxyType: string read FproxyType write fproxyType;
property remoteGlobalIDString: string read fremoteGlobalIDString write fremoteGlobalIDString; //object = 0AFA6EAC19F60EFD004C8FD9;
property remoteInfo : string read fremoteInfo write fremoteInfo; // ttestGame;
end ;
{ PBXFileReference }
2015-12-20 03:54:35 +00:00
// 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
2014-11-10 02:30:09 +00:00
PBXFileReference = class( PBXObject)
private
FexplicitFileType: string ;
2015-12-20 03:54:35 +00:00
FincludeInIndex: Boolean ;
2014-11-10 02:30:09 +00:00
FlastKnownFileType: string ;
Fname: string ;
Fpath: string ;
FsourceTree: string ;
published
property explicitFileType: string read FexplicitFileType write FexplicitFileType;
2015-12-20 03:54:35 +00:00
property includeInIndex: Boolean read FincludeInIndex write FincludeInIndex;
2014-11-10 02:30:09 +00:00
property lastKnownFileType: string read flastKnownFileType write flastKnownFileType;
property name : string read Fname write Fname;
property path: string read Fpath write Fpath;
property sourceTree: string read FsourceTree write FsourceTree;
end ;
{ PBXBuildFile }
PBXBuildFile = class( PBXObject)
private
fFileRef : PBXFileReference;
published
property fileRef : PBXFileReference read ffileRef write ffileRef; // obj
end ;
{ PBXBuildPhase }
// mmgr: on free
// * content of files
PBXBuildPhase = class( PBXObject)
private
fbuildActionMask : Integer ;
ffiles: TPBXObjectsList;
2014-11-11 04:52:01 +00:00
frunOnlyForDeploymentPostprocessing: Boolean ;
2014-11-10 02:30:09 +00:00
fname: string ;
public
constructor Create; override ;
destructor Destroy; override ;
2016-01-18 16:55:44 +00:00
function AddFile( ref: PBXFileReference) : PBXBuildFile;
2014-11-10 02:30:09 +00:00
published
property buildActionMask: Integer read fbuildActionMask write fbuildActionMask;
property files: TPBXObjectsList read ffiles;
property name : string read fname write fname;
2014-11-11 04:52:01 +00:00
property runOnlyForDeploymentPostprocessing: Boolean read frunOnlyForDeploymentPostprocessing write frunOnlyForDeploymentPostprocessing;
2014-11-10 02:30:09 +00:00
end ;
{ PBXFrameworksBuildPhase }
PBXFrameworksBuildPhase = class( PBXBuildPhase) ;
PBXResourcesBuildPhase = class( PBXBuildPhase) ;
PBXSourcesBuildPhase = class( PBXBuildPhase) ;
2016-01-18 16:55:44 +00:00
PBXBuildPhaseClass = class of PBXBuildPhase;
2014-11-10 02:30:09 +00:00
{ PBXShellScriptBuildPhase }
PBXShellScriptBuildPhase = class( PBXBuildPhase)
private
finputPaths: TPBXStringArray;
foutputPaths: TPBXStringArray;
fshellpath: string ;
fshellScript: string ;
2015-12-20 03:54:35 +00:00
fshowEnvVarsInLog: Boolean ;
2014-11-10 02:30:09 +00:00
public
constructor Create; override ;
destructor Destroy; override ;
published
property inputPaths: TPBXStringArray read finputPaths;
property outputPaths: TPBXStringArray read foutputPaths;
property shellPath: string read fshellpath write fshellPath;
property shellScript: string read fshellScript write fshellScript;
2015-12-20 03:54:35 +00:00
property showEnvVarsInLog: Boolean read fshowEnvVarsInLog write fshowEnvVarsInLog default true ;
2014-11-10 02:30:09 +00:00
end ;
{ PBXGroup }
// mmgt: PBXGroup owns children object (PBXGroup and PBXFileRefernece)
// and would free then on release;
// note, that PBXFileReference objects might be used in other places
PBXGroup = class( PBXObject)
private
fsourceTree : string ;
fchildren: TPBXObjectsList;
fname: string ;
fpath: string ;
public
constructor Create; override ;
destructor Destroy; override ;
function addSubGroup( const aname: string ) : PBXGroup;
2016-01-18 06:49:24 +00:00
function findGroup( const aname: string ; aforce: Boolean = false ) : PBXGroup;
function findFileRefByPathName( const afilename: string ) : PBXFileReference;
2014-11-10 02:30:09 +00:00
published
property children: TPBXObjectsList read fchildren;
property name : string read fname write fname;
property path: string read fpath write fpath;
property sourceTree: string read fsourceTree write fsourceTree;
end ;
PBXVariantGroup = class( PBXGroup) ;
{ PBXNativeTarget }
// mmgr: PBXNativeTarget
// * buildConfigurationList
// * contents of buildPhases
// * contents of buildRules
// * content of dependencies
PBXNativeTarget = class( PBXObject)
private
fbuildConfigurationList: XCConfigurationList;
fname : string ;
fproductName : string ;
fproductReference : PBXObject;
fproductType : string ;
fbuildPhases : TPBXObjectsList;
fbuildRules : TPBXObjectsList;
fdependencies : TPBXObjectsList;
public
constructor Create; override ;
destructor Destroy; override ;
published
property buildConfigurationList : XCConfigurationList read fbuildConfigurationList write fbuildConfigurationList; //= 0AFA6ED419F60F01004C8FD9 /* Build configuration list for PBXNativeTarget "ttestGame" */;
property buildPhases: TPBXObjectsList read fbuildPhases;
property buildRules: TPBXObjectsList read fbuildRules;
property dependencies: TPBXObjectsList read fdependencies;
property name : string read fname write fname;
property productName: string read fproductName write fproductName; // = ttestGame;
2015-12-20 03:54:35 +00:00
property productReference: PBXObject read fproductReference write fproductReference; // producut resulting file
2014-11-10 02:30:09 +00:00
property productType: string read fproductType write fproductType; // = "com.apple.product-type.application";
end ;
2015-12-20 03:54:35 +00:00
{ 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 ;
2014-11-10 02:30:09 +00:00
{ PBXTargetDependency }
// mmgt:
// targetProxy - is freed
PBXTargetDependency = class( PBXObject)
private
ftargetProxy: PBXContainerItemProxy;
ftarget: PBXNativeTarget;
public
destructor Destroy; override ;
published
property target : PBXNativeTarget read ftarget write ftarget;
property targetProxy: PBXContainerItemProxy read ftargetProxy write ftargetProxy; {* PBXContainerItemProxy *}
end ;
{ PBXProject }
// mmgt: PBXProject frees the following property objects, if assigned:
// * mainGroup
// * buildConfigurationList
// * contents of targets
PBXProject = class( PBXObject)
private
fattributes : TPBXKeyValue;
fcompatibilityVersion : string ;
fdevelopmentRegion : string ;
2014-11-11 04:52:01 +00:00
fhasScannedForEncodings: Boolean ;
2014-11-10 02:30:09 +00:00
fmainGroup: PBXGroup;
fknownRegions: TPBXStringArray;
fproductRefGroup: PBXGroup;
fprojectDirPath: string ;
fprojectRoot : string ;
ftargets: TPBXObjectsList;
fbuildConfigurationList: XCConfigurationList;
protected
class procedure _WriteEmpty( propnames: TStrings) ; override ;
public
constructor Create; override ;
destructor Destroy; override ;
function addTarget( const aname: string ) : PBXNativeTarget;
published
property attributes: TPBXKeyValue read fattributes;
property buildConfigurationList: XCConfigurationList read fbuildConfigurationList write fbuildConfigurationList;
property compatibilityVersion: string read fcompatibilityVersion write fcompatibilityVersion;
property developmentRegion: string read fdevelopmentRegion write fdevelopmentRegion;
2014-11-11 04:52:01 +00:00
property hasScannedForEncodings: Boolean read fhasScannedForEncodings write fhasScannedForEncodings;
2014-11-10 02:30:09 +00:00
property knownRegions: TPBXStringArray read fknownRegions;
property mainGroup: PBXGroup read fmainGroup write fmainGroup;
property productRefGroup: PBXGroup read fproductRefGroup write fproductRefGroup;
property projectDirPath: string read fprojectDirPath write fprojectDirPath;
property projectRoot: string read fprojectRoot write fprojectRoot;
property targets: TPBXObjectsList read ftargets;
end ;
2014-11-11 04:52:01 +00:00
function ProjectLoadFromStream( st: TStream; var prj: PBXProject) : Boolean ;
function ProjectLoadFromFile( const fn: string ; var prj: PBXProject) : Boolean ;
2016-03-22 14:54:36 +00:00
function ProjectSaveToFile( prj: PBXProject; const fn: string ) : Boolean ;
2014-11-10 02:30:09 +00:00
2014-11-11 04:52:01 +00:00
// serializes a PBX project to the string, using PBXContainer structure
2014-11-10 02:30:09 +00:00
function ProjectWrite( prj: PBXProject) : string ;
2014-11-11 04:52:01 +00:00
// creates a minimum possible project
function ProjectCreateMin: PBXProject;
// creates main group and product groups
procedure ProjectDefaultGroups( prj: PBXProject) ;
// adds necessary flags for Xcode3.2 not to throw any warnings
procedure ProjectUpdateForXcode3_2( prj: PBXProject) ;
// creates a minimum project, defaults the structure and sets Xcode 3.2 compat flags
function ProjectCreate3_2: PBXProject;
2014-11-10 02:30:09 +00:00
function ProjectAddTarget( prj: PBXProject; const ATargetName: string ) : PBXNativeTarget;
2016-01-18 06:49:24 +00:00
// adds if doesn't exist
function ProjectForceTarget( prj: PBXProject; const ATargetName: string ) : PBXNativeTarget;
2014-11-10 02:30:09 +00:00
const
SCRIPT_RUNPATH = '/bin/sh' ;
SCRIPT_DEFAULT = '' ;
SCRIPT_DEFNAME = 'Run Script' ;
function TargetAddRunScript( atarget: PBXNativeTarget) : PBXShellScriptBuildPhase;
2016-01-18 16:55:44 +00:00
function TargetFindBuildPhase( atarget: PBXNativeTarget; aclass: PBXBuildPhaseClass; aforce: Boolean = false ) : PBXBuildPhase;
function TargetFindRunScript( atarget: PBXNativeTarget; aforce: Boolean = false ) : PBXShellScriptBuildPhase;
function TargetFindResources( atarget: PBXNativeTarget; aforce: Boolean = false ) : PBXResourcesBuildPhase;
2014-11-10 02:30:09 +00:00
const
//FILETYPE_SCRIPT = 'text.script.sh';
FILETYPE_EXEC = 'compiled.mach-o.executable' ;
FILETYPE_MACHO = FILETYPE_EXEC;
2015-12-20 03:54:35 +00:00
FILETYPE_BUNDLE = 'wrapper.application' ;
FILETYPE_PLIST = 'text.plist.xml' ;
FILETYPE_OBJC = 'sourcecode.c.objc' ;
2014-11-10 02:30:09 +00:00
2016-01-18 16:55:44 +00:00
// defaults to SRCTREE_GROUP for source related
function FileRefCreate( const afilename: string ; const filetype: string = '' ) : PBXFileReference; overload ;
function FileRefCreate( const afilename: string ; const filetype, ASrcTreeRel: string ) : PBXFileReference; overload ;
2014-11-10 02:30:09 +00:00
const
2015-12-20 03:54:35 +00:00
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 = SRCTREE_GROUP) : PBXGroup;
2014-11-10 02:30:09 +00:00
//todo: need a rountine to update the path whenever the project is saved
2014-11-11 04:52:01 +00:00
function GroupCreateRoot( const projectfolder: string = '' ) : PBXGroup;
2014-11-10 02:30:09 +00:00
const
PRODTYPE_TOOL = 'com.apple.product-type.tool' ;
2015-12-20 03:54:35 +00:00
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
2014-11-10 02:30:09 +00:00
//
// PBXSourcesBuildPhase (sources) - is part of a PBXNativeTarget
// PBXNativeTarget - is part of Target
// PBXNativeTarget
//buildPhases = (
//0AA67B651A04929900CF0DD7 /* Sources */,
//0AA67B661A04929900CF0DD7 /* Frameworks */,
//0AA67B671A04929900CF0DD7 /* CopyFiles */,
//);
2015-12-20 03:54:35 +00:00
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' ;
2014-11-10 02:30:09 +00:00
2016-03-22 14:54:36 +00:00
procedure SetNewStr( kv: TPBXKeyValue; const aname, avalue: string ) ;
2014-11-10 02:30:09 +00:00
implementation
2016-03-22 14:54:36 +00:00
procedure SetNewStr( kv: TPBXKeyValue; const aname, avalue: string ) ;
begin
if Assigned( kv) then begin
if kv. FindIndexOf( aname) < 0 then
kv. AddStr( aname, avalue) ;
end ;
end ;
2015-12-20 03:54:35 +00:00
procedure ConfigIOS( cfg: XCBuildConfiguration; const targetiOS: string ) ;
begin
if not Assigned( cfg) then Exit;
2016-03-22 14:54:36 +00:00
SetNewStr( cfg. buildSettings, CFG_IOSTRG, targetiOS) ;
SetNewStr( cfg. buildSettings, CFG_SDKROOT, 'iphoneos' ) ;
SetNewStr( cfg. buildSettings, CFG_DEVICE, CFG_DEVICE_ALL) ;
2015-12-20 03:54:35 +00:00
end ;
{ PBXLegacyTarget }
constructor PBXLegacyTarget. Create;
begin
inherited Create;
fpassBuildSettingsInEnvironment: = true ;
end ;
2014-11-10 02:30:09 +00:00
{ PBXTargetDependency }
destructor PBXTargetDependency. Destroy;
begin
ftargetProxy. Free;
inherited Destroy;
end ;
{ PBXShellScriptBuildPhase }
constructor PBXShellScriptBuildPhase. Create;
begin
inherited Create;
finputPaths: = TPBXStringArray. Create;
foutputPaths: = TPBXStringArray. Create;
end ;
destructor PBXShellScriptBuildPhase. Destroy;
begin
finputPaths. Free;
foutputPaths. Free;
inherited Destroy;
end ;
{ PBXNativeTarget }
constructor PBXNativeTarget. Create;
begin
inherited Create;
fbuildPhases : = TPBXObjectsList. Create( true ) ;
fdependencies : = TPBXObjectsList. Create( true ) ;
fbuildRules : = TPBXObjectsList. Create( true ) ;
end ;
destructor PBXNativeTarget. Destroy;
begin
fbuildConfigurationList. Free;
fbuildRules. Free;
fbuildPhases. Free;
fdependencies. Free;
inherited Destroy;
end ;
{ PBXProject }
class procedure PBXProject. _WriteEmpty( propnames: TStrings) ;
begin
propnames. Add( 'projectDirPath' ) ;
propnames. Add( 'projectRoot' ) ;
end ;
constructor PBXProject. Create;
begin
inherited Create;
ftargets: = TPBXObjectsList. create( true ) ;
fknownRegions: = TPBXStringArray. Create;
fattributes: = TPBXKeyValue. Create( true ) ;
end ;
destructor PBXProject. Destroy;
begin
fattributes. Free;
fknownRegions. Free;
ftargets. Free;
fmainGroup. Free;
fbuildConfigurationList. Free;
inherited Destroy;
end ;
function PBXProject. addTarget( const aname: string ) : PBXNativeTarget;
begin
Result : = PBXNativeTarget. Create;
targets. Add( Result ) ;
Result . _headerComment: = aname;
Result . name : = aname;
2015-12-20 03:54:35 +00:00
Result . productName: = aname;
2014-11-10 02:30:09 +00:00
end ;
{ XCConfigurationList }
2015-12-20 03:54:35 +00:00
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 ;
2014-11-10 02:30:09 +00:00
constructor XCConfigurationList. Create;
begin
inherited Create;
fbuildConfigurations: = TPBXObjectsList. Create( true ) ;
end ;
destructor XCConfigurationList. Destroy;
begin
fbuildConfigurations. Free;
inherited Destroy;
end ;
2015-12-20 03:54:35 +00:00
function XCConfigurationList. addConfig( const aname: string
) : XCBuildConfiguration;
2014-11-10 02:30:09 +00:00
begin
Result : = XCBuildConfiguration. Create;
Result . name : = aname;
Result . _headerComment: = aname;
fbuildConfigurations. Add( Result ) ;
end ;
2016-01-18 06:49:24 +00:00
function XCConfigurationList. findConfig( const aname: string ; aforce: Boolean ) : XCBuildConfiguration;
var
i : integer ;
begin
for i: = 0 to fbuildConfigurations. Count- 1 do begin
Result : = XCBuildConfiguration( fbuildConfigurations[ i] ) ;
if Result . name = aname then
Exit;
end ;
if aforce then
Result : = addConfig( aname)
else
Result : = nil ;
end ;
2014-11-10 02:30:09 +00:00
{ XCBuildConfiguration }
constructor XCBuildConfiguration. Create;
begin
inherited Create;
fbuildSettings: = TPBXKeyValue. Create( true ) ;
end ;
destructor XCBuildConfiguration. Destroy;
begin
fbuildSettings. Free;
inherited Destroy;
end ;
{ PBXGroup }
constructor PBXGroup. Create;
begin
inherited Create;
fchildren: = TPBXObjectsList. Create( true ) ;
end ;
destructor PBXGroup. Destroy;
begin
fchildren. Free;
inherited Destroy;
end ;
function PBXGroup. addSubGroup( const aname: string ) : PBXGroup;
begin
Result : = PBXGroup. Create;
fchildren. Add( Result ) ;
Result . name : = aname;
Result . _headerComment: = aname;
2015-12-20 03:54:35 +00:00
Result . sourceTree: = SRCTREE_GROUP;
2014-11-10 02:30:09 +00:00
end ;
2016-01-18 06:49:24 +00:00
function PBXGroup. findGroup( const aname: string ; aforce: Boolean = false ) : PBXGroup;
2014-11-11 04:52:01 +00:00
var
i : integer ;
obj : TObject;
begin
for i: = 0 to fchildren. Count- 1 do begin
obj: = fchildren[ i] ;
if ( obj is PBXGroup) and ( PBXGroup( obj) . name = aname) then begin
Result : = PBXGroup( obj) ;
Exit;
end ;
end ;
2016-01-18 06:49:24 +00:00
if aforce then
Result : = addSubGroup( aname)
else
Result : = nil ;
end ;
function PBXGroup. findFileRefByPathName( const afilename: string ) : PBXFileReference;
var
i : integer ;
obj : TObject;
begin
for i: = 0 to fchildren. Count- 1 do begin
obj: = fchildren[ i] ;
if ( obj is PBXFileReference) and ( PBXFileReference( obj) . path= afilename) then begin
Result : = PBXFileReference( obj) ;
Exit;
end ;
end ;
2014-11-11 04:52:01 +00:00
Result : = nil ;
end ;
2014-11-10 02:30:09 +00:00
{ PBXBuildPhase }
constructor PBXBuildPhase. Create;
begin
inherited Create;
ffiles: = TPBXObjectsList. Create( true ) ;
end ;
destructor PBXBuildPhase. Destroy;
begin
ffiles. Free;
end ;
2016-01-18 16:55:44 +00:00
function PBXBuildPhase. AddFile( ref: PBXFileReference) : PBXBuildFile;
begin
if not Assigned( ref) then begin
Result : = nil ;
Exit;
end ;
Result : = PBXBuildFile. Create;
Result . fileRef: = ref;
ffiles. Add( Result ) ;
end ;
2014-11-11 04:52:01 +00:00
function ProjectLoadFromStream( st: TStream; var prj: PBXProject) : Boolean ;
2014-11-10 02:30:09 +00:00
var
c : TPBXContainer;
info : TPBXFileInfo;
begin
prj: = nil ;
c: = TPBXContainer. Create;
try
Result : = c. ReadFile( st, info) ;
if Result then begin
if not ( info. rootObject is PBXProject) then begin
info. rootObject. Free;
end else begin
prj: = PBXProject( info. rootObject) ;
end ;
end
finally
c. Free;
end ;
end ;
2014-11-11 04:52:01 +00:00
function ProjectLoadFromFile( const fn: string ; var prj: PBXProject) : Boolean ;
2014-11-10 02:30:09 +00:00
var
fs : TFileStream;
begin
try
2016-04-17 18:55:41 +00:00
prj: = nil ;
fs: = TFileStream. Create( fn, fmOpenRead or fmShareDenyNone) ;
try
Result : = ProjectLoadFromStream( fs, prj) ;
finally
fs. Free;
end ;
except
Result : = false ;
2014-11-10 02:30:09 +00:00
end ;
end ;
2016-03-22 14:54:36 +00:00
function ProjectSaveToFile( prj: PBXProject; const fn: string ) : Boolean ;
var
fs : TFileStream;
s : string ;
begin
s: = ProjectWrite( prj) ;
try
fs: = TFileStream. Create( fn, fmCreate) ;
try
if length( s) > 0 then fs. Write( s[ 1 ] , length( s) ) ;
finally
fs. Free;
end ;
except
Result : = false ;
end ;
end ;
2014-11-10 02:30:09 +00:00
function ProjectWrite( prj: PBXProject) : string ;
var
info : TPBXFileInfo;
begin
info. archiveVersion: = '1' ;
info. objectVersion: = '46' ;
info. rootObject: = prj;
Result : = PBXWriteContainer( info) ;
end ;
2014-11-11 04:52:01 +00:00
function ProjectCreateMin: PBXProject;
2014-11-10 02:30:09 +00:00
var
p : PBXProject;
2016-07-29 03:34:23 +00:00
//cfg : XCBuildConfiguration;
2014-11-10 02:30:09 +00:00
begin
// requirements:
// * at least one build configuration
p : = PBXProject. Create;
p. _headerComment: = 'Project object' ;
p. buildConfigurationList: = XCConfigurationList. Create;
2014-11-11 04:52:01 +00:00
p. buildConfigurationList. _headerComment: = 'Build configuration list for PBXProject' ;
2014-11-10 02:30:09 +00:00
p. buildConfigurationList. defaultConfigurationIsVisible: = '0' ;
2016-07-29 03:34:23 +00:00
p. buildConfigurationList. addConfig( 'Debug' ) ;
p. buildConfigurationList. addConfig( 'Release' ) ;
2014-11-10 02:30:09 +00:00
// default name must be present
p. buildConfigurationList. defaultConfigurationName: = 'Release' ;
Result : = p;
end ;
2014-11-11 04:52:01 +00:00
procedure ProjectDefaultGroups( prj: PBXProject) ;
var
prd : PBXGroup;
begin
if not Assigned( prj) then Exit;
if not Assigned( prj. mainGroup) then
prj. mainGroup: = GroupCreateRoot;
if not Assigned( prj. productRefGroup) then begin
prd: = prj. mainGroup. findGroup( 'Products' ) ;
if not Assigned( prd) then
prd: = prj. mainGroup. addSubGroup( 'Products' ) ;
prj. productRefGroup: = prd;
end ;
end ;
procedure ProjectUpdateForXcode3_2( prj: PBXProject) ;
begin
if not Assigned( prj) then Exit;
// without the attribute Xcode complains aboutt updating settings
prj. attributes. AddStr( 'LastUpgradeCheck' , '0600' ) ;
prj. compatibilityVersion: = 'Xcode 3.2' ;
end ;
function ProjectCreate3_2: PBXProject;
begin
Result : = ProjectCreateMin;
ProjectDefaultGroups( Result ) ;
ProjectUpdateForXcode3_2( Result ) ;
end ;
2014-11-10 02:30:09 +00:00
function ProjectAddTarget( prj: PBXProject; const ATargetName: string ) : PBXNativeTarget;
begin
Result : = nil ;
if not Assigned( prj) then Exit;
Result : = prj. addTarget( ATargetName) ;
end ;
2016-01-18 06:49:24 +00:00
function ProjectForceTarget( prj: PBXProject; const ATargetName: string ) : PBXNativeTarget;
var
i : integer ;
begin
for i: = 0 to prj. targets. Count- 1 do begin
Result : = PBXNativeTarget( prj. targets[ i] ) ;
if Result . name = ATargetName then
Exit;
end ;
Result : = ProjectAddTarget( prj, ATargetName) ;
end ;
2016-01-18 16:55:44 +00:00
function TargetFindBuildPhase( atarget: PBXNativeTarget; aclass: PBXBuildPhaseClass; aforce: Boolean = false ) : PBXBuildPhase;
var
i : integer ;
begin
Result : = nil ;
if not Assigned( atarget) then Exit;
for i: = 0 to atarget. buildPhases. Count- 1 do
if atarget. buildPhases[ i] is aclass then begin
Result : = PBXBuildPhase( atarget. buildPhases[ i] ) ;
Break;
end ;
if not Assigned( Result ) and aforce then begin
Result : = aclass. Create;
atarget. buildPhases. Add( Result ) ;
end ;
end ;
function TargetFindResources( atarget: PBXNativeTarget; aforce: Boolean = false ) : PBXResourcesBuildPhase;
begin
Result : = PBXResourcesBuildPhase( TargetFindBuildPhase( atarget, PBXResourcesBuildPhase, aforce) ) ;
end ;
function TargetFindRunScript( atarget: PBXNativeTarget; aforce: Boolean = false ) : PBXShellScriptBuildPhase;
begin
Result : = PBXShellScriptBuildPhase( TargetFindBuildPhase( atarget, PBXShellScriptBuildPhase, false ) ) ;
if not Assigned( Result ) and aforce then
Result : = TargetAddRunScript( atarget) ;
end ;
2014-11-10 02:30:09 +00:00
function TargetAddRunScript( atarget: PBXNativeTarget) : PBXShellScriptBuildPhase;
begin
2016-01-18 16:55:44 +00:00
if not Assigned( atarget) then begin
Result : = nil ;
Exit;
end ;
2014-11-10 02:30:09 +00:00
Result : = PBXShellScriptBuildPhase. Create;
Result . name : = SCRIPT_DEFNAME;
Result . _headerComment: = SCRIPT_DEFNAME;
Result . shellScript: = SCRIPT_DEFAULT;
Result . shellPath: = SCRIPT_RUNPATH;
atarget. buildPhases. Add( Result ) ;
end ;
2014-11-11 04:52:01 +00:00
function FileRefCreate( const afilename: string ; const filetype: string ) : PBXFileReference;
2016-01-18 16:55:44 +00:00
begin
Result : = FileRefCreate( afilename, filetype, SRCTREE_GROUP) ;
end ;
function FileRefCreate( const afilename: string ; const filetype, ASrcTreeRel: string ) : PBXFileReference;
2014-11-10 02:30:09 +00:00
begin
Result : = PBXFileReference. Create;
Result . path: = afilename;
Result . _headerComment: = afilename;
Result . explicitFileType: = FILETYPE_EXEC;
2016-01-18 16:55:44 +00:00
Result . sourceTree: = ASrcTreeRel;
2014-11-10 02:30:09 +00:00
end ;
2014-11-11 04:52:01 +00:00
function GroupCreate( const aname, srcTree: string ) : PBXGroup;
2014-11-10 02:30:09 +00:00
begin
Result : = PBXGroup. Create;
Result . name : = aname;
Result . sourceTree: = srcTree;
Result . _headerComment: = aname;
end ;
2014-11-11 04:52:01 +00:00
function GroupCreateRoot( const projectfolder: string ) : PBXGroup;
2014-11-10 02:30:09 +00:00
begin
2015-12-20 03:54:35 +00:00
Result : = GroupCreate( '' , SRCTREE_GROUP) ;
2014-11-10 02:30:09 +00:00
Result . path: = projectfolder;
Result . _headerComment: = projectfolder;
end ;
initialization
PBXRegisterClass( PBXBuildFile) ;
PBXRegisterClass( PBXContainerItemProxy) ;
PBXRegisterClass( PBXFileReference) ;
PBXRegisterClass( PBXFrameworksBuildPhase) ;
PBXRegisterClass( PBXGroup) ;
PBXRegisterClass( PBXNativeTarget) ;
PBXRegisterClass( PBXProject) ;
PBXRegisterClass( PBXResourcesBuildPhase) ;
PBXRegisterClass( PBXSourcesBuildPhase) ;
PBXRegisterClass( PBXTargetDependency) ;
PBXRegisterClass( PBXVariantGroup) ;
PBXRegisterClass( XCBuildConfiguration) ;
PBXRegisterClass( XCConfigurationList) ;
2016-01-16 06:16:32 +00:00
PBXRegisterClass( PBXShellScriptBuildPhase) ;
2014-11-10 02:30:09 +00:00
end .