From 7c797a5fedc6d01cc7120a504fd60b84a71235f0 Mon Sep 17 00:00:00 2001 From: ofTheo Date: Mon, 29 Jun 2020 15:41:32 -0700 Subject: [PATCH 1/6] adding ability to specify additional source/include folders to add to the project --- commandLine/src/main.cpp | 20 ++++++- .../src/projects/baseProject.cpp | 54 +++++++++++++++++++ .../src/projects/baseProject.h | 1 + .../src/projects/xcodeProject.cpp | 12 +++-- .../src/projects/xcodeProject.h | 1 + 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/commandLine/src/main.cpp b/commandLine/src/main.cpp index 07d67a7a..101abb9b 100644 --- a/commandLine/src/main.cpp +++ b/commandLine/src/main.cpp @@ -1,6 +1,6 @@ #include "ofMain.h" #include "optionparser.h" -enum optionIndex { UNKNOWN, HELP, PLUS, RECURSIVE, LISTTEMPLATES, PLATFORMS, ADDONS, OFPATH, VERBOSE, TEMPLATE, DRYRUN }; +enum optionIndex { UNKNOWN, HELP, PLUS, RECURSIVE, LISTTEMPLATES, PLATFORMS, ADDONS, OFPATH, VERBOSE, TEMPLATE, DRYRUN, SRCEXTRA }; constexpr option::Descriptor usage[] = { {UNKNOWN, 0, "", "",option::Arg::None, "Options:\n" }, @@ -13,6 +13,7 @@ constexpr option::Descriptor usage[] = {VERBOSE, 0,"v","verbose",option::Arg::None, " --verbose, -v \trun verbose" }, {TEMPLATE, 0,"t","template",option::Arg::Optional, " --template, -t \tproject template" }, {DRYRUN, 0,"d","dryrun",option::Arg::None, " --dryrun, -d \tdry run, don't change files" }, + {SRCEXTRA, 0,"s","source",option::Arg::Optional, " --source, -s \trelative or absolute path to source or include folders to add (such as ../../../../common_utils/" }, {0,0,0,0,0,0} }; @@ -56,6 +57,7 @@ std::string directoryForRecursion; std::string projectPath; std::string ofPath; std::vector addons; +std::vector srcPaths; std::vector targets; std::string ofPathEnv; std::string currentWorkingDirectory; @@ -257,6 +259,12 @@ void updateProject(std::string path, ofTargetPlatform target, bool bConsiderPara ofLogNotice() << "parsing addons.make"; project->parseAddons(); } + + if(!bDryRun){ + for(auto & srcPath : srcPaths){ + project->addSrcRecursively(srcPath); + } + } if (!bDryRun) project->save(); } @@ -405,7 +413,12 @@ int main(int argc, char* argv[]){ } } - + if (options[SRCEXTRA].count() > 0){ + if (options[SRCEXTRA].arg != NULL){ + std::string srcString(options[SRCEXTRA].arg); + srcPaths = ofSplitString(srcString, ",", true, true); + } + } if (options[OFPATH].count() > 0){ if (options[OFPATH].arg != NULL){ @@ -561,6 +574,9 @@ int main(int argc, char* argv[]){ for(auto & addon: addons){ project->addAddon(addon); } + for(auto & srcPath : srcPaths){ + project->addSrcRecursively(srcPath); + } } if (!bDryRun) project->save(); diff --git a/ofxProjectGenerator/src/projects/baseProject.cpp b/ofxProjectGenerator/src/projects/baseProject.cpp index 1d60d662..f41b808d 100644 --- a/ofxProjectGenerator/src/projects/baseProject.cpp +++ b/ofxProjectGenerator/src/projects/baseProject.cpp @@ -294,6 +294,60 @@ void baseProject::addAddon(std::string addonName){ } } +void baseProject::addSrcRecursively(std::string srcPath){ + vector srcFilesToAdd; + + //so we can just pass through the file paths + ofDisableDataPath(); + getFilesRecursively(srcPath, srcFilesToAdd); + ofEnableDataPath(); + + //need this for absolute paths so we can subtract this path from each file path + //say we add this path: /user/person/documents/shared_of_code + //we want folders added for shared_of_code/ and any subfolders, but not folders added for /user/ /user/person/ etc + string parentFolder = ofFilePath::getEnclosingDirectory(ofFilePath::removeTrailingSlash(srcPath)); + + for( auto & fileToAdd : srcFilesToAdd){ + + //if it is an absolute path it is easy - add the file and enclosing folder to the project + if( ofFilePath::isAbsolute(fileToAdd) ){ + string folder = ofFilePath::getEnclosingDirectory(fileToAdd,false); + + auto pos = folder.find_first_of(parentFolder); + + //just to be 100% sure - check if the parent folder path is at the beginning of the file path + //then remove it so we just get the folder structure of the actual src files being added and not the full path + if( pos == 0 ){ + folder = folder.substr(parentFolder.size()); + } + + ofLogVerbose() << " adding file " << fileToAdd << " in folder " << folder << " to project "; + addSrc(fileToAdd, folder); + }else{ + + //if it is a realtive path make the file relative to the project folder + auto absPath = ofFilePath::getAbsolutePath( ofFilePath::join(ofFilePath::getCurrentExeDir(), fileToAdd) ); + auto canPath = std::filesystem::canonical(absPath); //resolves the ./ and ../ to be the most minamlist absolute path + + //get the file path realtive to the project + auto projectPath = ofFilePath::getAbsolutePath( projectDir ); + auto relPathPathToAdd = ofFilePath::makeRelative(projectPath, canPath); + + //get the folder from the path and clean it up + string folder = ofFilePath::getEnclosingDirectory(relPathPathToAdd,false); + + ofStringReplace(folder, "../", ""); +#ifdef TARGET_WIN32 + ofStringReplace(folder, "..\\", ""); //do both just incase someone has used linux paths on windows +#endif + folder = ofFilePath::removeTrailingSlash(folder); + + ofLogVerbose() << " adding file " << fileToAdd << " in folder " << folder << " to project "; + addSrc(relPathPathToAdd, folder); + } + } +} + void baseProject::addAddon(ofAddon & addon){ for(int i=0;i<(int)addons.size();i++){ if(addons[i].name==addon.name) return; diff --git a/ofxProjectGenerator/src/projects/baseProject.h b/ofxProjectGenerator/src/projects/baseProject.h index c4048b10..52b7c671 100644 --- a/ofxProjectGenerator/src/projects/baseProject.h +++ b/ofxProjectGenerator/src/projects/baseProject.h @@ -67,6 +67,7 @@ class baseProject { virtual void addAddon(std::string addon); virtual void addAddon(ofAddon & addon); + virtual void addSrcRecursively(std::string srcPath); std::string getName() { return projectName;} std::string getPath() { return projectDir; } diff --git a/ofxProjectGenerator/src/projects/xcodeProject.cpp b/ofxProjectGenerator/src/projects/xcodeProject.cpp index 46fe139d..3618d58b 100644 --- a/ofxProjectGenerator/src/projects/xcodeProject.cpp +++ b/ofxProjectGenerator/src/projects/xcodeProject.cpp @@ -218,6 +218,7 @@ STRINGIFY( xcodeProject::xcodeProject(std::string target) :baseProject(target){ if( target == "osx" ){ + projRootUUID = "E4B69B4A0A3A1720003C02F2"; srcUUID = "E4B69E1C0A3A1BDC003C02F2"; addonUUID = "BB4B014C10F69532006C3DED"; localAddonUUID = "6948EE371B920CB800B5AC1A"; @@ -229,6 +230,7 @@ xcodeProject::xcodeProject(std::string target) frameworksBuildPhaseUUID = "E4328149138ABC9F0047C5CB"; }else{ + projRootUUID = "29B97314FDCFA39411CA2CEA"; srcUUID = "E4D8936A11527B74007E1F53"; addonUUID = "BB16F26B0F2B646B00518274"; localAddonUUID = "6948EE371B920CB800B5AC1A"; @@ -903,13 +905,15 @@ void xcodeProject::addSrc(std::string srcFile, std::string folder, SrcType type) nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); } else { - std::string xmlStr = "//key[contains(.,'"+srcUUID+"')]/following-sibling::node()[1]"; + std::string xmlStr = "//key[contains(.,'"+projRootUUID+"')]/following-sibling::node()[1]"; pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); + pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, "extra"); + + nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - // I'm not sure the best way to proceed; - // we should maybe find the rootest level and add it there. - // TODO: fix this. + // This should add any files not in src/ addons/ or local_addons/ + // to the root of the project hierarchy } }; diff --git a/ofxProjectGenerator/src/projects/xcodeProject.h b/ofxProjectGenerator/src/projects/xcodeProject.h index 2878f3df..41f496d5 100644 --- a/ofxProjectGenerator/src/projects/xcodeProject.h +++ b/ofxProjectGenerator/src/projects/xcodeProject.h @@ -40,6 +40,7 @@ class xcodeProject : public baseProject { void saveScheme(); void renameProject(); + std::string projRootUUID; std::string srcUUID; std::string addonUUID; std::string localAddonUUID; From 30ea4882ae1ceb8276d18dbf97ae11cb5183b5f3 Mon Sep 17 00:00:00 2001 From: ofTheo Date: Wed, 1 Jul 2020 15:22:44 -0700 Subject: [PATCH 2/6] added include search paths for additional directories --- ofxProjectGenerator/src/projects/baseProject.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ofxProjectGenerator/src/projects/baseProject.cpp b/ofxProjectGenerator/src/projects/baseProject.cpp index f41b808d..759820cd 100644 --- a/ofxProjectGenerator/src/projects/baseProject.cpp +++ b/ofxProjectGenerator/src/projects/baseProject.cpp @@ -307,11 +307,13 @@ void baseProject::addSrcRecursively(std::string srcPath){ //we want folders added for shared_of_code/ and any subfolders, but not folders added for /user/ /user/person/ etc string parentFolder = ofFilePath::getEnclosingDirectory(ofFilePath::removeTrailingSlash(srcPath)); + std::map uniqueIncludeFolders; for( auto & fileToAdd : srcFilesToAdd){ //if it is an absolute path it is easy - add the file and enclosing folder to the project if( ofFilePath::isAbsolute(fileToAdd) ){ string folder = ofFilePath::getEnclosingDirectory(fileToAdd,false); + string absFolder = folder; auto pos = folder.find_first_of(parentFolder); @@ -323,6 +325,7 @@ void baseProject::addSrcRecursively(std::string srcPath){ ofLogVerbose() << " adding file " << fileToAdd << " in folder " << folder << " to project "; addSrc(fileToAdd, folder); + uniqueIncludeFolders[absFolder] = absFolder; }else{ //if it is a realtive path make the file relative to the project folder @@ -335,6 +338,7 @@ void baseProject::addSrcRecursively(std::string srcPath){ //get the folder from the path and clean it up string folder = ofFilePath::getEnclosingDirectory(relPathPathToAdd,false); + string includeFolder = folder; ofStringReplace(folder, "../", ""); #ifdef TARGET_WIN32 @@ -344,7 +348,14 @@ void baseProject::addSrcRecursively(std::string srcPath){ ofLogVerbose() << " adding file " << fileToAdd << " in folder " << folder << " to project "; addSrc(relPathPathToAdd, folder); + uniqueIncludeFolders[includeFolder] = includeFolder; } + } + + //do it this way so we don't try and add a include folder for each file ( as it checks if they are already added ) so should be faster + for(auto & includeFolder : uniqueIncludeFolders){ + ofLogVerbose() << " adding search include paths for folder " << includeFolder.second; + addInclude(includeFolder.second); } } From 7f2f26b11c6f1fa6bd25fb9abd49aca9f83923c1 Mon Sep 17 00:00:00 2001 From: ofTheo Date: Thu, 2 Jul 2020 14:08:57 -0700 Subject: [PATCH 3/6] fixes to allow adding a single folder with no subfolders to an xcode project --- ofxProjectGenerator/src/projects/baseProject.cpp | 2 +- ofxProjectGenerator/src/projects/xcodeProject.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ofxProjectGenerator/src/projects/baseProject.cpp b/ofxProjectGenerator/src/projects/baseProject.cpp index 759820cd..146a38ee 100644 --- a/ofxProjectGenerator/src/projects/baseProject.cpp +++ b/ofxProjectGenerator/src/projects/baseProject.cpp @@ -319,7 +319,7 @@ void baseProject::addSrcRecursively(std::string srcPath){ //just to be 100% sure - check if the parent folder path is at the beginning of the file path //then remove it so we just get the folder structure of the actual src files being added and not the full path - if( pos == 0 ){ + if( pos == 0 && parentFolder.size() < folder.size() ){ folder = folder.substr(parentFolder.size()); } diff --git a/ofxProjectGenerator/src/projects/xcodeProject.cpp b/ofxProjectGenerator/src/projects/xcodeProject.cpp index 3618d58b..18b48064 100644 --- a/ofxProjectGenerator/src/projects/xcodeProject.cpp +++ b/ofxProjectGenerator/src/projects/xcodeProject.cpp @@ -877,8 +877,8 @@ void xcodeProject::addSrc(std::string srcFile, std::string folder, SrcType type) std::vector < std::string > folders = ofSplitString(folder, "/", true); - if (folders.size() > 1){ - if (folders[0] == "src"){ + if (folders.size()){ + if (folders.size() > 1 && folders[0] == "src"){ std::string xmlStr = "//key[contains(.,'"+srcUUID+"')]/following-sibling::node()[1]"; folders.erase(folders.begin()); @@ -886,7 +886,7 @@ void xcodeProject::addSrc(std::string srcFile, std::string folder, SrcType type) pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, "src"); nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - } else if (folders[0] == "addons"){ + } else if (folders.size() > 1 && folders[0] == "addons"){ std::string xmlStr = "//key[contains(.,'"+addonUUID+"')]/following-sibling::node()[1]"; folders.erase(folders.begin()); @@ -895,7 +895,7 @@ void xcodeProject::addSrc(std::string srcFile, std::string folder, SrcType type) nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); - } else if (folders[0] == "local_addons"){ + } else if (folders.size() > 1 && folders[0] == "local_addons"){ std::string xmlStr = "//key[contains(.,'"+localAddonUUID+"')]/following-sibling::node()[1]"; folders.erase(folders.begin()); @@ -908,7 +908,7 @@ void xcodeProject::addSrc(std::string srcFile, std::string folder, SrcType type) std::string xmlStr = "//key[contains(.,'"+projRootUUID+"')]/following-sibling::node()[1]"; pugi::xml_node node = doc.select_single_node(xmlStr.c_str()).node(); - pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, "extra"); + pugi::xml_node nodeToAddTo = findOrMakeFolderSet( node, folders, folders[0]); nodeToAddTo.child("array").append_child("string").append_child(pugi::node_pcdata).set_value(UUID.c_str()); From 1d37ddcc68c43895c8e371b15b5902736dad1801 Mon Sep 17 00:00:00 2001 From: ofTheo Date: Thu, 2 Jul 2020 14:52:59 -0700 Subject: [PATCH 4/6] frontend changes to support adding additional source paths - hidden as advanced by default --- frontend/app.js | 43 ++++++++++++++++++++++++++++++++++++++++--- frontend/index.html | 9 +++++++++ frontend/index.js | 21 +++++++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/frontend/app.js b/frontend/app.js index edb2f304..28a5296a 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -28,7 +28,7 @@ var isFirstTimeSierra = false; var bVerbose = false; var localAddons = []; - +var numAddedSrcPaths = 1; //----------------------------------------------------------------------------------- // IPC @@ -92,6 +92,11 @@ ipc.on('setProjectPath', function(arg) { $("#projectName").trigger('change'); // checks if we need to be in update or generate mode }); +//------------------------------------------- +ipc.on('setSourceExtraPath', function(arg, index) { + $("#sourceExtra-"+index).val(arg); +}); + //------------------------------------------- ipc.on('setGenerateMode', function(arg) { switchGenerateMode(arg); @@ -914,12 +919,23 @@ function generate() { addonValueArray.push(localAddons[i]); } + // extra source locations + var srcExtraArr = ""; + for(var i = 0; i < numAddedSrcPaths; i++){ + var srcExtra = $("#sourceExtra-"+i).val(); + if( srcExtra != '' ){ + srcExtraArr += ", " + srcExtra; + } + } + + var lengthOfPlatforms = platformValueArray.length; var gen = {}; gen['projectName'] = $("#projectName").val(); gen['projectPath'] = $("#projectPath").val(); + gen['sourcePath'] = srcExtraArr; gen['platformList'] = platformValueArray; gen['templateList'] = templateValueArray; gen['addonList'] = addonValueArray; //$("#addonsDropdown").val(); @@ -1032,14 +1048,14 @@ function enableAdvancedMode(isAdvanced) { $('#platformsDropdown').removeClass("disabled"); $("body").addClass('advanced'); $('a.updateMultiMenuOption').show(); - + $('#sourceExtraSection').show(); $('#templateSection').show(); $('#templateSectionMulti').show(); } else { $('#platformsDropdown').addClass("disabled"); $('#platformsDropdown').dropdown('set exactly', defaultSettings['defaultPlatform']); - + $('#sourceExtraSection').hide(); $('#templateSection').hide(); $('#templateSectionMulti').hide(); $('#templateDropdown').dropdown('set exactly', ''); @@ -1122,6 +1138,27 @@ function browseProjectPath() { ipc.send('pickProjectPath', path); // current path could go here } +function browseSourcePath(index) { + + //if we don't have another field below us - add one + var nextFieldId = '#sourceExtra-'+(index+1); + if( $(nextFieldId).length == 0 ){ + var nextIndex = index+1; + var extrafield = '
\ +
\ + \ + \ +
\ +
'; + + $("#sourceExtraSection").append(extrafield); + numAddedSrcPaths++; + } + + ipc.send('pickSourcePath', path, index); // current path could go here +} + + function browseImportProject() { var path = $("#projectPath").val(); if (path === ''){ diff --git a/frontend/index.html b/frontend/index.html index 1b9df434..26bbb7d3 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -150,6 +150,15 @@ +
+ +
+
+ + +
+
+
\ '; - + $("#sourceExtraSection").append(extrafield); numAddedSrcPaths++; } - +} + +function browseSourcePath(index) { + var path = $("#ofPath").val(); ipc.send('pickSourcePath', path, index); // current path could go here } diff --git a/frontend/index.js b/frontend/index.js index 1647be38..42750413 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -497,6 +497,7 @@ ipc.on('isOFProjectFolder', function(event, project) { // todo: also check for config.make & addons.make ? var foundSrcFolder = false; var foundAddons = false; + var foundConfig = false; tmpFiles.forEach(function(el, i) { if (el == 'src') { foundSrcFolder = true; @@ -504,6 +505,9 @@ ipc.on('isOFProjectFolder', function(event, project) { if (el == 'addons.make') { foundAddons = true; } + if(el == 'config.make'){ + foundConfig = true; + } }); if (foundSrcFolder) { @@ -532,6 +536,57 @@ ipc.on('isOFProjectFolder', function(event, project) { } else { event.sender.send('selectAddons', {}); } + + if(foundConfig){ + var projectExtra = fsTemp.readFileSync(pathTemp.resolve(folder, 'config.make')).toString().split("\n"); + projectExtra = projectExtra.filter(function(el) { + if (el === '' || el[0] === '#') { + return false; + } // eleminates these items + else { + console.log("got a good element " + el ); + return true; + } + }); + + //read the valid lines + var extraSrcPathsCount = 0; + + projectExtra.forEach(function(el, i) { + //remove spaces + var line = el.replace(/ /g, ''); + + //split either on = or += + var splitter = "+="; + var n = line.indexOf(splitter); + var macro, value; + + if( n != -1 ){ + var macro = line.substr(0, n); + var value = line.substr(n + splitter.length); + }else{ + splitter = "="; + n = line.indexOf(splitter); + if( n != -1 ){ + macro = line.substr(0, n); + value = line.substr(n + splitter.length); + } + } + + if( macro.length && value.length){ + // this is where you can do things with the macro/values from the config.make file + + console.log("Reading config pair. Macro: " + macro + " Value: " + value); + + if(macro.startsWith('PROJECT_EXTERNAL_SOURCE_PATHS')){ + event.sender.send('setSourceExtraPath', value, extraSrcPathsCount); + extraSrcPathsCount++; + } + } + }); + + } + } else { event.sender.send('setGenerateMode', 'createMode'); } diff --git a/ofxProjectGenerator/src/projects/baseProject.cpp b/ofxProjectGenerator/src/projects/baseProject.cpp index 044a647f..551236fa 100644 --- a/ofxProjectGenerator/src/projects/baseProject.cpp +++ b/ofxProjectGenerator/src/projects/baseProject.cpp @@ -109,6 +109,7 @@ vector baseProject::listAvailableTemplates(std::string ta bool baseProject::create(string path, std::string templateName){ templatePath = getPlatformTemplateDir(); addons.clear(); + extSrcPaths.clear(); if(!ofFilePath::isAbsolute(path)){ path = (std::filesystem::current_path() / std::filesystem::path(path)).string(); @@ -228,7 +229,34 @@ bool baseProject::save(){ addonsMake << addons[i].name << endl; } } - + + //save out params which the PG knows about to config.make + //we mostly use this right now for storing the external source paths + auto buffer = ofBufferFromFile(ofFilePath::join(projectDir,"config.make")); + if( buffer.size() ){ + ofFile saveConfig(ofFilePath::join(projectDir,"config.make"), ofFile::WriteOnly); + + for(auto line : buffer.getLines()){ + string str = line; + + //add the of root path + if( str.rfind("# OF_ROOT =", 0) == 0 ){ + saveConfig << "OF_ROOT = " + getOFRoot() << endl; + } + // replace this section with our external paths + else if( extSrcPaths.size() && str.rfind("# PROJECT_EXTERNAL_SOURCE_PATHS =", 0) == 0 ){ + + for(int d = 0; d < extSrcPaths.size(); d++){ + ofLog(OF_LOG_VERBOSE) << " adding PROJECT_EXTERNAL_SOURCE_PATHS to config" << extSrcPaths[d] << endl; + saveConfig << "PROJECT_EXTERNAL_SOURCE_PATHS" << (d == 0 ? " = " : " += ") << extSrcPaths[d] << endl; + } + + }else{ + saveConfig << str << endl; + } + } + } + return saveProjectFile(); } @@ -295,6 +323,7 @@ void baseProject::addAddon(std::string addonName){ } void baseProject::addSrcRecursively(std::string srcPath){ + extSrcPaths.push_back(srcPath); vector srcFilesToAdd; //so we can just pass through the file paths diff --git a/ofxProjectGenerator/src/projects/baseProject.h b/ofxProjectGenerator/src/projects/baseProject.h index 52b7c671..6729a691 100644 --- a/ofxProjectGenerator/src/projects/baseProject.h +++ b/ofxProjectGenerator/src/projects/baseProject.h @@ -88,6 +88,7 @@ class baseProject { void recursiveCopyContents(const ofDirectory & srcDir, ofDirectory & destDir); std::vector addons; + std::vector extSrcPaths; }; diff --git a/ofxProjectGenerator/src/utils/Utils.cpp b/ofxProjectGenerator/src/utils/Utils.cpp index adda7add..64002e4a 100644 --- a/ofxProjectGenerator/src/utils/Utils.cpp +++ b/ofxProjectGenerator/src/utils/Utils.cpp @@ -290,6 +290,8 @@ void getPropsRecursively(const std::string & path, std::vector < std::string > & for (auto & temp : dir) { if (temp.isDirectory()) { + //skip example directories - this is needed as we are search all folders in the addons root path + if( temp.getFileName().rfind("example", 0) == 0) continue; getPropsRecursively(temp.path(), props, platform); } else {