I have the string put in debugger initial command:
source $(TARGET_COMPILER_DIR)bin\my.gdb
But when gdb runs, I see it looks like below:
[debug]> source bin\my.gdb
[debug]bin\my.gdb: No such file or directory.
But most of the time, it works Ok, which means the value "$(TARGET_COMPILER_DIR)" was replaced correctly, and my.gdb was correctly located and run.
Did you also experience this bug?
I'm using the latest nightly build (windows XP)
For those would like to reproduce this bug, do the following:
1, disable CC(I think this is not CC related)
2, open the file "CodeBlocks.workspace"
3, Set the gdb executable as "$(TARGET_COMPILER_DIR)bin\gdb.exe" (no double quotes)
4, Set the "wxsmith" as the active c::b project
4a, You should check off the option "Auto-build the project if it is not up-to-date". (I suppose you have already build this target)
5, start the debugging. (you can select the option "Do *not" run the debugee", as this bug appeared in the initialization of the debugging session)
6, then read the debugger log. This is mine:
Selecting target:
wxSmith
Adding source dir: E:\code\cb\cleantrunk\src\plugins\contrib\wxSmith\
Adding source dir: E:\code\cb\cleantrunk\src\plugins\contrib\wxSmith\
Adding file: ..\..\..\devel\codeblocks.exe
Changing directory to: E:/code/cb/cleantrunk/src/plugins/contrib/wxSmith/.
[debug]PATH=.;E:\code\cb\wx\wxWidgets-2.8.12\lib\gcc_dll;E:\code\cb\wx\wxWidgets-2.8.12\lib\gcc_dll\mswu;E:\code\cb\cleantrunk\src\devel;E:\code\cb\cleantrunk\src\base\tinyxml;E:\code\gcc\PCXMinGW463\bin;E:\code\gcc\PCXMinGW463;.;C:\Program Files\Intel\WiFi\bin;E:\code\common_bin;E:\code\shortcut
[debug]Command-line: bin\gdb.exe -nx -fullname -quiet -args ../../../devel/codeblocks.exe
[debug]Working dir : E:\code\cb\cleantrunk\src\plugins\contrib\wxSmith
Starting debugger: bin\gdb.exe -nx -fullname -quiet -args ../../../devel/codeblocks.exe
done
[debug]> set prompt >>>>>>cb_gdb:
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
[debug]Reading symbols from E:\code\cb\cleantrunk\src\devel\codeblocks.exe...done.
[debug](gdb) >>>>>>cb_gdb:
[debug]> show version
[debug]GNU gdb (GDB) 7.5.50.20120823-cvs
[debug]Copyright (C) 2012 Free Software Foundation, Inc.
[debug]License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
[debug]This is free software: you are free to change and redistribute it.
[debug]There is NO WARRANTY, to the extent permitted by law. Type "show copying"
[debug]and "show warranty" for details.
[debug]This GDB was configured as "mingw32".
[debug]For bug reporting instructions, please see:
[debug]<http://www.gnu.org/software/gdb/bugs/>.
[debug]>>>>>>cb_gdb:
[debug]> set confirm off
Debugger name and version: GNU gdb (GDB) 7.5.50.20120823-cvs
[debug]>>>>>>cb_gdb:
[debug]> set width 0
[debug]>>>>>>cb_gdb:
[debug]> set height 0
[debug]>>>>>>cb_gdb:
[debug]> set breakpoint pending on
[debug]>>>>>>cb_gdb:
[debug]> set print asm-demangle on
[debug]>>>>>>cb_gdb:
[debug]> set unwindonsignal on
[debug]>>>>>>cb_gdb:
[debug]> set print elements 0
[debug]>>>>>>cb_gdb:
[debug]> set disassembly-flavor att
[debug]>>>>>>cb_gdb:
[debug]> catch throw
[debug]Catchpoint 1 (throw)
[debug]>>>>>>cb_gdb:
[debug]> source E:\code\cb\cb_trunk\src\devel\share\codeblocks/scripts/stl-views-1.0.3.gdb
[debug]>>>>>>cb_gdb:
[debug]> source bin\my.gdb
[debug]bin\my.gdb: No such file or directory.
[debug]>>>>>>cb_gdb:
[debug]> directory E:/code/cb/cleantrunk/src/plugins/contrib/wxSmith/
[debug]Source directories searched: E:/code/cb/cleantrunk/src/plugins/contrib/wxSmith;$cdir;$cwd
[debug]>>>>>>cb_gdb:
[debug]> set args --debug-log --multiple-instance -na -ns -nd -p=debugCC
[debug]>>>>>>cb_gdb:
Look:
bin\gdb.exe
It looks like if I set the active project as "Code::Blocks wx2.8.x", I don't have such issue. So, I guess this is caused by something related to "switch the project".
EDIT:
When debugging, I found that in the code:
void MacrosManager::ReplaceMacros(wxString& buffer, ProjectBuildTarget* target, bool subrequest)
{
if (buffer.IsEmpty())
return;
static const wxString delim(_T("$%["));
if ( buffer.find_first_of(delim) == wxString::npos )
return;
cbProject* project = target
? target->GetParentProject()
: Manager::Get()->GetProjectManager()->GetActiveProject();
EditorBase* editor = Manager::Get()->GetEditorManager()->GetActiveEditor();
if (!target)
{
if (project)
{
// use the currently compiling target
target = project->GetCurrentlyCompilingTarget();
// if none,
if (!target)
// use the last known active target
target = project->GetBuildTarget(project->GetActiveBuildTarget());
}
}
if (project != m_LastProject || target != m_LastTarget || (editor && (editor->GetFilename() != m_ActiveEditorFilename)) )
RecalcVars(project, editor, target);
The "target" value is 0. This may cause the issue.
Because the variable $(TARGET_COMPILER_DIR) is only set when "target" is valid, see below:
if (target)
{
const StringHash& v = target->GetAllVars();
for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
m_Macros[it->first.Upper()] = it->second;
if (Compiler* c = CompilerFactory::GetCompiler(target->GetCompilerID()))
{
m_Macros[_T("TARGET_CC")] = c->GetPrograms().C;
m_Macros[_T("TARGET_CPP")] = c->GetPrograms().CPP;
m_Macros[_T("TARGET_LD")] = c->GetPrograms().LD;
m_Macros[_T("TARGET_LIB")] = c->GetPrograms().LIB;
wxFileName MasterPath;
MasterPath.SetPath(c->GetMasterPath(), wxPATH_NATIVE);
m_Macros[_T("TARGET_COMPILER_DIR")] = MasterPath.GetPathWithSep(wxPATH_NATIVE);
}
m_Macros[_T("TARGET_OBJECT_DIR")] = target->GetObjectOutput();
}
Look at the code:
void MacrosManager::ReplaceMacros(wxString& buffer, ProjectBuildTarget* target, bool subrequest)
{
if (buffer.IsEmpty())
return;
static const wxString delim(_T("$%["));
if ( buffer.find_first_of(delim) == wxString::npos )
return;
cbProject* project = target
? target->GetParentProject()
: Manager::Get()->GetProjectManager()->GetActiveProject();
EditorBase* editor = Manager::Get()->GetEditorManager()->GetActiveEditor();
if (!target)
{
if (project)
{
// use the currently compiling target
target = project->GetCurrentlyCompilingTarget();
// if none,
if (!target)
// use the last known active target
target = project->GetBuildTarget(project->GetActiveBuildTarget());
}
}
if (project != m_LastProject || target != m_LastTarget || (editor && (editor->GetFilename() != m_ActiveEditorFilename)) )
RecalcVars(project, editor, target);
wxString search;
wxString replace;
When I debug this code, I found that
target = project->GetBuildTarget(project->GetActiveBuildTarget());
will still set the target to 0.
Internally, it call
int cbProject::IndexOfBuildTargetName(const wxString& targetName) const
{
for (unsigned int i = 0; i < m_Targets.GetCount(); ++i)
{
ProjectBuildTarget* target = m_Targets[i];
if (target->GetTitle().Matches(targetName))
return i;
}
return -1;
}
But the "targetName" passed in is "All", and it does not match any target name of wxsmith.cbp, so it return -1, and the final "target" is still 0.
Now, we go to the line:
if (project != m_LastProject || target != m_LastTarget || (editor && (editor->GetFilename() != m_ActiveEditorFilename)) )
RecalcVars(project, editor, target);
But unluckily, this if condition is false. m_LastTarget is 0, and m_LastProject is the same as project, so there is no chance to call RecalcVars().
This cause the issue.
...but then precisely it is the correct thing to do. As targets can be assigned to different compilers and therefore different debuggers, virtual targets have no specified value.
The only thing you could do is to record when the active target has changes and issue the RecalcVars then.
I review the code a little, and I see that if the active target name is "All", which is not a valid build target, the debugger will open a dialog to let the user select one, see the code:
int DebuggerGDB::DoDebug(bool breakOnEntry)
{
// set this to true before every error exit point in this function
m_Canceled = false;
ProjectManager* prjMan = Manager::Get()->GetProjectManager();
// select the build target to debug
ProjectBuildTarget* target = 0;
Compiler* actualCompiler = 0;
if (m_PidToAttach == 0)
{
Log(_("Selecting target: "));
if (!m_pProject->BuildTargetValid(m_ActiveBuildTarget, false))
{
int tgtIdx = m_pProject->SelectTarget();
if (tgtIdx == -1)
{
Log(_("canceled"));
m_Canceled = true;
return 3;
}
target = m_pProject->GetBuildTarget(tgtIdx);
m_ActiveBuildTarget = target->GetTitle();
}
else
target = m_pProject->GetBuildTarget(m_ActiveBuildTarget);
So, the debugger plugin know which target it will going to debug.
But what about Macromanager? it was just blind. E.g.:
wxString DebuggerConfiguration::GetDebuggerExecutable(bool expandMacro)
{
wxString result = m_config.Read(wxT("executable_path"), wxEmptyString);
if (expandMacro)
Manager::Get()->GetMacrosManager()->ReplaceEnvVars(result);
return !result.empty() ? result : cbDetectDebuggerExecutable(wxT("gdb"));
}
This code, the debugger plugin try to prepare the full path of gdb.exe, it directly call ReplaceEnvVars(result), which is:
void ReplaceEnvVars(wxString& buffer) { ReplaceMacros(buffer); }
Then:
void MacrosManager::ReplaceMacros(wxString& buffer, ProjectBuildTarget* target, bool subrequest)
{
if (buffer.IsEmpty())
return;
static const wxString delim(_T("$%["));
if ( buffer.find_first_of(delim) == wxString::npos )
return;
cbProject* project = target
? target->GetParentProject()
: Manager::Get()->GetProjectManager()->GetActiveProject();
EditorBase* editor = Manager::Get()->GetEditorManager()->GetActiveEditor();
if (!target)
{
if (project)
{
// use the currently compiling target
target = project->GetCurrentlyCompilingTarget();
// if none,
if (!target)
// use the last known active target
target = project->GetBuildTarget(project->GetActiveBuildTarget());
}
}
if (project != m_LastProject || target != m_LastTarget || (editor && (editor->GetFilename() != m_ActiveEditorFilename)) )
RecalcVars(project, editor, target);
NOTE: when call the function: ReplaceMacros(), the default argument target = 0 is used, which try to use the "GetActiveBuildTarget()", but as we know, currently, the activeTarget name is "All", which is not a valid build target, so the variable "target" is still ZERO.
Thus, even the function RecalcVars() is called, the piece of code in the function body still has no chance to run.
if (target)
{
const StringHash& v = target->GetAllVars();
for (StringHash::const_iterator it = v.begin(); it != v.end(); ++it)
m_Macros[it->first.Upper()] = it->second;
if (Compiler* c = CompilerFactory::GetCompiler(target->GetCompilerID()))
{
m_Macros[_T("TARGET_CC")] = c->GetPrograms().C;
m_Macros[_T("TARGET_CPP")] = c->GetPrograms().CPP;
m_Macros[_T("TARGET_LD")] = c->GetPrograms().LD;
m_Macros[_T("TARGET_LIB")] = c->GetPrograms().LIB;
wxFileName MasterPath;
MasterPath.SetPath(c->GetMasterPath(), wxPATH_NATIVE);
m_Macros[_T("TARGET_COMPILER_DIR")] = MasterPath.GetPathWithSep(wxPATH_NATIVE);
}
m_Macros[_T("TARGET_OBJECT_DIR")] = target->GetObjectOutput();
}
So: ("TARGET_OBJECT_DIR") is still empty string.
The simple solution I thought is:
1, when the debugger plugin started debugging, it can temporary switch the target to a real valid target name, e.g. Switch "All" to "src".
2, when it finish debugging, do switching back.
This way, the ReplaceMacros() function can get the real valid target, and it should solve the bug.
What's you comments about this?
EDIT:
Maybe, we can let the debugger plugin to temporary to select this one, and select to none after debugging......
void cbProject::SetCurrentlyCompilingTarget(ProjectBuildTarget* bt)
{
m_CurrentlyCompilingTarget = bt;
}
In the case that I open a workspace, and I don't want to build anything, and just start debugging.
Hi, all, I finally find a solution, this method is just like way currently used in
int CompilerGCC::Run(ProjectBuildTarget* target)
{
...
if (!target)
{
if (m_RealTargetIndex == -1) // only ask for target if a virtual target is selected
{
int idx = -1;
int bak = m_RealTargetIndex;
if (m_pProject->GetBuildTargetsCount() == 1)
idx = 0;
else
idx = DoGUIAskForTarget();
m_RealTargetIndex = idx;
target = DoAskForTarget();
m_RealTargetIndex = bak;
}
else
target = DoAskForTarget();
}
// DBGLOG(_T("2) target=%s, m_RealTargetIndex=%d, m_TargetIndex=%d"), target ? target->GetTitle().c_str() : _T("null"), m_RealTargetIndex, m_TargetIndex);
if (!target)
return -1;
m_pProject->SetCurrentlyCompilingTarget(target); // help macros manager
.....[prepare many run command]
.....
m_pProject->SetCurrentlyCompilingTarget(0);
Manager::Get()->GetProjectManager()->SetIsRunning(this);
return 0;
}
See: it use SetCurrentlyCompilingTarget() to dynamically handle the target related variable for Macromanager.
So, I create a patch (against an quite old svn revision ;))which did same thing as this for debugger plugin.
Index: E:/code/cb/cb_trunk/src/plugins/debuggergdb/debuggergdb.cpp
===================================================================
--- E:/code/cb/cb_trunk/src/plugins/debuggergdb/debuggergdb.cpp (revision 8190)
+++ E:/code/cb/cb_trunk/src/plugins/debuggergdb/debuggergdb.cpp (working copy)
@@ -632,12 +632,17 @@
else
target = m_pProject->GetBuildTarget(m_ActiveBuildTarget);
+ // the macro manager will internal use this current compiling target to initial
+ // some target related variables
+ m_pProject->SetCurrentlyCompilingTarget(target);
+
// make sure it's not a commands-only target
if (target->GetTargetType() == ttCommandsOnly)
{
cbMessageBox(_("The selected target is only running pre/post build step commands\n"
"Can't debug such a target..."), _("Information"), wxICON_INFORMATION);
Log(_("aborted"));
+ m_pProject->SetCurrentlyCompilingTarget(0);
return 3;
}
Log(target->GetTitle());
@@ -654,6 +659,7 @@
msg.Printf(_("This %s is configured to use an invalid debugger.\nThe operation failed..."), target ? _("target") : _("project"));
cbMessageBox(msg, _("Error"), wxICON_ERROR);
m_Canceled = true;
+ m_pProject->SetCurrentlyCompilingTarget(0);
return 9;
}
@@ -677,6 +683,7 @@
}
m_Canceled = true;
+ m_pProject->SetCurrentlyCompilingTarget(0);
return -1;
}
@@ -685,6 +692,7 @@
{
cbMessageBox(_T("Could not decide which debugger to use!"), _T("Error"), wxICON_ERROR);
m_Canceled = true;
+ m_pProject->SetCurrentlyCompilingTarget(0);
return -1;
}
@@ -698,6 +706,7 @@
cbMessageBox(_T("A plugin interrupted the debug process."));
Log(_("Aborted by plugin"));
m_Canceled = true;
+ m_pProject->SetCurrentlyCompilingTarget(0);
return -1;
}
// Continue
@@ -817,6 +826,7 @@
if (ret != 0)
{
m_Canceled = true;
+ m_pProject->SetCurrentlyCompilingTarget(0);
return ret;
}
@@ -836,8 +846,12 @@
--i;
}
if (!m_State.HasDriver())
+ {
+ m_pProject->SetCurrentlyCompilingTarget(0);
return -1;
+ }
+
bool isConsole = (target && target->GetTargetType() == ttConsoleOnly);
m_State.GetDriver()->Prepare(isConsole, m_printElements);
m_State.ApplyBreakpoints();
@@ -871,6 +885,7 @@
if (m_pProcess)
SwitchToDebuggingLayout();
+ m_pProject->SetCurrentlyCompilingTarget(0);
return 0;
} // Debug
Tested and works fine. :)