From badced81d54f02a2faada79604714331e9e666f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Tue, 22 Oct 2024 01:02:30 -0300 Subject: [PATCH] Fix crash when Build Settings due to invalid memory access. Added ${arch} predefined custom variable for project build settings. Expose cmake and ninja projects out of the box. --- premake5.lua | 2 + src/tools/ecode/projectbuild.cpp | 138 ++++++++++++++++++--------- src/tools/ecode/projectbuild.hpp | 18 +++- src/tools/ecode/uibuildsettings.cpp | 66 ++++++------- src/tools/ecode/universallocator.cpp | 13 +-- 5 files changed, 147 insertions(+), 90 deletions(-) diff --git a/premake5.lua b/premake5.lua index 80bb2e3f0..e5a6858d6 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,4 +1,6 @@ require "premake.export-compile-commands.export-compile-commands" +require "premake.premake-cmake.cmake" +require "premake.premake-ninja.ninja" newoption { trigger = "with-openssl", description = "Enables OpenSSL support ( and disables mbedtls backend )." } newoption { trigger = "with-dynamic-freetype", description = "Dynamic link against freetype." } diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index f1db9f131..9de01fb0f 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -24,6 +24,7 @@ static constexpr auto SidePanelLoadUniqueId = String::hash( "ProjectBuildManager static const char* VAR_PROJECT_ROOT = "${project_root}"; static const char* VAR_BUILD_TYPE = "${build_type}"; static const char* VAR_OS = "${os}"; +static const char* VAR_ARCH = "${arch}"; static const char* VAR_NPROC = "${nproc}"; static const char* VAR_CURRENT_DOC = "${current_doc}"; static const char* VAR_CURRENT_DOC_NAME = "${current_doc_name}"; @@ -50,14 +51,14 @@ ProjectBuildStep ProjectBuild::replaceVars( const ProjectBuildStep& step ) const } ProjectBuildSteps ProjectBuild::replaceVars( const ProjectBuildSteps& steps ) const { - ProjectBuildSteps newSteps( steps ); + ProjectBuildSteps newSteps( deepCopySteps( steps ) ); for ( auto& s : newSteps ) { - replaceVar( s, VAR_PROJECT_ROOT, mProjectRoot ); + replaceVar( *s.get(), VAR_PROJECT_ROOT, mProjectRoot ); for ( auto& var : mVars ) { std::string varKey( "${" + var.first + "}" ); std::string varVal( var.second ); String::replaceAll( varVal, VAR_PROJECT_ROOT, mProjectRoot ); - replaceVar( s, varKey, varVal ); + replaceVar( *s.get(), varKey, varVal ); } } return newSteps; @@ -74,11 +75,11 @@ json ProjectBuild::serialize( const ProjectBuild::Map& builds ) { auto& jbuild = bj["build"]; for ( const auto& build : curBuild.buildSteps() ) { json step; - step["working_dir"] = build.workingDir; - step["args"] = build.args; - step["command"] = build.cmd; - if ( !build.enabled ) - step["enabled"] = build.enabled; + step["working_dir"] = build->workingDir; + step["args"] = build->args; + step["command"] = build->cmd; + if ( !build->enabled ) + step["enabled"] = build->enabled; jbuild.push_back( step ); } @@ -86,11 +87,11 @@ json ProjectBuild::serialize( const ProjectBuild::Map& builds ) { auto& jclean = bj["clean"]; for ( const auto& build : curBuild.cleanSteps() ) { json step; - step["working_dir"] = build.workingDir; - step["args"] = build.args; - step["command"] = build.cmd; - if ( !build.enabled ) - step["enabled"] = build.enabled; + step["working_dir"] = build->workingDir; + step["args"] = build->args; + step["command"] = build->cmd; + if ( !build->enabled ) + step["enabled"] = build->enabled; jclean.push_back( step ); } @@ -99,14 +100,14 @@ json ProjectBuild::serialize( const ProjectBuild::Map& builds ) { auto& jrun = bj["run"]; for ( auto& run : curBuild.mRun ) { json step; - step["name"] = run.name; - step["working_dir"] = run.workingDir; - step["args"] = run.args; - step["command"] = run.cmd; - if ( !run.enabled ) - step["enabled"] = run.enabled; - if ( run.runInTerminal ) - step["run_in_terminal"] = run.runInTerminal; + step["name"] = run->name; + step["working_dir"] = run->workingDir; + step["args"] = run->args; + step["command"] = run->cmd; + if ( !run->enabled ) + step["enabled"] = run->enabled; + if ( run->runInTerminal ) + step["run_in_terminal"] = run->runInTerminal; jrun.push_back( step ); } } @@ -152,6 +153,50 @@ json ProjectBuild::serialize( const ProjectBuild::Map& builds ) { return j; } +ProjectBuildSteps ProjectBuild::deepCopySteps( const ProjectBuildSteps& steps ) const { + ProjectBuildSteps copy; + for ( const auto& step : steps ) + copy.push_back( std::make_unique( *step.get() ) ); + return copy; +} + +ProjectBuild::ProjectBuild( const ProjectBuild& other ) : + mName( other.mName ), + mProjectRoot( other.mProjectRoot ), + mOS( other.mOS ), + mBuildTypes( other.mBuildTypes ), + mEnvs( other.mEnvs ), + mVars( other.mVars ), + mConfig( other.mConfig ), + mOutputParser( other.mOutputParser ) { + mBuild = deepCopySteps( other.mBuild ); + mClean = deepCopySteps( other.mClean ); + mRun = deepCopySteps( other.mRun ); +} + +ProjectBuild& ProjectBuild::operator=( const ProjectBuild& other ) { + if ( this != &other ) { + mName = other.mName; + mProjectRoot = other.mProjectRoot; + mOS = other.mOS; + mBuildTypes = other.mBuildTypes; + mEnvs = other.mEnvs; + mVars = other.mVars; + mConfig = other.mConfig; + mOutputParser = other.mOutputParser; + mBuild.clear(); + mClean.clear(); + mRun.clear(); + mBuild = deepCopySteps( other.mBuild ); + mClean = deepCopySteps( other.mClean ); + mRun = deepCopySteps( other.mRun ); + } + return *this; +} + +ProjectBuild::ProjectBuild( const std::string& name, const std::string& projectRoot ) : + mName( name ), mProjectRoot( projectRoot ) {} + bool ProjectBuild::isOSSupported( const std::string& os ) const { return mOS.empty() || std::any_of( mOS.begin(), mOS.end(), [&os]( const auto& oos ) { return oos == os || oos == "any"; @@ -338,6 +383,7 @@ void ProjectBuildManager::replaceDynamicVars( ProjectBuildCommand& cmd ) { std::string curDocName = FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( curDoc ) ); replaceVar( cmd, VAR_OS, currentOS ); + replaceVar( cmd, VAR_ARCH, Sys::getOSArchitecture() ); replaceVar( cmd, VAR_NPROC, nproc ); replaceVar( cmd, VAR_CURRENT_DOC, curDoc ); replaceVar( cmd, VAR_CURRENT_DOC_NAME, curDocName ); @@ -369,7 +415,7 @@ ProjectBuildCommandsRes ProjectBuildManager::generateBuildCommands( const std::s ProjectBuildCommandsRes res; for ( const auto& step : finalBuild ) { - ProjectBuildCommand buildCmd( step ); + ProjectBuildCommand buildCmd( *step ); replaceDynamicVars( buildCmd ); if ( !buildType.empty() ) replaceVar( buildCmd, VAR_BUILD_TYPE, buildType ); @@ -470,11 +516,11 @@ ProjectBuild::Map ProjectBuild::deserialize( const json& j, const std::string& p if ( buildObj.contains( "build" ) && buildObj["build"].is_array() ) { const auto& buildArray = buildObj["build"]; for ( const auto& step : buildArray ) { - ProjectBuildStep bstep; - bstep.cmd = step.value( "command", "" ); - bstep.args = step.value( "args", "" ); - bstep.workingDir = step.value( "working_dir", "" ); - bstep.enabled = step.value( "enabled", true ); + std::unique_ptr bstep = std::make_unique(); + bstep->cmd = step.value( "command", "" ); + bstep->args = step.value( "args", "" ); + bstep->workingDir = step.value( "working_dir", "" ); + bstep->enabled = step.value( "enabled", true ); b.mBuild.emplace_back( std::move( bstep ) ); } } @@ -482,11 +528,11 @@ ProjectBuild::Map ProjectBuild::deserialize( const json& j, const std::string& p if ( buildObj.contains( "clean" ) && buildObj["clean"].is_array() ) { const auto& cleanArray = buildObj["clean"]; for ( const auto& step : cleanArray ) { - ProjectBuildStep cstep; - cstep.cmd = step.value( "command", "" ); - cstep.args = step.value( "args", "" ); - cstep.workingDir = step.value( "working_dir", "" ); - cstep.enabled = step.value( "enabled", true ); + std::unique_ptr cstep = std::make_unique(); + cstep->cmd = step.value( "command", "" ); + cstep->args = step.value( "args", "" ); + cstep->workingDir = step.value( "working_dir", "" ); + cstep->enabled = step.value( "enabled", true ); b.mClean.emplace_back( std::move( cstep ) ); } } @@ -494,13 +540,13 @@ ProjectBuild::Map ProjectBuild::deserialize( const json& j, const std::string& p if ( buildObj.contains( "run" ) && buildObj["run"].is_array() ) { const auto& runArray = buildObj["run"]; for ( const auto& step : runArray ) { - ProjectBuildStep rstep; - rstep.name = step.value( "name", "" ); - rstep.cmd = step.value( "command", "" ); - rstep.args = step.value( "args", "" ); - rstep.workingDir = step.value( "working_dir", "" ); - rstep.enabled = step.value( "enabled", true ); - rstep.runInTerminal = step.value( "run_in_terminal", false ); + std::unique_ptr rstep = std::make_unique(); + rstep->name = step.value( "name", "" ); + rstep->cmd = step.value( "command", "" ); + rstep->args = step.value( "args", "" ); + rstep->workingDir = step.value( "working_dir", "" ); + rstep->enabled = step.value( "enabled", true ); + rstep->runInTerminal = step.value( "run_in_terminal", false ); b.mRun.emplace_back( std::move( rstep ) ); } } @@ -743,8 +789,8 @@ void ProjectBuildManager::runConfig( StatusAppOutputController* saoc ) { const ProjectBuildStep* run = nullptr; for ( const auto& crun : build->mRun ) { - if ( crun.name == mConfig.runName || mConfig.runName.empty() ) { - run = &crun; + if ( crun->name == mConfig.runName || mConfig.runName.empty() ) { + run = crun.get(); break; } } @@ -1238,11 +1284,11 @@ void ProjectBuildManager::updateRunConfig() { std::vector items; size_t i = 1; for ( const auto& run : runConfigs ) { - auto name = run.name.empty() ? String::format( mApp->i18n( "custom_executable_num", - "Custom Executable %d" ) - .toUtf8(), - i ) - : run.name; + auto name = run->name.empty() ? String::format( mApp->i18n( "custom_executable_num", + "Custom Executable %d" ) + .toUtf8(), + i ) + : run->name; items.emplace_back( name ); i++; } diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index f56b91a4d..dea6c628b 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -102,7 +102,7 @@ struct ProjectBuildStep { bool runInTerminal{ false }; }; -using ProjectBuildSteps = std::vector; +using ProjectBuildSteps = std::vector>; using ProjectBuildKeyVal = std::vector>; struct ProjectBuildConfig { @@ -169,8 +169,16 @@ class ProjectBuild { public: using Map = std::unordered_map; - ProjectBuild( const std::string& name, const std::string& projectRoot ) : - mName( name ), mProjectRoot( projectRoot ){}; + ProjectBuildSteps deepCopySteps( const ProjectBuildSteps& steps ) const; + + ProjectBuild( const ProjectBuild& other ); + + ProjectBuild& operator=( const ProjectBuild& other ); + + ProjectBuild( ProjectBuild&& ) = default; + ProjectBuild& operator=( ProjectBuild&& ) = default; + + ProjectBuild( const std::string& name, const std::string& projectRoot ); const ProjectBuildConfig& getConfig() const { return mConfig; } @@ -199,8 +207,8 @@ class ProjectBuild { bool hasClean() const { return !mClean.empty(); } bool hasRun() const { - return !mRun.empty() && ( !mRun.front().cmd.empty() || !mRun.front().args.empty() || - !mRun.front().workingDir.empty() ); + return !mRun.empty() && ( !mRun.front()->cmd.empty() || !mRun.front()->args.empty() || + !mRun.front()->workingDir.empty() ); } ProjectBuildStep replaceVars( const ProjectBuildStep& step ) const; diff --git a/src/tools/ecode/uibuildsettings.cpp b/src/tools/ecode/uibuildsettings.cpp index e574083d0..c671c8148 100644 --- a/src/tools/ecode/uibuildsettings.cpp +++ b/src/tools/ecode/uibuildsettings.cpp @@ -409,7 +409,7 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + @@ -508,39 +508,38 @@ UIBuildSettings::UIBuildSettings( } if ( mBuild.mBuild.empty() ) - mBuild.mBuild.push_back( {} ); + mBuild.mBuild.push_back( std::make_unique() ); if ( mBuild.mClean.empty() ) - mBuild.mClean.push_back( {} ); + mBuild.mClean.push_back( std::make_unique() ); auto buildStepsParent = find( "build_steps_cont" ); for ( size_t step = 0; step < mBuild.mBuild.size(); ++step ) { auto bs = - UIBuildStep::New( UIBuildStep::StepType::Build, this, step, &mBuild.mBuild[step] ); + UIBuildStep::New( UIBuildStep::StepType::Build, this, step, mBuild.mBuild[step].get() ); bs->setParent( buildStepsParent ); } find( "add_build_step" )->onClick( [this, buildStepsParent]( const Event* ) { - mBuild.mBuild.push_back( {} ); + mBuild.mBuild.push_back( std::make_unique() ); auto step = mBuild.mBuild.size() - 1; - UIBuildStep::New( UIBuildStep::StepType::Build, this, step, &mBuild.mBuild[step] ) + UIBuildStep::New( UIBuildStep::StepType::Build, this, step, mBuild.mBuild[step].get() ) ->setParent( buildStepsParent ); } ); auto buildCleanStepsParent = find( "build_clean_steps_cont" ); for ( size_t step = 0; step < mBuild.mClean.size(); ++step ) { - UIBuildStep::New( UIBuildStep::StepType::Clean, this, step, &mBuild.mClean[step] ) + UIBuildStep::New( UIBuildStep::StepType::Clean, this, step, mBuild.mClean[step].get() ) ->setParent( buildCleanStepsParent ); } find( "add_clean_step" )->onClick( [this, buildCleanStepsParent]( const Event* ) { - mBuild.mClean.push_back( {} ); + mBuild.mClean.push_back( std::make_unique() ); auto step = mBuild.mClean.size() - 1; - UIBuildStep::New( UIBuildStep::StepType::Clean, this, step, &mBuild.mClean[step] ) + UIBuildStep::New( UIBuildStep::StepType::Clean, this, step, mBuild.mClean[step].get() ) ->setParent( buildCleanStepsParent ); } ); - auto buildTypeDropDown = find( "build_type_list" ); auto panelBuildTypeDDL = getUISceneNode() ->getRoot() @@ -804,8 +803,8 @@ void UIBuildSettings::moveStepDir( size_t stepNum, bool isClean, int dir ) { std::swap( steps[stepNum], steps[newStep] ); auto bs1 = cont->findByClass( String::toString( (Uint64)stepNum ) ); auto bs2 = cont->findByClass( String::toString( newStep ) ); - bs1->updateStep( stepNum, &steps[stepNum] ); - bs2->updateStep( newStep, &steps[newStep] ); + bs1->updateStep( stepNum, steps[stepNum].get() ); + bs2->updateStep( newStep, steps[newStep].get() ); } void UIBuildSettings::deleteStep( size_t stepNum, bool isClean ) { @@ -818,16 +817,16 @@ void UIBuildSettings::deleteStep( size_t stepNum, bool isClean ) { cont->findByClass( String::toString( (Uint64)stepNum ) )->close(); for ( auto step = stepNum + 1; step <= steps.size(); step++ ) cont->findByClass( String::toString( (Uint64)step ) ) - ->updateStep( step - 1, &steps[step - 1] ); + ->updateStep( step - 1, steps[step - 1].get() ); } void UIBuildSettings::runSetup() { if ( mBuild.mRun.empty() ) { - mBuild.mRun.push_back( {} ); - mBuild.mRun.back().name = i18n( "custom_executable", "Custom Executable" ); + mBuild.mRun.push_back( std::make_unique() ); + mBuild.mRun.back()->name = i18n( "custom_executable", "Custom Executable" ); } - UIBuildStep::New( UIBuildStep::StepType::Run, this, 0, &mBuild.mRun[runIndex()] ) + UIBuildStep::New( UIBuildStep::StepType::Run, this, 0, mBuild.mRun[runIndex()].get() ) ->setParent( find( "run_cont" ) ); UIDropDownList* runList = find( "run_list" )->asType(); @@ -872,15 +871,15 @@ void UIBuildSettings::runSetup() { bool unique = true; auto newName = msgBox->getTextInput()->getText().toUtf8(); for ( const auto& run : mBuild.mRun ) { - if ( newName == run.name ) { + if ( newName == run->name ) { unique = false; break; } } if ( unique ) { - mBuild.mRun.push_back( {} ); - mBuild.mRun.back().name = newName; + mBuild.mRun.push_back( std::make_unique() ); + mBuild.mRun.back()->name = newName; runList->getListBox()->addListBoxItem( newName ); runList->getListBox()->setSelected( newName ); @@ -945,16 +944,16 @@ void UIBuildSettings::runSetup() { auto newName = msgBox->getTextInput()->getText().toUtf8(); for ( size_t i = 0; i < mBuild.mRun.size(); i++ ) { const auto& run = mBuild.mRun[i]; - if ( newName == run.name && i != selectedIndex ) { + if ( newName == run->name && i != selectedIndex ) { unique = false; break; } } if ( unique && selectedIndex < mBuild.mRun.size() ) { - if ( mBuild.mRun[selectedIndex].name == mConfig.runName ) + if ( mBuild.mRun[selectedIndex]->name == mConfig.runName ) mConfig.runName = newName; - mBuild.mRun[selectedIndex].name = newName; + mBuild.mRun[selectedIndex]->name = newName; runList->getListBox()->setItemText( selectedIndex, newName ); if ( panelRunListDDL ) panelRunListDDL->getListBox()->setItemText( selectedIndex, newName ); @@ -983,7 +982,7 @@ void UIBuildSettings::runSetup() { bool unique = true; auto newName = msgBox->getTextInput()->getText().toUtf8(); for ( const auto& run : mBuild.mRun ) { - if ( newName == run.name ) { + if ( newName == run->name ) { unique = false; break; } @@ -992,11 +991,12 @@ void UIBuildSettings::runSetup() { if ( unique ) { auto selectedIndex = runList->getListBox()->getItemSelectedIndex(); if ( selectedIndex < mBuild.mRun.size() ) { - mBuild.mRun.push_back( mBuild.mRun[selectedIndex] ); + mBuild.mRun.push_back( + std::make_unique( *mBuild.mRun[selectedIndex].get() ) ); } else { - mBuild.mRun.push_back( {} ); + mBuild.mRun.push_back( std::make_unique() ); } - mBuild.mRun.back().name = newName; + mBuild.mRun.back()->name = newName; runList->getListBox()->addListBoxItem( newName ); runList->getListBox()->setSelected( newName ); @@ -1022,13 +1022,13 @@ void UIBuildSettings::runSelect( Uint32 index ) { UIWidget* cont = find( "run_cont" ); auto bs = cont->findByClass( String::toString( 0 ) ); if ( index < mBuild.mRun.size() ) { - bs->updateStep( 0, &mBuild.mRun[index] ); + bs->updateStep( 0, mBuild.mRun[index].get() ); } else { if ( mBuild.mRun.empty() ) { - mBuild.mRun.push_back( {} ); - mBuild.mRun.back().name = i18n( "custom_executable", "Custom Executable" ); + mBuild.mRun.push_back( std::make_unique() ); + mBuild.mRun.back()->name = i18n( "custom_executable", "Custom Executable" ); } - bs->updateStep( 0, &mBuild.mRun[0] ); + bs->updateStep( 0, mBuild.mRun[0].get() ); } } @@ -1067,10 +1067,10 @@ void UIBuildSettings::runUpdate( bool recreateList, UIDropDownList* runList, size_t i = 1; for ( const auto& run : mBuild.mRun ) { auto name = - run.name.empty() + run->name.empty() ? String::format( i18n( "custom_executable_num", "Custom Executable %d" ).toUtf8(), i ) - : run.name; + : run->name; runList->getListBox()->addListBoxItem( name ); if ( panelRunListDDL ) panelRunListDDL->getListBox()->addListBoxItem( name ); @@ -1091,7 +1091,7 @@ void UIBuildSettings::runUpdate( bool recreateList, UIDropDownList* runList, Uint32 UIBuildSettings::runIndex() const { for ( size_t i = 0; i < mBuild.mRun.size(); i++ ) { - if ( mBuild.mRun[i].name == mConfig.runName ) + if ( mBuild.mRun[i]->name == mConfig.runName ) return i; } return 0; diff --git a/src/tools/ecode/universallocator.cpp b/src/tools/ecode/universallocator.cpp index 97b1408dc..cbe9966c1 100644 --- a/src/tools/ecode/universallocator.cpp +++ b/src/tools/ecode/universallocator.cpp @@ -291,10 +291,11 @@ UniversalLocator::UniversalLocator( UICodeEditorSplitter* editorSplitter, UIScen auto build = pbm->getBuild( cfg.buildName ); if ( build != nullptr ) { std::string runTarget = vName.toString(); - auto it = std::find_if( build->runConfigs().begin(), build->runConfigs().end(), - [&runTarget]( const ProjectBuildStep& run ) { - return run.name == runTarget; - } ); + auto it = + std::find_if( build->runConfigs().begin(), build->runConfigs().end(), + [&runTarget]( const std::unique_ptr& run ) { + return run->name == runTarget; + } ); if ( it != build->runConfigs().end() ) { cfg.runName = runTarget; pbm->setConfig( cfg ); @@ -893,8 +894,8 @@ UniversalLocator::openRunTargetModel( const std::string& match ) { runTargetNames.reserve( runs.size() ); for ( const auto& run : runs ) { if ( match.empty() || - String::startsWith( String::toLower( run.name ), String::toLower( match ) ) ) - runTargetNames.push_back( run.name ); + String::startsWith( String::toLower( run->name ), String::toLower( match ) ) ) + runTargetNames.push_back( run->name ); } std::sort( runTargetNames.begin(), runTargetNames.end() ); return ItemListOwnerModel::create( runTargetNames );