aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2015-04-09 19:19:20 +0200
committerEinar Johan Trøan Sømåen2015-04-09 20:02:17 +0200
commit790f7dc0178b05a519b9e353e8e6d542ae6d9cf9 (patch)
tree2d3a519a34f4bf331200ac67dc68cc46b6771b6d
parent000b80263c46287843b5859d84cfb6fcaf3363ff (diff)
downloadscummvm-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.
-rw-r--r--devtools/create_project/xcode.cpp206
-rw-r--r--devtools/create_project/xcode.h35
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;