Browse Source

Projucer: Enabled adding Xcode subprojects

tags/2021-05-28
Tom Poole 7 years ago
parent
commit
885168568d
11 changed files with 459 additions and 32 deletions
  1. +8
    -0
      extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj
  2. +1
    -0
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj
  3. +3
    -0
      extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters
  4. +1
    -0
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj
  5. +3
    -0
      extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters
  6. +1
    -0
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
  7. +3
    -0
      extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
  8. +2
    -0
      extras/Projucer/Projucer.jucer
  9. +194
    -32
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h
  10. +242
    -0
      extras/Projucer/Source/ProjectSaving/jucer_XcodeProjectParser.h
  11. +1
    -0
      extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h

+ 8
- 0
extras/Projucer/Builds/MacOSX/Projucer.xcodeproj/project.pbxproj View File

@@ -374,6 +374,13 @@
path = "../../Source/Application/jucer_CommandLine.cpp";
sourceTree = "SOURCE_ROOT";
};
044478BB994878E35D30154A = {
isa = PBXFileReference;
lastKnownFileType = sourcecode.c.h;
name = "jucer_XcodeProjectParser.h";
path = "../../Source/ProjectSaving/jucer_XcodeProjectParser.h";
sourceTree = "SOURCE_ROOT";
};
0462692BAA9CD1BE6DFBCC33 = {
isa = PBXFileReference;
lastKnownFileType = sourcecode.cpp.objcpp;
@@ -2985,6 +2992,7 @@
9EE3141E20C9CE3EA182FA04,
E13A54A6D3A1895EACE53E51,
25BE1265FE6C6EA3473A3A0A,
044478BB994878E35D30154A,
);
name = ProjectSaving;
sourceTree = "<group>";


+ 1
- 0
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj View File

@@ -1611,6 +1611,7 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_StoredSettings.h"/>
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.h"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2013/Projucer_App.vcxproj.filters View File

@@ -2283,6 +2283,9 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h">
<Filter>Projucer\Settings</Filter>
</ClInclude>


+ 1
- 0
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj View File

@@ -1611,6 +1611,7 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_StoredSettings.h"/>
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.h"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2015/Projucer_App.vcxproj.filters View File

@@ -2283,6 +2283,9 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h">
<Filter>Projucer\Settings</Filter>
</ClInclude>


+ 1
- 0
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj View File

@@ -1613,6 +1613,7 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectExporter.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ProjectSaver.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h"/>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h"/>
<ClInclude Include="..\..\Source\Settings\jucer_StoredSettings.h"/>
<ClInclude Include="..\..\Source\Utility\Helpers\jucer_CodeHelpers.h"/>


+ 3
- 0
extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters View File

@@ -2283,6 +2283,9 @@
<ClInclude Include="..\..\Source\ProjectSaving\jucer_ResourceFile.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\ProjectSaving\jucer_XcodeProjectParser.h">
<Filter>Projucer\ProjectSaving</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\Settings\jucer_AppearanceSettings.h">
<Filter>Projucer\Settings</Filter>
</ClInclude>


+ 2
- 0
extras/Projucer/Projucer.jucer View File

@@ -608,6 +608,8 @@
file="Source/ProjectSaving/jucer_ResourceFile.cpp"/>
<FILE id="d4INvx" name="jucer_ResourceFile.h" compile="0" resource="0"
file="Source/ProjectSaving/jucer_ResourceFile.h"/>
<FILE id="kw0nyx" name="jucer_XcodeProjectParser.h" compile="0" resource="0"
file="Source/ProjectSaving/jucer_XcodeProjectParser.h"/>
</GROUP>
<GROUP id="{DC7C1395-DD88-0C6C-2D8A-EC48A63D31E8}" name="Settings">
<FILE id="DsopUB" name="jucer_AppearanceSettings.cpp" compile="1" resource="0"


+ 194
- 32
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h View File

@@ -26,6 +26,7 @@
#pragma once
#include "jucer_XcodeProjectParser.h"
//==============================================================================
namespace
@@ -61,6 +62,7 @@ public:
customPListValue (settings, Ids::customPList, getUndoManager()),
pListPrefixHeaderValue (settings, Ids::pListPrefixHeader, getUndoManager()),
pListPreprocessValue (settings, Ids::pListPreprocess, getUndoManager()),
subprojectsValue (settings, Ids::xcodeSubprojects, getUndoManager()),
extraFrameworksValue (settings, Ids::extraFrameworks, getUndoManager()),
frameworkSearchPathsValue (settings, Ids::frameworkSearchPaths, getUndoManager()),
extraCustomFrameworksValue (settings, Ids::extraCustomFrameworks, getUndoManager()),
@@ -112,6 +114,8 @@ public:
String getPListPrefixHeaderString() const { return pListPrefixHeaderValue.get(); }
bool isPListPreprocessEnabled() const { return pListPreprocessValue.get(); }
String getSubprojectsString() const { return subprojectsValue.get(); }
String getExtraFrameworksString() const { return extraFrameworksValue.get(); }
String getFrameworkSearchPathsString() const { return frameworkSearchPathsValue.get(); }
String getExtraCustomFrameworksString() const { return extraCustomFrameworksValue.get(); }
@@ -317,6 +321,12 @@ public:
"If you are adding a framework here then you do not need to specify it in Extra Custom Frameworks too. "
"You will probably need to add an entry to the Framework Search Paths for each unique directory.");
props.add (new TextPropertyComponent (subprojectsValue, "Xcode Subprojects", 8192, true),
"Paths to Xcode projects that should be added to the build (one per line). "
"The names of the required build products can be specified after a colon, comma seperated, "
"e.g. \"path/to/MySubProject.xcodeproj: MySubProject, OtherTarget\". "
"If no build products are specified, all build products associated with a subproject will be added.");
props.add (new TextPropertyComponent (prebuildCommandValue, "Pre-Build Shell Script", 32768, true),
"Some shell-script that will be run before a build starts.");
@@ -1105,8 +1115,8 @@ public:
if (type == Target::SharedCodeTarget)
s.set ("SKIP_INSTALL", "YES");
if (! owner.getEmbeddedFrameworks().isEmpty())
s.set ("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks\"");
if (! owner.embeddedFrameworkIDs.isEmpty())
s.set ("LD_RUNPATH_SEARCH_PATHS", "\"$(inherited) @executable_path/Frameworks @executable_path/../Frameworks\"");
if (xcodeCopyToProductInstallPathAfterBuild)
{
@@ -1769,14 +1779,18 @@ private:
mutable OwnedArray<ValueTree> pbxBuildFiles, pbxFileReferences, pbxGroups, misc, projectConfigs, targetConfigs;
mutable StringArray resourceIDs, sourceIDs, targetIDs;
mutable StringArray frameworkFileIDs, rezFileIDs, resourceFileRefs;
mutable StringArray frameworkFileIDs, embeddedFrameworkIDs, rezFileIDs, resourceFileRefs, subprojectFileIDs;
mutable Array<std::pair<String, String>> subprojectReferences;
mutable File menuNibFile, iconFile;
mutable StringArray buildProducts;
const bool iOS;
ValueWithDefault customPListValue, pListPrefixHeaderValue, pListPreprocessValue, extraFrameworksValue, frameworkSearchPathsValue, extraCustomFrameworksValue, embeddedFrameworksValue,
postbuildCommandValue, prebuildCommandValue, duplicateAppExResourcesFolderValue, iosDeviceFamilyValue, iPhoneScreenOrientationValue,
ValueWithDefault customPListValue, pListPrefixHeaderValue, pListPreprocessValue,
subprojectsValue,
extraFrameworksValue, frameworkSearchPathsValue, extraCustomFrameworksValue, embeddedFrameworksValue,
postbuildCommandValue, prebuildCommandValue,
duplicateAppExResourcesFolderValue, iosDeviceFamilyValue, iPhoneScreenOrientationValue,
iPadScreenOrientationValue, customXcodeResourceFoldersValue, customXcassetsFolderValue,
microphonePermissionNeededValue, microphonePermissionsTextValue, cameraPermissionNeededValue, cameraPermissionTextValue,
uiFileSharingEnabledValue, uiSupportsDocumentBrowserValue, uiStatusBarHiddenValue, documentExtensionsValue, iosInAppPurchasesValue,
@@ -1803,9 +1817,14 @@ private:
{
prepareTargets();
// Must be called before adding embedded frameworks, as we want to
// embed any frameworks found in subprojects.
addSubprojects();
addFrameworks();
addCustomFrameworks();
addEmbeddedFrameworks();
addCustomResourceFolders();
addPlistFileReferences();
@@ -1948,6 +1967,13 @@ private:
addGroup (productsGroupID, "Products", buildProducts);
topLevelGroupIDs.add (productsGroupID);
}
if (! subprojectFileIDs.isEmpty())
{
auto subprojectLibrariesGroupID = createID ("__subprojects");
addGroup (subprojectLibrariesGroupID, "Subprojects", subprojectFileIDs);
topLevelGroupIDs.add (subprojectLibrariesGroupID);
}
}
void addBuildPhases() const
@@ -2479,12 +2505,9 @@ private:
void addEmbeddedFrameworks() const
{
auto frameworks = getEmbeddedFrameworks();
if (frameworks.isEmpty())
return;
StringArray embeddedFrameworkIDs;
StringArray frameworks;
frameworks.addTokens (getEmbeddedFrameworksString(), true);
frameworks.trim();
for (auto& framework : frameworks)
{
@@ -2498,17 +2521,9 @@ private:
}
}
for (auto& target : targets)
target->addCopyFilesPhase ("Embed Frameworks", embeddedFrameworkIDs, kFrameworksFolder);
}
StringArray getEmbeddedFrameworks() const
{
StringArray frameworks;
frameworks.addTokens (getEmbeddedFrameworksString(), true);
frameworks.trim();
return frameworks;
if (! embeddedFrameworkIDs.isEmpty())
for (auto& target : targets)
target->addCopyFilesPhase ("Embed Frameworks", embeddedFrameworkIDs, kFrameworksFolder);
}
void addCustomResourceFolders() const
@@ -2523,6 +2538,104 @@ private:
addCustomResourceFolder (crf);
}
void addSubprojects() const
{
auto subprojectLines = StringArray::fromLines (getSubprojectsString());
subprojectLines.removeEmptyStrings (true);
Array<std::pair<String, StringArray>> subprojects;
for (auto& line : subprojectLines)
{
String subprojectName (line.upToFirstOccurrenceOf (":", false, false));
StringArray requestedBuildProducts (StringArray::fromTokens (line.fromFirstOccurrenceOf (":", false, false), ",;|", "\"'"));
requestedBuildProducts.trim();
subprojects.add ({ subprojectName, requestedBuildProducts });
}
for (const auto& subprojectInfo : subprojects)
{
String subprojectPath (subprojectInfo.first);
if (! subprojectPath.endsWith (".xcodeproj"))
subprojectPath += ".xcodeproj";
File subprojectFile;
if (File::isAbsolutePath (subprojectPath))
{
subprojectFile = subprojectPath;
}
else
{
subprojectFile = getProject().getProjectFolder().getChildFile (subprojectPath);
RelativePath p (subprojectPath, RelativePath::projectFolder);
subprojectPath = p.rebased (getProject().getProjectFolder(), getTargetFolder(), RelativePath::buildTargetFolder).toUnixStyle();
}
if (! subprojectFile.isDirectory())
continue;
auto availableBuildProducts = XcodeProjectParser::parseBuildProducts (subprojectFile);
// If no build products have been specified then we'll take everything
if (! subprojectInfo.second.isEmpty())
{
auto newEnd = std::remove_if (availableBuildProducts.begin(), availableBuildProducts.end(),
[&subprojectInfo](const std::pair<String, String> &item)
{
return ! subprojectInfo.second.contains (item.first);
});
availableBuildProducts.erase (newEnd, availableBuildProducts.end());
}
if (availableBuildProducts.empty())
continue;
auto subprojectFileType = getFileType (RelativePath (subprojectPath, RelativePath::projectFolder));
auto subprojectFileID = addFileOrFolderReference (subprojectPath, "<group>", subprojectFileType);
subprojectFileIDs.add (subprojectFileID);
StringArray proxyIDs;
for (auto& buildProduct : availableBuildProducts)
{
auto buildProductFileType = getFileType (RelativePath (buildProduct.second, RelativePath::projectFolder));
auto containerID = addContainerItemProxy (subprojectFileID, buildProduct.first);
auto proxyID = addReferenceProxy (containerID, buildProduct.second, buildProductFileType);
proxyIDs.add (proxyID);
if (buildProductFileType == "archive.ar" || buildProductFileType == "wrapper.framework")
{
auto buildFileID = addBuildFile (buildProduct.second, proxyID, false, true);
for (auto& target : targets)
target->frameworkIDs.add (buildFileID);
if (buildProductFileType == "wrapper.framework")
{
auto fileID = createID (buildProduct.second + "buildref");
auto* v = new ValueTree (fileID);
v->setProperty ("isa", "PBXBuildFile", nullptr);
v->setProperty ("fileRef", proxyID, nullptr);
v->setProperty ("settings", "{ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }", nullptr);
pbxBuildFiles.add (v);
embeddedFrameworkIDs.add (fileID);
}
}
}
auto productGroupID = createFileRefID (subprojectPath + "_products");
addGroup (productGroupID, "Products", proxyIDs);
subprojectReferences.add ({ productGroupID, subprojectFileID });
}
}
void addXcassets() const
{
auto customXcassetsPath = getCustomXcassetsFolderString();
@@ -2635,17 +2748,8 @@ private:
return addFileOrFolderReference (pathString, sourceTree, fileType);
}
String addFileOrFolderReference (String pathString, String sourceTree, String fileType) const
void checkAndAddFileReference (std::unique_ptr<ValueTree> v) const
{
auto fileRefID = createFileRefID (pathString);
std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
v->setProperty ("isa", "PBXFileReference", nullptr);
v->setProperty ("lastKnownFileType", fileType, nullptr);
v->setProperty (Ids::name, pathString.fromLastOccurrenceOf ("/", false, false), nullptr);
v->setProperty ("path", pathString, nullptr);
v->setProperty ("sourceTree", sourceTree, nullptr);
auto existing = pbxFileReferences.indexOfSorted (*this, v.get());
if (existing >= 0)
@@ -2657,6 +2761,53 @@ private:
{
pbxFileReferences.addSorted (*this, v.release());
}
}
String addFileOrFolderReference (const String& pathString, String sourceTree, String fileType) const
{
auto fileRefID = createFileRefID (pathString);
std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
v->setProperty ("isa", "PBXFileReference", nullptr);
v->setProperty ("lastKnownFileType", fileType, nullptr);
v->setProperty (Ids::name, pathString.fromLastOccurrenceOf ("/", false, false), nullptr);
v->setProperty ("path", pathString, nullptr);
v->setProperty ("sourceTree", sourceTree, nullptr);
checkAndAddFileReference (std::move (v));
return fileRefID;
}
String addContainerItemProxy (const String& subprojectID, const String& itemName) const
{
auto uniqueString = subprojectID + "_" + itemName;
auto fileRefID = createFileRefID (uniqueString);
std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
v->setProperty ("isa", "PBXContainerItemProxy", nullptr);
v->setProperty ("containerPortal", subprojectID, nullptr);
v->setProperty ("proxyType", 2, nullptr);
v->setProperty ("remoteGlobalIDString", createFileRefID (uniqueString + "_global"), nullptr);
v->setProperty ("remoteInfo", itemName, nullptr);
checkAndAddFileReference (std::move (v));
return fileRefID;
}
String addReferenceProxy (const String& containerItemID, const String& proxyPath, const String& fileType) const
{
auto fileRefID = createFileRefID (containerItemID + "_" + proxyPath);
std::unique_ptr<ValueTree> v (new ValueTree (fileRefID));
v->setProperty ("isa", "PBXReferenceProxy", nullptr);
v->setProperty ("fileType", fileType, nullptr);
v->setProperty ("path", proxyPath, nullptr);
v->setProperty ("remoteRef", containerItemID, nullptr);
v->setProperty ("sourceTree", "BUILT_PRODUCTS_DIR", nullptr);
checkAndAddFileReference (std::move (v));
return fileRefID;
}
@@ -2996,6 +3147,17 @@ private:
v->setProperty ("hasScannedForEncodings", (int) 0, nullptr);
v->setProperty ("mainGroup", createID ("__mainsourcegroup"), nullptr);
v->setProperty ("projectDirPath", "\"\"", nullptr);
if (! subprojectReferences.isEmpty())
{
StringArray projectReferences;
for (auto& reference : subprojectReferences)
projectReferences.add (indentBracedList ({ "ProductGroup = " + reference.first, "ProjectRef = " + reference.second }, 1));
v->setProperty ("projectReferences", indentParenthesisedList (projectReferences), nullptr);
}
v->setProperty ("projectRoot", "\"\"", nullptr);
auto targetString = "(" + targetIDs.joinIntoString (", ") + ")";


+ 242
- 0
extras/Projucer/Source/ProjectSaving/jucer_XcodeProjectParser.h View File

@@ -0,0 +1,242 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
#include <regex>
//==============================================================================
class XcodeProjectParser
{
public:
//==============================================================================
static std::unique_ptr<HashMap<std::string, std::string>> parseObjects (const File& projectFile)
{
auto pbxprojs = projectFile.findChildFiles (File::TypesOfFileToFind::findFiles, false, "*.pbxproj");
if (pbxprojs.isEmpty())
{
jassertfalse;
return nullptr;
}
auto content = pbxprojs[0].loadFileAsString().toStdString();
std::regex comments ("/\\*.*?\\*/");
content = (std::regex_replace (content, comments, ""));
std::regex whitespace ("\\s+");
content = (std::regex_replace (content, whitespace, " "));
auto objects = std::make_unique<HashMap<std::string, std::string>>();
std::smatch objectsStartMatch;
if (! std::regex_search (content, objectsStartMatch, std::regex ("[ ;{]+objects *= *\\{")))
{
jassertfalse;
return nullptr;
}
auto strPtr = content.begin() + objectsStartMatch.position() + objectsStartMatch.length();
while (strPtr++ != content.end())
{
if (*strPtr == ' ' || *strPtr == ';')
continue;
if (*strPtr == '}')
break;
auto groupReference = parseObjectID (content, strPtr);
if (groupReference.empty())
{
jassertfalse;
return nullptr;
}
while (*strPtr == ' ' || *strPtr == '=')
{
if (++strPtr == content.end())
{
jassertfalse;
return nullptr;
}
}
auto bracedContent = parseBracedContent (content, strPtr);
if (bracedContent.empty())
return nullptr;
objects->set (groupReference, bracedContent);
}
jassert (strPtr <= content.end());
return objects;
}
static std::pair<std::string, std::string> findObjectMatching (const HashMap<std::string, std::string>& objects,
const std::regex& rgx)
{
HashMap<std::string, std::string>::Iterator it (objects);
std::smatch match;
while (it.next())
{
auto key = it.getValue();
if (std::regex_search (key, match, rgx))
return { it.getKey(), it.getValue() };
}
return {};
}
//==============================================================================
static std::vector<std::pair<String, String>> parseBuildProducts (const File& projectFile)
{
auto objects = parseObjects (projectFile);
if (objects == nullptr)
return {};
auto mainObject = findObjectMatching (*objects, std::regex ("[ ;{]+isa *= *PBXProject[ ;}]+"));
jassert (! mainObject.first.empty());
auto targetRefs = parseObjectItemList (mainObject.second, "targets");
jassert (! targetRefs.isEmpty());
std::vector<std::pair<String, String>> results;
for (auto& t : targetRefs)
{
auto targetRef = t.toStdString();
if (! objects->contains (targetRef))
{
jassertfalse;
continue;
}
auto name = parseObjectItemValue (objects->getReference (targetRef), "name");
if (name.empty())
continue;
auto productRef = parseObjectItemValue (objects->getReference (targetRef), "productReference");
if (productRef.empty())
continue;
if (! objects->contains (productRef))
{
jassertfalse;
continue;
}
auto path = parseObjectItemValue (objects->getReference (productRef), "path");
if (path.empty())
continue;
results.push_back ({ String (name).unquoted(), String (path).unquoted() });
}
return results;
}
private:
//==============================================================================
static std::string parseObjectID (std::string& content, std::string::iterator& ptr)
{
auto start = ptr;
while (ptr != content.end() && *ptr != ' ' && *ptr != ';' && *ptr != '=')
++ptr;
return ptr == content.end() ? std::string()
: content.substr ((size_t) std::distance (content.begin(), start),
(size_t) std::distance (start, ptr));
}
//==============================================================================
static std::string parseBracedContent (std::string& content, std::string::iterator& ptr)
{
jassert (*ptr == '{');
auto start = ++ptr;
auto braceDepth = 1;
while (ptr++ != content.end())
{
switch (*ptr)
{
case '{':
++braceDepth;
break;
case '}':
if (--braceDepth == 0)
return content.substr ((size_t) std::distance (content.begin(), start),
(size_t) std::distance (start, ptr));
}
}
jassertfalse;
return {};
}
//==============================================================================
static std::string parseObjectItemValue (const std::string& source, const std::string& key)
{
std::smatch match;
if (! std::regex_search (source, match, std::regex ("[ ;{]+" + key + " *= *(.*?)[ ;]+")))
{
jassertfalse;
return {};
}
return match[1];
}
//==============================================================================
static StringArray parseObjectItemList (const std::string& source, const std::string& key)
{
std::smatch match;
if (! std::regex_search (source, match, std::regex ("[ ;{]+" + key + " *= *\\((.*?)\\)")))
{
jassertfalse;
return {};
}
auto result = StringArray::fromTokens (String (match[1]), ", ", "");
result.removeEmptyStrings();
return result;
}
};

+ 1
- 0
extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h View File

@@ -125,6 +125,7 @@ namespace Ids
DECLARE_ID (osxCompatibility);
DECLARE_ID (osxArchitecture);
DECLARE_ID (iosCompatibility);
DECLARE_ID (xcodeSubprojects);
DECLARE_ID (extraFrameworks);
DECLARE_ID (frameworkSearchPaths);
DECLARE_ID (extraCustomFrameworks);


Loading…
Cancel
Save