diff options
| -rw-r--r-- | devtools/create_project/create_project.cpp | 17 | ||||
| -rw-r--r-- | devtools/create_project/xcode.cpp | 405 | ||||
| -rw-r--r-- | devtools/create_project/xcode.h | 36 | 
3 files changed, 345 insertions, 113 deletions
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index 34d30e1d69..2e4e53dc59 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -20,7 +20,7 @@   *   */ -//#define ENABLE_XCODE +#define ENABLE_XCODE  // HACK to allow building with the SDL backend on MinGW  // see bug #1800764 "TOOLS: MinGW tools building broken" @@ -336,7 +336,12 @@ int main(int argc, char *argv[]) {  	setup.defines.splice(setup.defines.begin(), featureDefines);  	// Windows only has support for the SDL backend, so we hardcode it here (along with winmm) -	setup.defines.push_back("WIN32"); +	if (projectType != kProjectXcode) { +		setup.defines.push_back("WIN32"); +	} else { +		setup.defines.push_back("POSIX"); +		setup.defines.push_back("MACOSX"); // This will break iOS, but allows OS X to catch up on browser_osx. +	}  	setup.defines.push_back("SDL_BACKEND");  	if (!useSDL2) {  		cout << "\nLinking to SDL 1.2\n\n"; @@ -410,7 +415,6 @@ int main(int argc, char *argv[]) {  		globalWarnings.push_back("-Wwrite-strings");  		// The following are not warnings at all... We should consider adding them to  		// a different list of parameters. -		globalWarnings.push_back("-fno-rtti");  		globalWarnings.push_back("-fno-exceptions");  		globalWarnings.push_back("-fcheck-new"); @@ -1039,7 +1043,7 @@ bool producesObjectFile(const std::string &fileName) {  	std::string n, ext;  	splitFilename(fileName, n, ext); -	if (ext == "cpp" || ext == "c" || ext == "asm") +	if (ext == "cpp" || ext == "c" || ext == "asm" || ext == "m" || ext == "mm")  		return true;  	else  		return false; @@ -1279,8 +1283,9 @@ void ProjectProvider::createProject(BuildSetup &setup) {  	for (UUIDMap::const_iterator i = _uuidMap.begin(); i != _uuidMap.end(); ++i) {  		if (i->first == setup.projectName)  			continue; - +		// Retain the files between engines if we're creating a single project  		in.clear(); ex.clear(); +  		const std::string moduleDir = setup.srcDir + targetFolder + i->first;  		createModuleList(moduleDir, setup.defines, setup.testDirs, in, ex); @@ -1290,7 +1295,6 @@ void ProjectProvider::createProject(BuildSetup &setup) {  	if (setup.tests) {  		// Create the main project file.  		in.clear(); ex.clear(); -  		createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex);  		createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex);  		createModuleList(setup.srcDir + "/base", setup.defines, setup.testDirs, in, ex); @@ -1305,7 +1309,6 @@ void ProjectProvider::createProject(BuildSetup &setup) {  	} else if (!setup.devTools) {  		// Last but not least create the main project file.  		in.clear(); ex.clear(); -  		// File list for the Project file  		createModuleList(setup.srcDir + "/backends", setup.defines, setup.testDirs, in, ex);  		createModuleList(setup.srcDir + "/backends/platform/sdl", setup.defines, setup.testDirs, in, ex); diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index d95bf3e9ee..5edbb2985a 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -30,6 +30,14 @@ namespace CreateProjectTool {  #define DEBUG_XCODE_HASH 0 +#ifdef ENABLE_IOS +#define IOS_TARGET 0 +#define OSX_TARGET 1 +#define SIM_TARGET 2 +#else +#define OSX_TARGET 0 +#endif +  #define ADD_DEFINE(defines, name) \  	defines.push_back(name); @@ -54,39 +62,172 @@ namespace CreateProjectTool {  #define REMOVE_SETTING(config, key) \  	config.settings.erase(key); -#define ADD_BUILD_FILE(id, name, comment) { \ +#define ADD_BUILD_FILE(id, name, fileRefId, comment) { \  	Object *buildFile = new Object(this, id, name, "PBXBuildFile", "PBXBuildFile", comment); \ -	buildFile->addProperty("fileRef", getHash(name), name, SettingsNoValue); \ +	buildFile->addProperty("fileRef", fileRefId, name, SettingsNoValue); \  	_buildFile.add(buildFile); \  	_buildFile.flags = SettingsSingleItem; \  } -#define ADD_FILE_REFERENCE(name, properties) { \ -	Object *fileRef = new Object(this, name, name, "PBXFileReference", "PBXFileReference", name); \ +#define ADD_FILE_REFERENCE(id, name, properties) { \ +	Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); \  	if (!properties.fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties.fileEncoding, "", SettingsNoValue); \ -	if (!properties.lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties.lastKnownFileType, "", SettingsNoValue); \ -	if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue); \ -	if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", SettingsNoValue); \ +	if (!properties.lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties.lastKnownFileType, "", SettingsNoValue|SettingsQuoteVariable); \ +	if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue|SettingsQuoteVariable); \ +	if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", SettingsNoValue|SettingsQuoteVariable); \  	if (!properties.sourceTree.empty()) fileRef->addProperty("sourceTree", properties.sourceTree, "", SettingsNoValue); \  	_fileReference.add(fileRef); \  	_fileReference.flags = SettingsSingleItem; \  } +bool producesObjectFileOnOSX(const std::string &fileName) { +	std::string n, ext; +	splitFilename(fileName, n, ext); + +	// Note that the difference between this and the general producesObjectFile is that +	// this one adds Objective-C(++), and removes asm-support. +	if (ext == "cpp" || ext == "c" || ext == "m" || ext == "mm") +		return true; +	else +		return false; +} + +XCodeProvider::Group::Group(XCodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path) : Object(objectParent, uniqueName, groupName, "PBXGroup", "", groupName) { +	addProperty("name", name, "", SettingsNoValue|SettingsQuoteVariable); +	addProperty("sourceTree", "<group>", "", SettingsNoValue|SettingsQuoteVariable); +	 +	if (path != "") { +		addProperty("path", path, "", SettingsNoValue|SettingsQuoteVariable); +	} +	_childOrder = 0; +	_treeName = uniqueName; +} + +void XCodeProvider::Group::ensureChildExists(const std::string &name) { +	std::map<std::string, Group*>::iterator it = _childGroups.find(name); +	if (it == _childGroups.end()) { +		Group *child = new Group(parent, name, this->_treeName + '/' + name, name); +		_childGroups[name] = child; +		addChildGroup(child); +		parent->_groups.add(child); +	} +} + +void XCodeProvider::Group::addChildInternal(const std::string &id, const std::string &comment) { +	if (properties.find("children") == properties.end()) { +		Property children; +		children.hasOrder = true; +		children.flags = SettingsAsList; +		properties["children"] = children; +	} +	properties["children"].settings[id] = Setting("", comment + " in Sources", SettingsNoValue, 0, _childOrder++); +	if (_childOrder == 1) { +		// Force children to use () even when there is only 1 child. +		// Also this enforces the use of "," after the single item, instead of ; (see writeProperty) +		properties["children"].flags |= SettingsSingleItem; +	} else { +		properties["children"].flags ^= SettingsSingleItem; +	} + +} + +void XCodeProvider::Group::addChildGroup(const Group* group) { +	addChildInternal(parent->getHash(group->_treeName), group->_treeName); +} + +void XCodeProvider::Group::addChildFile(const std::string &name) { +	std::string id = "FileReference_" + _treeName + "/" + name; +	addChildInternal(parent->getHash(id), name); +	FileProperty property = FileProperty(name, name, name, "\"<group>\""); + +	parent->addFileReference(id, name, property); +	if (producesObjectFileOnOSX(name)) { +		parent->addBuildFile(_treeName + "/" + name, name, parent->getHash(id), name + " in Sources"); +	} +} + +void XCodeProvider::Group::addChildByHash(const std::string &hash, const std::string &name) { +	addChildInternal(hash, name); +} + +XCodeProvider::Group *XCodeProvider::Group::getChildGroup(const std::string &name) { +	std::map<std::string, Group*>::iterator it = _childGroups.find(name); +	assert(it != _childGroups.end()); +	return it->second; +} + +XCodeProvider::Group *XCodeProvider::touchGroupsForPath(const std::string &path) { +	if (_rootSourceGroup == nullptr) { +		assert (path == _projectRoot); +		_rootSourceGroup = new Group(this, "Sources", path, path); +		_groups.add(_rootSourceGroup); +		return _rootSourceGroup; +	} else { +		assert(path.find(_projectRoot) == 0); +		std::string subPath = path.substr(_projectRoot.size() + 1); +		Group *currentGroup = _rootSourceGroup; +		size_t firstPathComponent = subPath.find_first_of('/'); +		// We assume here that all paths have trailing '/', otherwise this breaks. +		while (firstPathComponent != std::string::npos) { +			currentGroup->ensureChildExists(subPath.substr(0, firstPathComponent)); +			currentGroup = currentGroup->getChildGroup(subPath.substr(0, firstPathComponent)); +			subPath = subPath.substr(firstPathComponent + 1); +			firstPathComponent = subPath.find_first_of('/'); +		} +		return currentGroup; +	} +} + +void XCodeProvider::addFileReference(const std::string &id, const std::string &name, FileProperty properties) { +	Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); +	if (!properties.fileEncoding.empty()) fileRef->addProperty("fileEncoding", properties.fileEncoding, "", SettingsNoValue); +	if (!properties.lastKnownFileType.empty()) fileRef->addProperty("lastKnownFileType", properties.lastKnownFileType, "", SettingsNoValue|SettingsQuoteVariable); +	if (!properties.fileName.empty()) fileRef->addProperty("name", properties.fileName, "", SettingsNoValue|SettingsQuoteVariable); +	if (!properties.filePath.empty()) fileRef->addProperty("path", properties.filePath, "", SettingsNoValue|SettingsQuoteVariable); +	if (!properties.sourceTree.empty()) fileRef->addProperty("sourceTree", properties.sourceTree, "", SettingsNoValue); +	_fileReference.add(fileRef); +	_fileReference.flags = SettingsSingleItem; +} + +void XCodeProvider::addProductFileReference(const std::string &id, const std::string &name) { +	Object *fileRef = new Object(this, id, name, "PBXFileReference", "PBXFileReference", name); +	fileRef->addProperty("explicitFileType", "compiled.mach-o.executable", "", SettingsNoValue|SettingsQuoteVariable); +	fileRef->addProperty("includeInIndex", "0", "", SettingsNoValue); +	fileRef->addProperty("path", name, "", SettingsNoValue|SettingsQuoteVariable); +	fileRef->addProperty("sourceTree", "BUILT_PRODUCTS_DIR", "", SettingsNoValue); +	_fileReference.add(fileRef); +	_fileReference.flags = SettingsSingleItem; +} + +void XCodeProvider::addBuildFile(const std::string &id, const std::string &name, const std::string &fileRefId, const std::string &comment) { + +	Object *buildFile = new Object(this, id, name, "PBXBuildFile", "PBXBuildFile", comment); +	buildFile->addProperty("fileRef", fileRefId, name, SettingsNoValue); +	_buildFile.add(buildFile); +	_buildFile.flags = SettingsSingleItem; +} +  XCodeProvider::XCodeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)  	: ProjectProvider(global_warnings, project_warnings, version) { +	_rootSourceGroup = NULL;  }  void XCodeProvider::createWorkspace(const BuildSetup &setup) {  	// Create project folder  	std::string workspace = setup.outputDir + '/' + PROJECT_NAME ".xcodeproj";  	createDirectory(workspace); - +	_projectRoot = setup.srcDir; +	touchGroupsForPath(_projectRoot); +	  	// Setup global objects  	setupDefines(setup); +#ifdef ENABLE_IOS  	_targets.push_back(PROJECT_DESCRIPTION "-iPhone"); +#endif  	_targets.push_back(PROJECT_DESCRIPTION "-OS X"); +#ifdef ENABLE_IOS  	_targets.push_back(PROJECT_DESCRIPTION "-Simulator"); - +#endif  	setupCopyFilesBuildPhase();  	setupFrameworksBuildPhase();  	setupNativeTarget(); @@ -167,44 +308,20 @@ void XCodeProvider::ouputMainProjectFile(const BuildSetup &setup) {  void XCodeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,                                             const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) { -	// Add comments for shared lists -	_buildFile.comment = "PBXBuildFile"; -	_fileReference.comment = "PBXFileReference"; - -	// Init root group -	_groups.comment = "PBXGroup"; - -	// Create group -	std::string name = getLastPathComponent(dir.name); -	Object *group = new Object(this, "PBXGroup_" + name , "PBXGroup", "PBXGroup", "", name); - -	// List of children -	Property children; -	children.hasOrder = true; -	children.flags = SettingsAsList; - -	group->addProperty("name", name, "", SettingsNoValue|SettingsQuoteVariable); -	group->addProperty("sourceTree", "<group>", "", SettingsNoValue|SettingsQuoteVariable); - -	int order = 0; +	// Ensure that top-level groups are generated for i.e. engines/ +	Group *group = touchGroupsForPath(filePrefix);  	for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {  		const FileNode *node = *i; -		std::string id = "FileReference_" + node->name; -		FileProperty property = FileProperty(node->name, node->name, node->name, "<group>"); - -		ADD_SETTING_ORDER_NOVALUE(children, getHash(id), node->name, order++); -		ADD_BUILD_FILE(id, node->name, node->name + " in Sources"); -		ADD_FILE_REFERENCE(node->name, property); - +		// Iff it is a file, then add (build) file references. Since we're using Groups and not File References +		// for folders, we shouldn't add folders as file references, obviously. +		if (node->children.empty()) { +			group->addChildFile(node->name); +		}  		// Process child nodes  		if (!node->children.empty())  			writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');  	} - -	group->properties["children"] = children; - -	_groups.add(group);  }  ////////////////////////////////////////////////////////////////////////// @@ -214,6 +331,12 @@ void XCodeProvider::setupCopyFilesBuildPhase() {  	// Nothing to do here  } +#define DEF_SYSFRAMEWORK(framework) properties[framework".framework"] = FileProperty("wrapper.framework", framework".framework", "System/Library/Frameworks/" framework ".framework", "SDKROOT"); \ +	ADD_SETTING_ORDER_NOVALUE(children, getHash(framework".framework"), framework".framework", fwOrder++); +	 +#define DEF_LOCALLIB_STATIC(lib) properties[lib".a"] = FileProperty("archive.ar", lib".a", "/opt/local/lib/" lib ".a", "\"<group>\""); \ +	ADD_SETTING_ORDER_NOVALUE(children, getHash(lib".a"), lib".a", fwOrder++); +  /**   * Sets up the frameworks build phase.   * @@ -222,34 +345,53 @@ void XCodeProvider::setupCopyFilesBuildPhase() {  void XCodeProvider::setupFrameworksBuildPhase() {  	_frameworksBuildPhase.comment = "PBXFrameworksBuildPhase"; +	// Just use a hardcoded id for the Frameworks-group +	Group *frameworksGroup = new Group(this, "Frameworks", "PBXGroup_CustomTemplate_Frameworks_", ""); + +	Property children; +	children.hasOrder = true; +	children.flags = SettingsAsList; +  	// Setup framework file properties  	std::map<std::string, FileProperty> properties; - +	int fwOrder = 0;  	// Frameworks -	properties["ApplicationServices.framework"] = FileProperty("wrapper.framework", "ApplicationServices.framework", "System/Library/Frameworks/ApplicationServices.framework", "SDKROOT"); -	properties["AudioToolbox.framework"]        = FileProperty("wrapper.framework", "AudioToolbox.framework", "System/Library/Frameworks/AudioToolbox.framework", "SDKROOT"); -	properties["AudioUnit.framework"]           = FileProperty("wrapper.framework", "AudioUnit.framework", "System/Library/Frameworks/AudioUnit.framework", "SDKROOT"); -	properties["Carbon.framework"]              = FileProperty("wrapper.framework", "Carbon.framework", "System/Library/Frameworks/Carbon.framework", "SDKROOT"); -	properties["Cocoa.framework"]               = FileProperty("wrapper.framework", "Cocoa.framework", "System/Library/Frameworks/Cocoa.framework", "SDKROOT"); -	properties["CoreAudio.framework"]           = FileProperty("wrapper.framework", "CoreAudio.framework", "System/Library/Frameworks/CoreAudio.framework", "SDKROOT"); -	properties["CoreFoundation.framework"]      = FileProperty("wrapper.framework", "CoreFoundation.framework", "System/Library/Frameworks/CoreFoundation.framework", "SDKROOT"); -	properties["CoreMIDI.framework"]            = FileProperty("wrapper.framework", "CoreMIDI.framework", "System/Library/Frameworks/CoreMIDI.framework", "SDKROOT"); -	properties["Foundation.framework"]          = FileProperty("wrapper.framework", "Foundation.framework", "System/Library/Frameworks/Foundation.framework", "SDKROOT"); -	properties["IOKit.framework"]               = FileProperty("wrapper.framework", "IOKit.framework", "System/Library/Frameworks/IOKit.framework", "SDKROOT"); -	properties["OpenGLES.framework"]            = FileProperty("wrapper.framework", "OpenGLES.framework", "System/Library/Frameworks/OpenGLES.framework", "SDKROOT"); -	properties["QuartzCore.framework"]          = FileProperty("wrapper.framework", "QuartzCore.framework", "System/Library/Frameworks/QuartzCore.framework", "SDKROOT"); -	properties["QuickTime.framework"]           = FileProperty("wrapper.framework", "QuickTime.framework", "System/Library/Frameworks/QuickTime.framework", "SDKROOT"); -	properties["UIKit.framework"]               = FileProperty("wrapper.framework", "UIKit.framework", "System/Library/Frameworks/UIKit.framework", "SDKROOT"); +	DEF_SYSFRAMEWORK("ApplicationServices"); +	DEF_SYSFRAMEWORK("AudioToolbox"); +	DEF_SYSFRAMEWORK("AudioUnit"); +	DEF_SYSFRAMEWORK("Carbon"); +	DEF_SYSFRAMEWORK("Cocoa"); +	DEF_SYSFRAMEWORK("CoreAudio"); +	DEF_SYSFRAMEWORK("CoreFoundation"); +	DEF_SYSFRAMEWORK("CoreMIDI"); +	DEF_SYSFRAMEWORK("Foundation"); +	DEF_SYSFRAMEWORK("IOKit"); +	DEF_SYSFRAMEWORK("OpenGLES"); +	DEF_SYSFRAMEWORK("QuartzCore"); +	DEF_SYSFRAMEWORK("QuickTime"); +	DEF_SYSFRAMEWORK("UIKit"); +	// Optionals: +	DEF_SYSFRAMEWORK("OpenGL");  	// Local libraries -	properties["libFLAC.a"]                     = FileProperty("archive.ar", "libFLAC.a", "lib/libFLAC.a", "\"<group>\""); -	properties["libmad.a"]                      = FileProperty("archive.ar", "libmad.a", "lib/libmad.a", "\"<group>\""); -	//properties["libmpeg2.a"]                    = FileProperty("archive.ar", "libmpeg2.a", "lib/libmpeg2.a", "\"<group>\""); -	properties["libvorbisidec.a"]               = FileProperty("archive.ar", "libvorbisidec.a", "lib/libvorbisidec.a", "\"<group>\""); +	DEF_LOCALLIB_STATIC("libFLAC"); +	DEF_LOCALLIB_STATIC("libmad"); +	DEF_LOCALLIB_STATIC("libvorbisidec"); +	DEF_LOCALLIB_STATIC("libfreetype"); +//	DEF_LOCALLIB_STATIC("libmpeg2"); + +	frameworksGroup->properties["children"] = children; +	_groups.add(frameworksGroup); +	// Force this to be added as a sub-group in the root. +	_rootSourceGroup->addChildGroup(frameworksGroup); + +	// Declare this here, as it's used across the three targets +	int order = 0; +#ifdef ENABLE_IOS  	//////////////////////////////////////////////////////////////////////////  	// iPhone -	Object *framework_iPhone = new Object(this, "PBXFrameworksBuildPhase_" + _targets[0], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); +	Object *framework_iPhone = new Object(this, "PBXFrameworksBuildPhase_" + _targets[IOS_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");  	framework_iPhone->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);  	framework_iPhone->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue); @@ -272,23 +414,22 @@ void XCodeProvider::setupFrameworksBuildPhase() {  	frameworks_iPhone.push_back("libvorbisidec.a");  	frameworks_iPhone.push_back("OpenGLES.framework"); -	int order = 0;  	for (ValueList::iterator framework = frameworks_iPhone.begin(); framework != frameworks_iPhone.end(); framework++) {  		std::string id = "Frameworks_" + *framework + "_iphone";  		std::string comment = *framework + " in Frameworks";  		ADD_SETTING_ORDER_NOVALUE(iPhone_files, getHash(id), comment, order++); -		ADD_BUILD_FILE(id, *framework, comment); -		ADD_FILE_REFERENCE(*framework, properties[*framework]); +		ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); +		ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);  	}  	framework_iPhone->properties["files"] = iPhone_files;  	_frameworksBuildPhase.add(framework_iPhone); - +#endif  	//////////////////////////////////////////////////////////////////////////  	// ScummVM-OS X -	Object *framework_OSX = new Object(this, "PBXFrameworksBuildPhase_" + _targets[1], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); +	Object *framework_OSX = new Object(this, "PBXFrameworksBuildPhase_" + _targets[OSX_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");  	framework_OSX->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);  	framework_OSX->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue); @@ -311,6 +452,8 @@ void XCodeProvider::setupFrameworksBuildPhase() {  	frameworks_osx.push_back("IOKit.framework");  	frameworks_osx.push_back("Cocoa.framework");  	frameworks_osx.push_back("AudioUnit.framework"); +	// Optionals: +	frameworks_osx.push_back("OpenGL.framework");  	order = 0;  	for (ValueList::iterator framework = frameworks_osx.begin(); framework != frameworks_osx.end(); framework++) { @@ -318,17 +461,17 @@ void XCodeProvider::setupFrameworksBuildPhase() {  		std::string comment = *framework + " in Frameworks";  		ADD_SETTING_ORDER_NOVALUE(osx_files, getHash(id), comment, order++); -		ADD_BUILD_FILE(id, *framework, comment); -		ADD_FILE_REFERENCE(*framework, properties[*framework]); +		ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); +		ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);  	}  	framework_OSX->properties["files"] = osx_files;  	_frameworksBuildPhase.add(framework_OSX); - +#ifdef ENABLE_IOS  	//////////////////////////////////////////////////////////////////////////  	// Simulator -	Object *framework_simulator = new Object(this, "PBXFrameworksBuildPhase_" + _targets[2], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks"); +	Object *framework_simulator = new Object(this, "PBXFrameworksBuildPhase_" + _targets[SIM_TARGET], "PBXFrameworksBuildPhase", "PBXFrameworksBuildPhase", "", "Frameworks");  	framework_simulator->addProperty("buildActionMask", "2147483647", "", SettingsNoValue);  	framework_simulator->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue); @@ -353,20 +496,28 @@ void XCodeProvider::setupFrameworksBuildPhase() {  		std::string comment = *framework + " in Frameworks";  		ADD_SETTING_ORDER_NOVALUE(simulator_files, getHash(id), comment, order++); -		ADD_BUILD_FILE(id, *framework, comment); -		ADD_FILE_REFERENCE(*framework, properties[*framework]); +		ADD_BUILD_FILE(id, *framework, getHash(*framework), comment); +		ADD_FILE_REFERENCE(*framework, *framework, properties[*framework]);  	}  	framework_simulator->properties["files"] = simulator_files;  	_frameworksBuildPhase.add(framework_simulator); +#endif  }  void XCodeProvider::setupNativeTarget() {  	_nativeTarget.comment = "PBXNativeTarget"; +	// Just use a hardcoded id for the Products-group +	Group *productsGroup = new Group(this, "Products", "PBXGroup_CustomTemplate_Products_" , "");  	// Output native target section  	for (unsigned int i = 0; i < _targets.size(); i++) { +#ifndef ENABLE_IOS +		if (i != OSX_TARGET) { // TODO: Fix iOS-targets, for now just disable them. +			continue; +		} +#endif  		Object *target = new Object(this, "PBXNativeTarget_" + _targets[i], "PBXNativeTarget", "PBXNativeTarget", "", _targets[i]);  		target->addProperty("buildConfigurationList", getHash("XCConfigurationList_" + _targets[i]), "Build configuration list for PBXNativeTarget \"" + _targets[i] + "\"", SettingsNoValue); @@ -385,11 +536,15 @@ void XCodeProvider::setupNativeTarget() {  		target->addProperty("name", _targets[i], "", SettingsNoValue|SettingsQuoteVariable);  		target->addProperty("productName", PROJECT_NAME, "", SettingsNoValue); +		addProductFileReference("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i], PROJECT_DESCRIPTION ".app"); +		productsGroup->addChildByHash(getHash("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i]), PROJECT_DESCRIPTION ".app");  		target->addProperty("productReference", getHash("PBXFileReference_" PROJECT_DESCRIPTION ".app_" + _targets[i]), PROJECT_DESCRIPTION ".app", SettingsNoValue);  		target->addProperty("productType", "com.apple.product-type.application", "", SettingsNoValue|SettingsQuoteVariable);  		_nativeTarget.add(target);  	} +	_rootSourceGroup->addChildGroup(productsGroup); +	_groups.add(productsGroup);  }  void XCodeProvider::setupProject() { @@ -411,17 +566,25 @@ void XCodeProvider::setupProject() {  	ADD_SETTING_ORDER_NOVALUE(regions, "German", "", 3);  	project->properties["knownRegions"] = regions; -	project->addProperty("mainGroup", getHash("PBXGroup_CustomTemplate"), "CustomTemplate", SettingsNoValue); -	project->addProperty("projectDirPath", "", "", SettingsNoValue|SettingsQuoteVariable); +	project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", SettingsNoValue); +	project->addProperty("projectDirPath", _projectRoot, "", SettingsNoValue|SettingsQuoteVariable);  	project->addProperty("projectRoot", "", "", SettingsNoValue|SettingsQuoteVariable);  	// List of targets  	Property targets;  	targets.flags = SettingsAsList; -	targets.settings[getHash("PBXNativeTarget_" + _targets[0])] = Setting("", _targets[0], SettingsNoValue, 0, 0); -	targets.settings[getHash("PBXNativeTarget_" + _targets[1])] = Setting("", _targets[1], SettingsNoValue, 0, 1); -	targets.settings[getHash("PBXNativeTarget_" + _targets[2])] = Setting("", _targets[2], SettingsNoValue, 0, 2); +#ifdef ENABLE_IOS +	targets.settings[getHash("PBXNativeTarget_" + _targets[IOS_TARGET])] = Setting("", _targets[IOS_TARGET], SettingsNoValue, 0, 0); +#endif +	targets.settings[getHash("PBXNativeTarget_" + _targets[OSX_TARGET])] = Setting("", _targets[OSX_TARGET], SettingsNoValue, 0, 1); +#ifdef ENABLE_IOS +	targets.settings[getHash("PBXNativeTarget_" + _targets[SIM_TARGET])] = Setting("", _targets[SIM_TARGET], SettingsNoValue, 0, 2); +#endif  	project->properties["targets"] = targets; +#ifndef ENABLE_IOS +	// Force list even when there is only a single target +	project->properties["targets"].flags |= SettingsSingleItem; +#endif  	_project.add(project);  } @@ -483,7 +646,7 @@ void XCodeProvider::setupResourcesBuildPhase() {  			ADD_SETTING_ORDER_NOVALUE(files, getHash(id), comment, order++);  			// TODO Fix crash when adding build file for data  			//ADD_BUILD_FILE(id, *file, comment); -			ADD_FILE_REFERENCE(*file, properties[*file]); +			ADD_FILE_REFERENCE(*file, *file, properties[*file]);  		}  		// Add custom files depending on the target @@ -504,7 +667,36 @@ void XCodeProvider::setupResourcesBuildPhase() {  }  void XCodeProvider::setupSourcesBuildPhase() { -	// TODO +	_sourcesBuildPhase.comment = "PBXSourcesBuildPhase"; + +	// Setup source file properties +	std::map<std::string, FileProperty> properties; + +	// Same as for containers: a rule for each native target +	for (unsigned int i = 0; i < _targets.size(); i++) { +		Object *source = new Object(this, "PBXSourcesBuildPhase_" + _targets[i], "PBXSourcesBuildPhase", "PBXSourcesBuildPhase", "", "Sources"); + +		source->addProperty("buildActionMask", "2147483647", "", SettingsNoValue); + +		Property files; +		files.hasOrder = true; +		files.flags = SettingsAsList; + +		int order = 0; +		for (std::vector<Object*>::iterator file = _buildFile.objects.begin(); file !=_buildFile.objects.end(); ++file) { +			if (!producesObjectFileOnOSX((*file)->name)) { +				continue; +			} +			std::string comment = (*file)->name + " in Sources"; +			ADD_SETTING_ORDER_NOVALUE(files, getHash((*file)->id), comment, order++); +		} + +		source->properties["files"] = files; + +		source->addProperty("runOnlyForDeploymentPostprocessing", "0", "", SettingsNoValue); + +		_sourcesBuildPhase.add(source); +	}  }  // Setup all build configurations @@ -516,9 +708,9 @@ void XCodeProvider::setupBuildConfiguration() {  	///****************************************  	// * iPhone  	// ****************************************/ - +#ifdef ENABLE_IOS  	// Debug -	Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[0] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); +	Object *iPhone_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Debug", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");  	Property iPhone_Debug;  	ADD_SETTING_QUOTE(iPhone_Debug, "ARCHS", "$(ARCHS_UNIVERSAL_IPHONE_OS)");  	ADD_SETTING_QUOTE(iPhone_Debug, "CODE_SIGN_IDENTITY", "iPhone Developer"); @@ -539,10 +731,10 @@ void XCodeProvider::setupBuildConfiguration() {  	ADD_SETTING(iPhone_Debug, "GCC_THUMB_SUPPORT", "NO");  	ADD_SETTING(iPhone_Debug, "GCC_UNROLL_LOOPS", "YES");  	ValueList iPhone_HeaderSearchPaths; -	iPhone_HeaderSearchPaths.push_back("../../engines/"); -	iPhone_HeaderSearchPaths.push_back("../../"); +	iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/"); +	iPhone_HeaderSearchPaths.push_back("$(SRCROOT)");  	iPhone_HeaderSearchPaths.push_back("include/"); -	ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, SettingsAsList|SettingsNoQuote, 5); +	ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, SettingsAsList|SettingsQuoteVariable, 5);  	ADD_SETTING(iPhone_Debug, "INFOPLIST_FILE", "Info.plist");  	ValueList iPhone_LibPaths;  	iPhone_LibPaths.push_back("$(inherited)"); @@ -560,7 +752,7 @@ void XCodeProvider::setupBuildConfiguration() {  	iPhone_Debug_Object->properties["buildSettings"] = iPhone_Debug;  	// Release -	Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[0] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); +	Object *iPhone_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-iPhone_Release", _targets[IOS_TARGET] /* ScummVM-iPhone */, "XCBuildConfiguration", "PBXNativeTarget", "Release");  	Property iPhone_Release(iPhone_Debug);  	ADD_SETTING(iPhone_Release, "GCC_OPTIMIZATION_LEVEL", "3");  	ADD_SETTING(iPhone_Release, "COPY_PHASE_STRIP", "YES"); @@ -572,7 +764,7 @@ void XCodeProvider::setupBuildConfiguration() {  	_buildConfiguration.add(iPhone_Debug_Object);  	_buildConfiguration.add(iPhone_Release_Object); - +#endif  	/****************************************  	 * scummvm  	 ****************************************/ @@ -581,13 +773,14 @@ void XCodeProvider::setupBuildConfiguration() {  	Object *scummvm_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_NAME "_Debug", PROJECT_NAME, "XCBuildConfiguration", "PBXProject", "Debug");  	Property scummvm_Debug;  	ADD_SETTING(scummvm_Debug, "ALWAYS_SEARCH_USER_PATHS", "NO"); +	ADD_SETTING_QUOTE(scummvm_Debug, "USER_HEADER_SEARCH_PATHS", "$(SRCROOT) $(SRCROOT)/engines");  	ADD_SETTING_QUOTE(scummvm_Debug, "ARCHS", "$(ARCHS_STANDARD_32_BIT)");  	ADD_SETTING_QUOTE(scummvm_Debug, "CODE_SIGN_IDENTITY", "Don't Code Sign");  	ADD_SETTING_QUOTE_VAR(scummvm_Debug, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "Don't Code Sign");  	ADD_SETTING_QUOTE(scummvm_Debug, "FRAMEWORK_SEARCH_PATHS", "");  	ADD_SETTING(scummvm_Debug, "GCC_C_LANGUAGE_STANDARD", "c99");  	ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); -	ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_RTTI", "NO"); +	ADD_SETTING(scummvm_Debug, "GCC_ENABLE_CPP_RTTI", "YES");  	ADD_SETTING(scummvm_Debug, "GCC_INPUT_FILETYPE", "automatic");  	ADD_SETTING(scummvm_Debug, "GCC_OPTIMIZATION_LEVEL", "0");  	ValueList scummvm_defines(_defines); @@ -601,15 +794,15 @@ void XCodeProvider::setupBuildConfiguration() {  	ADD_SETTING(scummvm_Debug, "GCC_WARN_UNUSED_VARIABLE", "YES");  	ValueList scummvm_HeaderPaths;  	scummvm_HeaderPaths.push_back("include/"); -	scummvm_HeaderPaths.push_back("../../engines/"); -	scummvm_HeaderPaths.push_back("../../"); -	ADD_SETTING_LIST(scummvm_Debug, "HEADER_SEARCH_PATHS", scummvm_HeaderPaths, SettingsNoQuote|SettingsAsList, 5); +	scummvm_HeaderPaths.push_back("$(SRCROOT)/engines/"); +	scummvm_HeaderPaths.push_back("$(SRCROOT)"); +	ADD_SETTING_LIST(scummvm_Debug, "HEADER_SEARCH_PATHS", scummvm_HeaderPaths, SettingsQuoteVariable|SettingsAsList, 5);  	ADD_SETTING_QUOTE(scummvm_Debug, "LIBRARY_SEARCH_PATHS", "");  	ADD_SETTING(scummvm_Debug, "ONLY_ACTIVE_ARCH", "YES");  	ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_CFLAGS", "");  	ADD_SETTING_QUOTE(scummvm_Debug, "OTHER_LDFLAGS", "-lz");  	ADD_SETTING(scummvm_Debug, "PREBINDING", "NO"); -	ADD_SETTING(scummvm_Debug, "SDKROOT", "macosx10.6"); +	ADD_SETTING(scummvm_Debug, "SDKROOT", "macosx");  	scummvm_Debug_Object->addProperty("name", "Debug", "", SettingsNoValue);  	scummvm_Debug_Object->properties["buildSettings"] = scummvm_Debug; @@ -633,7 +826,7 @@ void XCodeProvider::setupBuildConfiguration() {  	 ****************************************/  	// Debug -	Object *scummvmOSX_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Debug", _targets[1] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); +	Object *scummvmOSX_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Debug", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");  	Property scummvmOSX_Debug;  	ADD_SETTING_QUOTE(scummvmOSX_Debug, "ARCHS", "$(NATIVE_ARCH)");  	ADD_SETTING(scummvmOSX_Debug, "COMPRESS_PNG_FILES", "NO"); @@ -642,7 +835,7 @@ void XCodeProvider::setupBuildConfiguration() {  	ADD_SETTING_QUOTE(scummvmOSX_Debug, "FRAMEWORK_SEARCH_PATHS", "");  	ADD_SETTING(scummvmOSX_Debug, "GCC_C_LANGUAGE_STANDARD", "c99");  	ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); -	ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "NO"); +	ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "YES");  	ADD_SETTING(scummvmOSX_Debug, "GCC_DYNAMIC_NO_PIC", "NO");  	ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_FIX_AND_CONTINUE", "NO");  	ADD_SETTING(scummvmOSX_Debug, "GCC_OPTIMIZATION_LEVEL", "0"); @@ -656,11 +849,12 @@ void XCodeProvider::setupBuildConfiguration() {  	ValueList scummvmOSX_HeaderPaths;  	scummvmOSX_HeaderPaths.push_back("/opt/local/include/SDL");  	scummvmOSX_HeaderPaths.push_back("/opt/local/include"); +	scummvmOSX_HeaderPaths.push_back("/opt/local/include/freetype2");  	scummvmOSX_HeaderPaths.push_back("include/"); -	scummvmOSX_HeaderPaths.push_back("../../engines/"); -	scummvmOSX_HeaderPaths.push_back("../../"); -	ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, SettingsNoQuote|SettingsAsList, 5); -	ADD_SETTING_QUOTE(scummvmOSX_Debug, "INFOPLIST_FILE", "$(SRCROOT)/../macosx/Info.plist"); +	scummvmOSX_HeaderPaths.push_back("$(SRCROOT)/engines/"); +	scummvmOSX_HeaderPaths.push_back("$(SRCROOT)"); +	ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, SettingsQuoteVariable|SettingsAsList, 5); +	ADD_SETTING_QUOTE(scummvmOSX_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/macosx/Info.plist");  	ValueList scummvmOSX_LibPaths;  	scummvmOSX_LibPaths.push_back("/sw/lib");  	scummvmOSX_LibPaths.push_back("/opt/local/lib"); @@ -671,6 +865,10 @@ void XCodeProvider::setupBuildConfiguration() {  	ValueList scummvmOSX_LdFlags;  	scummvmOSX_LdFlags.push_back("-lSDLmain");  	scummvmOSX_LdFlags.push_back("-logg"); +	scummvmOSX_LdFlags.push_back("-lpng"); +	scummvmOSX_LdFlags.push_back("-ljpeg"); +	scummvmOSX_LdFlags.push_back("-ltheora"); +	scummvmOSX_LdFlags.push_back("-lfreetype");  	scummvmOSX_LdFlags.push_back("-lvorbisfile");  	scummvmOSX_LdFlags.push_back("-lvorbis");  	scummvmOSX_LdFlags.push_back("-lmad"); @@ -685,7 +883,7 @@ void XCodeProvider::setupBuildConfiguration() {  	scummvmOSX_Debug_Object->properties["buildSettings"] = scummvmOSX_Debug;  	// Release -	Object *scummvmOSX_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Release", _targets[1] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); +	Object *scummvmOSX_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-OSX_Release", _targets[OSX_TARGET] /* ScummVM-OS X */, "XCBuildConfiguration", "PBXNativeTarget", "Release");  	Property scummvmOSX_Release(scummvmOSX_Debug);  	ADD_SETTING(scummvmOSX_Release, "COPY_PHASE_STRIP", "YES");  	REMOVE_SETTING(scummvmOSX_Release, "GCC_DYNAMIC_NO_PIC"); @@ -697,13 +895,13 @@ void XCodeProvider::setupBuildConfiguration() {  	_buildConfiguration.add(scummvmOSX_Debug_Object);  	_buildConfiguration.add(scummvmOSX_Release_Object); - +#ifdef ENABLE_IOS  	/****************************************  	 * ScummVM-Simulator  	 ****************************************/  	// Debug -	Object *scummvmSimulator_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Debug", _targets[2] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Debug"); +	Object *scummvmSimulator_Debug_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Debug", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Debug");  	Property scummvmSimulator_Debug(iPhone_Debug);  	ADD_SETTING_QUOTE(scummvmSimulator_Debug, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");  	ADD_SETTING_LIST(scummvmSimulator_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvm_defines, SettingsNoQuote|SettingsAsList, 5); @@ -715,7 +913,7 @@ void XCodeProvider::setupBuildConfiguration() {  	scummvmSimulator_Debug_Object->properties["buildSettings"] = scummvmSimulator_Debug;  	// Release -	Object *scummvmSimulator_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Release", _targets[2] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Release"); +	Object *scummvmSimulator_Release_Object = new Object(this, "XCBuildConfiguration_" PROJECT_DESCRIPTION "-Simulator_Release", _targets[SIM_TARGET] /* ScummVM-Simulator */, "XCBuildConfiguration", "PBXNativeTarget", "Release");  	Property scummvmSimulator_Release(scummvmSimulator_Debug);  	ADD_SETTING(scummvmSimulator_Release, "COPY_PHASE_STRIP", "YES");  	ADD_SETTING(scummvmSimulator_Release, "GCC_OPTIMIZATION_LEVEL", "3"); @@ -732,7 +930,7 @@ void XCodeProvider::setupBuildConfiguration() {  	// Configuration List  	_configurationList.comment = "XCConfigurationList";  	_configurationList.flags = SettingsAsList; - +#endif  	// Warning: This assumes we have all configurations with a Debug & Release pair  	for (std::vector<Object *>::iterator config = _buildConfiguration.objects.begin(); config != _buildConfiguration.objects.end(); config++) { @@ -772,7 +970,6 @@ void XCodeProvider::setupDefines(const BuildSetup &setup) {  	ADD_DEFINE(_defines, "SCUMM_LITTLE_ENDIAN");  	ADD_DEFINE(_defines, "UNIX");  	ADD_DEFINE(_defines, "SCUMMVM"); -	ADD_DEFINE(_defines, "USE_TREMOR");  }  ////////////////////////////////////////////////////////////////////////// @@ -847,7 +1044,9 @@ std::string XCodeProvider::writeProperty(const std::string &variable, Property &  		output += writeSetting((*setting).first, (*setting).second); -		if ((prop.flags & SettingsAsList) && prop.settings.size() > 1) { +		// The combination of SettingsAsList, and SettingsSingleItem should use "," and not ";" (i.e children +		// in PBXGroup, so we special case that case here. +		if ((prop.flags & SettingsAsList) && (prop.settings.size() > 1 || (prop.flags & SettingsSingleItem))) {  			output += (prop.settings.size() > 0) ? ",\n" : "\n";  		} else {  			output += ";"; diff --git a/devtools/create_project/xcode.h b/devtools/create_project/xcode.h index f86e7c555c..d49be93de2 100644 --- a/devtools/create_project/xcode.h +++ b/devtools/create_project/xcode.h @@ -45,7 +45,6 @@ protected:  	void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,  	                            const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); -  private:  	enum {  		SettingsAsList        = 0x01, @@ -210,9 +209,10 @@ private:  			return output;  		} -	private: +	// Slight hack, to allow Group access to parent. +	protected:  		XCodeProvider *parent; - +	private:  		// Returns the type property (should always be the first in the properties map)  		std::string getType() {  			assert(!properties.empty()); @@ -258,6 +258,36 @@ private:  		}  	}; +	// A class to maintain a folder-reference group-hierarchy, which together with the functionality below +	// allows for breaking up sub-paths into a chain of groups. This helps with merging engines into the +	// overall group-layout. +	class Group : public Object { +		int _childOrder; +		std::map<std::string, Group *> _childGroups; +		std::string _treeName; +		void addChildInternal(const std::string &id, const std::string &comment); +	public: +		Group(XCodeProvider *objectParent, const std::string &groupName, const std::string &uniqueName, const std::string &path); +		void addChildFile(const std::string &name); +		void addChildByHash(const std::string &hash, const std::string &name); +		// Should be passed the hash for the entry +		void addChildGroup(const Group* group); +		void ensureChildExists(const std::string &name); +		Group *getChildGroup(const std::string &name); +		std::string getHashRef() const { return parent->getHash(id); } +	}; + +	// The path used by the root-source group +	std::string _projectRoot; +	// The base source group, currently also re-purposed for containing the various support-groups. +	Group *_rootSourceGroup; +	// Helper function to create the chain of groups for the various subfolders. Necessary as +	// create_project likes to start in engines/ +	Group *touchGroupsForPath(const std::string &path); +	// Functionality for adding file-refs and build-files, as Group-objects need to be able to do this. +	void addFileReference(const std::string &id, const std::string &name, FileProperty properties); +	void addProductFileReference(const std::string &id, const std::string &name); +	void addBuildFile(const std::string &id, const std::string &name, const std::string &fileRefId, const std::string &comment);  	// All objects  	std::map<std::string, std::string> _hashDictionnary;  	ValueList _defines;  | 
