I'm looking into using Code::Blocks as an IDE to use with the homebrew toolchains I produce @ devkitpro.org - thinking about distributing a kind of "lite" version with the tools (reducing compiler set to just devkitARM, devkitPPC & devkitPSP & removing unrelated wizards & templates).
The binaries produced need to be run on the game consoles or via emulators - I can make the run button work by abusing the Dynamic Library target and setting a host application (either to suitable emulator or an application that sends the binary to the game console in question) but getting the debug button to work is a little more awkward. The IDE needs to launch an emulator with gdb support or an application that sends the binary to the game console and sets up a gdb proxy then launch gdb with the matching elf file. Currently I've managed to patch Code::Blocks with an "Embedded Application" target which just operates in the same way as the Dynamic Library target for run and replaces the extension on the output file with .elf for sending to gdb.
diff --git a/src/include/compiletargetbase.h b/src/include/compiletargetbase.h
index 3d09dfd..a6b255d 100644
--- a/src/include/compiletargetbase.h
+++ b/src/include/compiletargetbase.h
@@ -37,7 +37,8 @@ enum TargetType
ttStaticLib = 2, /**< Target produces a static library */
ttDynamicLib = 3, /**< Target produces a dynamic library */
ttCommandsOnly = 4, /**< Target only runs commands in pre-build and/or post-build steps */
- ttNative = 5 /**< Target produces a native binary */
+ ttNative = 5, /**< Target produces a native binary */
+ ttEmbedded = 6, /**< Target produces an Embedded binary */
};
enum MakeCommand
diff --git a/src/plugins/compilergcc/compilergcc.cpp b/src/plugins/compilergcc/compilergcc.cpp
index 3e82e3b..4d531f3 100644
--- a/src/plugins/compilergcc/compilergcc.cpp
+++ b/src/plugins/compilergcc/compilergcc.cpp
@@ -1902,7 +1902,8 @@ int CompilerGCC::Run(ProjectBuildTarget* target)
}
if ( target->GetTargetType() == ttDynamicLib
- || target->GetTargetType() == ttStaticLib )
+ || target->GetTargetType() == ttStaticLib
+ || target->GetTargetType() == ttEmbedded )
{
// check for hostapp
if (target->GetHostApplication().IsEmpty())
diff --git a/src/sdk/cbplugin.cpp b/src/sdk/cbplugin.cpp
index eb20772..f656de1 100644
--- a/src/sdk/cbplugin.cpp
+++ b/src/sdk/cbplugin.cpp
@@ -648,6 +648,24 @@ bool cbDebuggerPlugin::GetDebuggee(wxString &pathToDebuggee, wxString &workingDi
}
break;
+ case ttEmbedded:
+ {
+ if (target->GetHostApplication().IsEmpty())
+ {
+ cbMessageBox(_("You must select a host application to \"run\" an Embedded Application..."));
+ return false;
+ }
+ out = UnixFilename(target->GetOutputFilename());
+ Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out); // apply env vars
+ wxFileName f(out);
+ f.MakeAbsolute(target->GetParentProject()->GetBasePath());
+ f.SetExt(_T("elf"));
+ out = f.GetFullPath();
+ Log(_("Adding file: ") + out);
+ ConvertDirectory(out);
+ }
+ break;
+
case ttStaticLib:
case ttDynamicLib:
// check for hostapp
diff --git a/src/sdk/compiletargetbase.cpp b/src/sdk/compiletargetbase.cpp
index 4debe3a..6ce6fc3 100644
--- a/src/sdk/compiletargetbase.cpp
+++ b/src/sdk/compiletargetbase.cpp
@@ -177,7 +177,8 @@ wxString CompileTargetBase::SuggestOutputFilename()
case ttExecutable: suggestion = GetExecutableFilename(); break;
case ttDynamicLib: suggestion = GetDynamicLibFilename(); break;
case ttStaticLib: suggestion = GetStaticLibFilename(); break;
- case ttNative: suggestion = GetNativeFilename(); break;
+ case ttNative: // fall through
+ case ttEmbedded: suggestion = GetNativeFilename(); break;
case ttCommandsOnly: // fall through
default:
suggestion.Clear();
@@ -279,6 +280,7 @@ void CompileTargetBase::GenerateTargetFilename(wxString& filename) const
break;
}
case ttNative:
+ case ttEmbedded:
{
if (m_ExtensionGenerationPolicy == tgfpPlatformDefault)
filename << fname.GetName() << FileFilters::NATIVE_DOT_EXT;
@@ -355,7 +357,7 @@ wxString CompileTargetBase::GetNativeFilename()
wxFileName fname(m_Filename);
fname.SetName(fname.GetName());
- fname.SetExt(FileFilters::NATIVE_EXT);
+ if (m_TargetType == ttNative) fname.SetExt(FileFilters::NATIVE_EXT);
return fname.GetFullPath();
}
diff --git a/src/sdk/scripting/bindings/sc_consts.cpp b/src/sdk/scripting/bindings/sc_consts.cpp
index 2b40563..71e2651 100644
--- a/src/sdk/scripting/bindings/sc_consts.cpp
+++ b/src/sdk/scripting/bindings/sc_consts.cpp
@@ -114,6 +114,7 @@ namespace ScriptBindings
BIND_INT_CONSTANT(ttDynamicLib);
BIND_INT_CONSTANT(ttCommandsOnly);
BIND_INT_CONSTANT(ttNative);
+ BIND_INT_CONSTANT(ttEmbedded);
// MakeCommand
BIND_INT_CONSTANT(mcClean);
diff --git a/src/src/projectoptionsdlg.cpp b/src/src/projectoptionsdlg.cpp
index 6f11d07..3c4ba6f 100644
--- a/src/src/projectoptionsdlg.cpp
+++ b/src/src/projectoptionsdlg.cpp
@@ -274,6 +274,7 @@ void ProjectOptionsDlg::DoTargetChange(bool saveOld)
case ttExecutable:
case ttDynamicLib:
case ttNative:
+ case ttEmbedded:
case ttStaticLib:
txt->SetValue(target->GetOutputFilename());
txt->Enable(true);
@@ -285,6 +286,7 @@ void ProjectOptionsDlg::DoTargetChange(bool saveOld)
txtW->Enable((TargetType)cmb->GetSelection() == ttExecutable ||
(TargetType)cmb->GetSelection() == ttConsoleOnly ||
(TargetType)cmb->GetSelection() == ttNative ||
+ (TargetType)cmb->GetSelection() == ttEmbedded ||
(TargetType)cmb->GetSelection() == ttDynamicLib);
txtO->SetValue(target->GetObjectOutput());
txtO->Enable(true);
@@ -294,6 +296,7 @@ void ProjectOptionsDlg::DoTargetChange(bool saveOld)
browseW->Enable((TargetType)cmb->GetSelection() == ttExecutable ||
(TargetType)cmb->GetSelection() == ttConsoleOnly ||
(TargetType)cmb->GetSelection() == ttNative ||
+ (TargetType)cmb->GetSelection() == ttEmbedded ||
(TargetType)cmb->GetSelection() == ttDynamicLib);
browseO->Enable(true);
break;
@@ -514,6 +517,16 @@ void ProjectOptionsDlg::OnProjectTypeChanged(cb_unused wxCommandEvent& event)
txtI->SetValue(_T(""));
txtD->SetValue(_T(""));
break;
+ case ttEmbedded:
+ if (!libpre.IsEmpty() && name.StartsWith(libpre))
+ {
+ name.Remove(0, libpre.Length());
+ fname.SetName(name);
+ }
+ txt->SetValue(fname.GetFullPath());
+ txtI->SetValue(_T(""));
+ txtD->SetValue(_T(""));
+ break;
case ttNative:
if (ext != FileFilters::NATIVE_EXT)
fname.SetExt(FileFilters::NATIVE_EXT);
diff --git a/src/src/resources/project_options.xrc b/src/src/resources/project_options.xrc
index c3b2834..e7b8e58 100644
--- a/src/src/resources/project_options.xrc
+++ b/src/src/resources/project_options.xrc
@@ -399,6 +399,7 @@
<item>Dynamic library</item>
<item>Commands only</item>
<item>Native</item>
+ <item>Embedded Application</item>
</content>
<style>wxCB_READONLY|wxCB_DROPDOWN</style>
</object>
With just this patch I can launch an emulator with debug support manually then hit the debug button & things work as expected. Getting the emulator to launch automatically with the extra parameters to open a gdb port is slightly more involved.
diff --git a/src/include/cbplugin.h b/src/include/cbplugin.h
index 6fe4131..a712a7c 100644
--- a/src/include/cbplugin.h
+++ b/src/include/cbplugin.h
@@ -622,6 +622,7 @@ class PLUGIN_EXPORT cbDebuggerPlugin: public cbPlugin
void SwitchToPreviousLayout();
bool GetDebuggee(wxString& pathToDebuggee, wxString& workingDirectory, ProjectBuildTarget* target);
+ bool GetHostForDebug(wxString &pathToHostApp, ProjectBuildTarget* target);
bool EnsureBuildUpToDate(StartType startType);
bool WaitingCompilerToFinish() const { return m_WaitingCompilerToFinish; }
diff --git a/src/include/compiletargetbase.h b/src/include/compiletargetbase.h
index a6b255d..61a5af7 100644
--- a/src/include/compiletargetbase.h
+++ b/src/include/compiletargetbase.h
@@ -140,6 +140,8 @@ class DLLIMPORT CompileTargetBase : public CompileOptionsBase
virtual void SetExecutionParameters(const wxString& params); ///< Set the target's execution parameters to \c params
virtual const wxString& GetHostApplication() const; ///< Read the target's host application
virtual void SetHostApplication(const wxString& app); ///< Set the target's host application to \c app
+ virtual const wxString& GetHostDebugParameters() const; ///< Read the target's host application parameters for debug
+ virtual void SetHostDebugParameters(const wxString& params); ///< Set the target's host application parameters for debug to \c params
virtual bool GetRunHostApplicationInTerminal() const; ///< Get the flag if the host app should be run in terminal
virtual void SetRunHostApplicationInTerminal(bool in_terminal); ///! Set the flag if the host app should be run in terminal
virtual void SetCompilerID(const wxString& id); ///< Set the target's compiler
@@ -160,6 +162,7 @@ class DLLIMPORT CompileTargetBase : public CompileOptionsBase
wxString m_DepsOutput;
wxString m_ExecutionParameters;
wxString m_HostApplication;
+ wxString m_HostDebugParameters;
OptionsRelation m_OptionsRelation[ortLast];
TargetType m_TargetType;
wxString m_CompilerId;
diff --git a/src/plugins/debuggergdb/debuggergdb.cpp b/src/plugins/debuggergdb/debuggergdb.cpp
index ad3a7ec..eb90a4b 100644
--- a/src/plugins/debuggergdb/debuggergdb.cpp
+++ b/src/plugins/debuggergdb/debuggergdb.cpp
@@ -812,10 +812,29 @@ int DebuggerGDB::DoDebug(bool breakOnEntry)
}
}
+ if(target->GetTargetType() == ttEmbedded)
+ {
+ wxString hostapp;
+ if (!GetHostForDebug(hostapp,target))
+ {
+ m_Canceled = true;
+ return -3;
+ }
+
+ wxString command;
+
+ command << hostapp << _T(" ") << target->GetExecutionParameters() << _T(" ") << target->GetHostDebugParameters();
+ Manager::Get()->GetMacrosManager()->ReplaceEnvVars(command);
+
+ Log(_T("Host Application: ") + command);
+ wxExecute(command, wxEXEC_ASYNC, NULL);
+ }
+
if (target && !target->GetExecutionParameters().IsEmpty())
m_State.GetDriver()->SetArguments(target->GetExecutionParameters());
cmdline = m_State.GetDriver()->GetCommandLine(cmdexe, debuggee, GetActiveConfigEx().GetUserArguments());
+ // start the host application
}
else // m_PidToAttach != 0
cmdline = m_State.GetDriver()->GetCommandLine(cmdexe, m_PidToAttach, GetActiveConfigEx().GetUserArguments());
@@ -863,6 +882,7 @@ int DebuggerGDB::DoDebug(bool breakOnEntry)
ShowWindow(windowHandle, SW_HIDE);
}
#endif
+
// start the gdb process
wxString wdir = m_State.GetDriver()->GetDebuggersWorkingDirectory();
if (wdir.empty())
diff --git a/src/sdk/cbplugin.cpp b/src/sdk/cbplugin.cpp
index 8e39929..3cfa20a 100644
--- a/src/sdk/cbplugin.cpp
+++ b/src/sdk/cbplugin.cpp
@@ -626,6 +626,34 @@ void cbDebuggerPlugin::SwitchToPreviousLayout()
Manager::Get()->ProcessEvent(switchEvent);
}
+bool cbDebuggerPlugin::GetHostForDebug(wxString &pathToHostApp, ProjectBuildTarget* target)
+{
+ if(!target)
+ return false;
+
+ if (target->GetTargetType() != ttEmbedded)
+ return false;
+
+ if (target->GetHostApplication().IsEmpty())
+ return false;
+
+ wxString out;
+ out = UnixFilename(target->GetHostApplication());
+ Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out); // apply env vars
+ Log(_("Adding file: ") + out);
+ ConvertDirectory(out);
+
+ if (out.empty())
+ {
+ Log(_("Couldn't find the path to the host application!"), Logger::error);
+ return false;
+ }
+
+ pathToHostApp = out;
+
+ return true;
+}
+
bool cbDebuggerPlugin::GetDebuggee(wxString &pathToDebuggee, wxString &workingDirectory, ProjectBuildTarget* target)
{
if (!target)
diff --git a/src/sdk/compiletargetbase.cpp b/src/sdk/compiletargetbase.cpp
index 6ce6fc3..3a6ba5a 100644
--- a/src/sdk/compiletargetbase.cpp
+++ b/src/sdk/compiletargetbase.cpp
@@ -502,6 +502,20 @@ void CompileTargetBase::SetExecutionParameters(const wxString& params)
SetModified(true);
}
+const wxString& CompileTargetBase::GetHostDebugParameters() const
+{
+ return m_HostDebugParameters;
+}
+
+void CompileTargetBase::SetHostDebugParameters(const wxString& params)
+{
+ if (m_HostDebugParameters == params)
+ return;
+
+ m_HostDebugParameters = params;
+ SetModified(true);
+}
+
const wxString& CompileTargetBase::GetHostApplication() const
{
return m_HostApplication;
diff --git a/src/sdk/projectloader.cpp b/src/sdk/projectloader.cpp
index 8d42065..191d446 100644
--- a/src/sdk/projectloader.cpp
+++ b/src/sdk/projectloader.cpp
@@ -541,6 +541,7 @@ void ProjectLoader::DoBuildTargetOptions(TiXmlElement* parentNode, ProjectBuildT
wxString compilerId = m_pProject->GetCompilerID();
wxString parameters;
wxString hostApplication;
+ wxString hostDebugParameters;
bool runHostApplicationInTerminal = false;
bool includeInTargetAll = m_IsPre_1_2 ? true : false;
bool createStaticLib = false;
@@ -603,6 +604,9 @@ void ProjectLoader::DoBuildTargetOptions(TiXmlElement* parentNode, ProjectBuildT
if (node->Attribute("host_application"))
hostApplication = UnixFilename(cbC2U(node->Attribute("host_application")));
+ if (node->Attribute("host_application_debug_parameters"))
+ hostDebugParameters = cbC2U(node->Attribute("host_application_debug_parameters"));
+
if (node->Attribute("run_host_application_in_terminal"))
{
wxString runInTerminal = cbC2U(node->Attribute("run_host_application_in_terminal"));
@@ -672,6 +676,7 @@ void ProjectLoader::DoBuildTargetOptions(TiXmlElement* parentNode, ProjectBuildT
target->SetAdditionalOutputFiles(added);
target->SetExecutionParameters(parameters);
target->SetHostApplication(hostApplication);
+ target->SetHostDebugParameters(hostDebugParameters);
target->SetRunHostApplicationInTerminal(runHostApplicationInTerminal);
target->SetIncludeInTargetAll(includeInTargetAll); // used in versions prior to 1.5
target->SetCreateDefFile(createDefFile);
@@ -1368,6 +1373,10 @@ bool ProjectLoader::ExportTargetAsProject(const wxString& filename, const wxStri
AddElement(tgtnode, "Option", "run_host_application_in_terminal", 1);
else
AddElement(tgtnode, "Option", "run_host_application_in_terminal", 0);
+ if (!target->GetHostDebugParameters().IsEmpty())
+ {
+ AddElement(tgtnode, "Option", "host_application_debug_parameters", target->GetHostDebugParameters());
+ }
}
// used in versions prior to 1.5
diff --git a/src/sdk/resources/select_target.xrc b/src/sdk/resources/select_target.xrc
index 6e5afbd..5a13af8 100644
--- a/src/sdk/resources/select_target.xrc
+++ b/src/sdk/resources/select_target.xrc
@@ -87,6 +87,21 @@
<border>8</border>
</object>
<object class="sizeritem">
+ <object class="wxStaticText" name="ID_STATICTEXT3">
+ <label>Host application debug arguments:</label>
+ </object>
+ <flag>wxTOP|wxLEFT|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>8</border>
+ </object>
+ <object class="sizeritem">
+ <object class="wxTextCtrl" name="txtHostDebugParameters">
+ <style>wxTE_MULTILINE</style>
+ </object>
+ <flag>wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
+ <border>8</border>
+ <option>1</option>
+ </object>
+ <object class="sizeritem">
<object class="wxStaticLine" name="ID_STATICLINE1"/>
<flag>wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_LEFT|wxALIGN_TOP</flag>
<border>8</border>
diff --git a/src/sdk/selecttargetdlg.cpp b/src/sdk/selecttargetdlg.cpp
index 6b04606..bd2dc84 100644
--- a/src/sdk/selecttargetdlg.cpp
+++ b/src/sdk/selecttargetdlg.cpp
@@ -72,6 +72,7 @@ void SelectTargetDlg::UpdateSelected()
XRCCTRL(*this, "chkSetAsDefaultExec", wxCheckBox)->SetValue(name == m_pProject->GetDefaultExecuteTarget());
XRCCTRL(*this, "txtParams", wxTextCtrl)->SetValue(target->GetExecutionParameters());
XRCCTRL(*this, "txtHostApp", wxTextCtrl)->SetValue(target->GetHostApplication());
+ XRCCTRL(*this, "txtHostDebugParameters", wxTextCtrl)->SetValue(target->GetHostDebugParameters());
XRCCTRL(*this, "chkHostInTerminal", wxCheckBox)->SetValue(target->GetRunHostApplicationInTerminal());
}
XRCCTRL(*this, "wxID_OK", wxButton)->Enable(target);
@@ -153,6 +154,16 @@ void SelectTargetDlg::EndModal(int retCode)
execution_parameters[pos] = ' ';
}
target->SetExecutionParameters(execution_parameters);
+
+ wxString debug_parameters = XRCCTRL(*this, "txtHostDebugParameters", wxTextCtrl)->GetValue();
+ pos = 0;
+
+ while ((pos = debug_parameters.find('\n', pos)) != wxString::npos)
+ {
+ debug_parameters[pos] = ' ';
+ }
+ target->SetHostDebugParameters(debug_parameters);
+
target->SetHostApplication(XRCCTRL(*this, "txtHostApp", wxTextCtrl)->GetValue());
target->SetRunHostApplicationInTerminal(XRCCTRL(*this, "chkHostInTerminal", wxCheckBox)->IsChecked());
}
Would these patches be acceptable for inclusion in Code::Blocks? It might be a useful feature for others working with embedded targets.