diff options
author | Einar Johan Trøan Sømåen | 2015-04-09 19:19:20 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2015-04-09 20:02:17 +0200 |
commit | 790f7dc0178b05a519b9e353e8e6d542ae6d9cf9 (patch) | |
tree | 2d3a519a34f4bf331200ac67dc68cc46b6771b6d /devtools/create_project | |
parent | 000b80263c46287843b5859d84cfb6fcaf3363ff (diff) | |
download | scummvm-rg350-790f7dc0178b05a519b9e353e8e6d542ae6d9cf9.tar.gz scummvm-rg350-790f7dc0178b05a519b9e353e8e6d542ae6d9cf9.tar.bz2 scummvm-rg350-790f7dc0178b05a519b9e353e8e6d542ae6d9cf9.zip |
CREATE_PROJECT: Introduce a subclass of Object to manage group-creation.
This rewrites the way groups are created, so that the root source folder has groups created for any subfolder that is used, which allows for
merging in the engines/-subfolder automatically.
Diffstat (limited to 'devtools/create_project')
-rw-r--r-- | devtools/create_project/xcode.cpp | 206 | ||||
-rw-r--r-- | devtools/create_project/xcode.h | 35 |
2 files changed, 157 insertions, 84 deletions
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index 20525af2d8..ab94bdc05f 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -80,15 +80,135 @@ namespace CreateProjectTool { _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::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 @@ -178,84 +298,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"; - - // We use only the last path component for paths, as every folder gets its own group, - // and subfolders then only need to specify their path relative to their parent folder. - std::string path = getLastPathComponent(dir.name); - std::string name = path; - // We need to use the prefix-name to make sure that the hashes become unique for folders - // that have the same name. - std::string prefixName = objPrefix; - std::string groupName; - // Special case handling for the root-node - if (indentation == 0) { // Indentation level 0 is the root - // Hard-code the name, so that we can use it as mainGroup - name = "CustomTemplate"; - // Should already be "", but lets make sure. - assert(prefixName == ""); - groupName = "PBXGroup_" + name; - } else { - groupName = "PBXGroup_" + prefixName; - } - // Create group - Object *group = new Object(this, groupName , "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); - // Sub-groups below the root need to have their relative path set (relative to their parent group) - if (indentation != 0) { - group->addProperty("path", path, "", 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>\""); - - // If it is a folder, create a group with a hash made from the concatenated name of the node and - // all its parents, this way, the various folders with the same name (i.e. sdl a bunch of places - // in backends) gets unique hashes, instead of the same hash becoming the child of multiple groups. - if (!node->children.empty()) { - ADD_SETTING_ORDER_NOVALUE(children, getHash("PBXGroup_" + prefixName + node->name + "_"), node->name, order++); - } else { - // Otherwise, simply hash the filename, and hope that we don't get conflicts on those. (Seems to work so far) - ADD_SETTING_ORDER_NOVALUE(children, getHash(node->name), node->name, order++); - } // 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()) { - ADD_BUILD_FILE(id, node->name, node->name + " in Sources"); - ADD_FILE_REFERENCE(node->name, property); + group->addChildFile(node->name); } // Process child nodes if (!node->children.empty()) writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/'); } - if (order == 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) - children.flags |= SettingsSingleItem; - } - if (indentation == 0) { - // Add any root-groups to the very bottom (Frameworks-etc) - for (std::vector<Object*>::iterator it = _rootGroups.objects.begin(); it != _rootGroups.objects.end(); ++it) { - ADD_SETTING_ORDER_NOVALUE(children, getHash((*it)->id), (*it)->id, order++); - } - } - group->properties["children"] = children; - - _groups.add(group); } ////////////////////////////////////////////////////////////////////////// @@ -487,7 +543,7 @@ void XCodeProvider::setupProject() { ADD_SETTING_ORDER_NOVALUE(regions, "German", "", 3); project->properties["knownRegions"] = regions; - project->addProperty("mainGroup", getHash("PBXGroup_CustomTemplate"), "CustomTemplate", SettingsNoValue); + project->addProperty("mainGroup", _rootSourceGroup->getHashRef(), "CustomTemplate", SettingsNoValue); project->addProperty("projectDirPath", "", "", SettingsNoValue|SettingsQuoteVariable); project->addProperty("projectRoot", "", "", SettingsNoValue|SettingsQuoteVariable); @@ -587,18 +643,6 @@ void XCodeProvider::setupResourcesBuildPhase() { } } -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; -} - void XCodeProvider::setupSourcesBuildPhase() { _sourcesBuildPhase.comment = "PBXSourcesBuildPhase"; diff --git a/devtools/create_project/xcode.h b/devtools/create_project/xcode.h index b02cb5b75c..792fa06d8b 100644 --- a/devtools/create_project/xcode.h +++ b/devtools/create_project/xcode.h @@ -46,7 +46,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: - std::string _projectRoot; enum { SettingsAsList = 0x01, SettingsSingleItem = 0x02, @@ -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,35 @@ 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 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; |