Author Topic: special handling of the macro replacement ""?  (Read 1195746 times)

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
special handling of the macro replacement ""?
« on: January 28, 2026, 06:43:08 am »
Hi, when I'm using the gd_on's unified workspace/code::blocks cbp files, I see something strange.

See here: it looks like GCC works OK, but GDB failed to find the dll(setting wrong PATH)

Re: crash when I try to open a wxsmith file under C::B against wx 3.3.1

If a variable a has a filed name b, and its value is
Code
""
, and if we have
Code
AAA$(#a.b)
, we will finally get
Code
AAA""

The current implementation treats an empty string "" as a valid value and performs the replacement, resulting in
Code
AAA""
instead of the expected
Code
AAA
.

I'd like to see your options on this issue.

Thanks.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline AndrewCot

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 682
Re: special handling of the macro replacement ""?
« Reply #1 on: January 28, 2026, 09:21:14 am »
Make sure you get approval by MortenMacFlybefore making any changes. Check out the SF tickets for posts on macro and hopefully you will fins the ticket and have a read before you spend time on this as you may end up wasting your time.
BTW I agree with you.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #2 on: January 28, 2026, 09:33:30 am »
Make sure you get approval by MortenMacFlybefore making any changes. Check out the SF tickets for posts on macro and hopefully you will fins the ticket and have a read before you spend time on this as you may end up wasting your time.
BTW I agree with you.

Hi, AndrewCot,  long time no see.
I think it is a good direction.
Maybe there are similar topics in the sourceforge tickets.
So I will search for that.

To switch between the debug version of wx library,  using the unified workspace or cbp project is much easier.  We don't need to replace or editor each cbp files.


If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline gd_on

  • Lives here!
  • ****
  • Posts: 866
Re: special handling of the macro replacement ""?
« Reply #3 on: January 28, 2026, 05:54:21 pm »
To add some informations:
In standard cbp files, there is an environment variable defined as:
Code
<Variable name="WX_CFG" value="" />
When it is used in standard cbp files, as:
Code
<Add directory="$(#wx33_64.lib)/gcc_dll$(WX_CFG)
there are no problems.

In my unified workspace/cbp files, I define a wxwidgets path as, in my case, C:\wxWidgets-3.3.1 as the base, and in a user-defined field, I have created a wx_cfg variable. If I set this variable with nothing (an empty field), the variable is eliminated after a click on the save button. It's why, as in standard cbp files, I tried to set an empty string by "". Apparently, this is the problem described by ollydbg when I use a variable as:
Code
<Add directory="$(#WXWIDGETS)/lib/gcc_dll$(#WXWIDGETS.WX_CFG)
Windows 11 64 bits (26H2), svn C::B (last version or almost!), wxWidgets 3.3.3 (tests with 3.3.4), Msys2 Compilers 16.2.0, 64 bits (seh, posix : gcc, g++ and gfortran in C:\msys64\mingw64) or 32 bits (dwarf2, posix  in C:\msys64\mingw32).

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #4 on: January 29, 2026, 04:10:26 am »
I did some test, and if the empty value key is allowed to add in the global compiler variable, the result may be that there are a lot of predefined keys saved to the config file, for example, see below:

Code
		<sets>
<default>
<cccccc>
<DDD>
<str>
<![CDATA[]]>
</str>
</DDD>
<BBB>
<str>
<![CDATA[xxx]]>
</str>
</BBB>
<CFLAGS>
<str>
<![CDATA[]]>
</str>
</CFLAGS>
<BIN>
<str>
<![CDATA[]]>
</str>
</BIN>
<LFLAGS>
<str>
<![CDATA[]]>
</str>
</LFLAGS>
<OBJ>
<str>
<![CDATA[]]>
</str>
</OBJ>
<LIB>
<str>
<![CDATA[]]>
</str>
</LIB>
<INCLUDE>
<str>
<![CDATA[]]>
</str>
</INCLUDE>
<BASE>
<str>
<![CDATA[aaaa]]>
</str>
</BASE>
</cccccc>

You can see, I don't want to do that DDD is a user defined key, and its value is empty. While the CFLAGS is predefined key, and its value is also empty.

So, I think the solution is: using the predefined value string, for example, a value named: __EMPTY__ or just an empty string "", then in the code when we get the value, we have to check the result, and remove the __EMPTY__ or "" in the command line.

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #5 on: January 29, 2026, 04:53:05 am »
Oh, I change the mind, it looks like this patch should solve the issue, see here:

* sdk: try to handle empty valued members in global compiler variable
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline AndrewCot

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 682
Re: special handling of the macro replacement ""?
« Reply #6 on: January 30, 2026, 10:41:01 am »

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #7 on: January 30, 2026, 10:53:50 am »
Have a look at https://sourceforge.net/p/codeblocks/tickets/1188/ .....

I looked at your patch file in the above link, it is a bit complex, I think my patch is much simple, we can just leave the gcd variable as empty.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #8 on: February 13, 2026, 03:43:20 pm »
Committed in r13786.

I think supporting the unified cbp file is an important feature.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #9 on: February 21, 2026, 04:17:30 am »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Wkerry

  • Multiple posting newcomer
  • *
  • Posts: 121
Re: special handling of the macro replacement ""?
« Reply #10 on: February 21, 2026, 06:57:43 am »
Any chance of moving to a commons CBP set for each environment to save allot of file and then duplication etc when a new WxWidget version comes out.
The file in https://github.com/gerard-durand/codeblocks_gd_cbps/tree/master/src look like they have solved this for windows only.

Offline Wkerry

  • Multiple posting newcomer
  • *
  • Posts: 121
Re: special handling of the macro replacement ""?
« Reply #11 on: February 24, 2026, 11:10:52 am »
Any chance of getting the following in once update to make the cbp's consistent as this will also reduce the cbp quantity?
     https://github.com/stahta01/CodeBlocks_Unofficial_Testing/blob/master/src/CodeBlocks_Unix_MacOS.cbp

Any chance for noobs for the following?
   https://github.com/stahta01/CodeBlocks_Unofficial_Testing/blob/master/src/CodeBlocks_Windows_MSYS2.cbp

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #12 on: February 24, 2026, 02:01:03 pm »
Any chance for noobs for the following?
   https://github.com/stahta01/CodeBlocks_Unofficial_Testing/blob/master/src/CodeBlocks_Windows_MSYS2.cbp

If I remember correctly. the msys2's wx library is shared library, so it has many separate libraries. I'm not sure it is easy to add to gd_on's cbp.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #13 on: Yesterday at 06:24:13 am »
It looks like I still see this issue in the recent C::B.

I have defined one of the global variable "wxWidgets.wx_cfg" as something like "".

I found that the building stage works correct.

Something like this in the compiler build log:

Code
[ 33.3%] g++.exe -Wall -std=gnu++20 -m64 -g -pipe -mthreads -fmessage-length=0 -fexceptions -DHAVE_W32API_H -D__WXMSW__ -DWXUSINGDLL -DcbDEBUG -DNOPCH -DwxUSE_UNICODE -D_WIN64 -D__WX__ -DWINVER=0x0501 -DLINK_LEXERS -DSCI_LEXER -DWXMAKINGDLL_SCI -std=gnu++20 -iquote.objs33_64\include -I.objs33_64\include -I. -IE:\code\wxWidgets-3.3.4\include -IE:\code\wxWidgets-3.3.4\lib\gcc_dll""\mswu -Isdk\wxscintilla\include -Iinclude\tinyxml -Isdk\wxscintilla\src\scintilla\include -Isdk\wxscintilla\src\scintilla\src -Isdk\wxscintilla\src\scintilla\lexlib -c D:\code\cb\cb_sf_git\cccrash2019\src\sdk\wxscintilla\src\PlatWX.cpp -o .objs33_64\sdk\wxscintilla\src\PlatWX.o

You can see that the
Code
-IE:\code\wxWidgets-3.3.4\lib\gcc_dll""\mswu

But when I try to start the debugger, it just failed to find the wx's dll, the debugger log:

Code
Set variable: PATH=.;E:\code\wxWidgets-3.3.4\lib\gcc_dll"";D:\code\cb\cb_sf_git\cccrash2019\src\devel33_64;D:\code\cb\cb_sf_git\cccrash2019\src\exchndl\win64\lib;F:\msys2\mingw64\bin;F:\msys2\mingw64;...

[debug]Command-line: F:\code\gdb-14.1.90.20231204-x86_64-python\bin\gdb.exe -nx -fullname -quiet  -args D:/code/cb/cb_sf_git/cccrash2019/src/devel33_64/codeblocks.exe
[debug]Working dir : D:\code\cb\cb_sf_git\cccrash2019\src\devel33_64


You can see that the "PATH" command failed to add the path "E:\code\wxWidgets-3.3.4\lib\gcc_dll".

So, I think I still need to find a way to "remove" the double quote in the command generation. Or, I need to make this "wxWidgets.wx_cfg" as empty, not the "".

If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 6247
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: special handling of the macro replacement ""?
« Reply #14 on: Today at 01:45:04 am »
Code
diff --git a/src/include/globals.h b/src/include/globals.h
index 8eab1bc2..25344464 100644
--- a/src/include/globals.h
+++ b/src/include/globals.h
@@ -228,12 +228,21 @@ extern DLLIMPORT wxString MakeUniqueString(const wxString& text,  const wxString
 extern DLLIMPORT void AppendArray(const wxArrayString& from, wxArrayString& to);
 
 extern DLLIMPORT wxString UnixFilename(const wxString& filename, wxPathFormat format = wxPATH_NATIVE);
 extern DLLIMPORT void QuoteStringIfNeeded(wxString& str);
 extern DLLIMPORT bool NeedQuotes(const wxString &str);
 
+/** \brief Remove all empty quote pairs (@c "" ) from a string.
+ *
+ * An empty quote pair is harmless inside a command line, the shell or the process
+ * launcher simply swallows it. It is fatal inside a path though, e.g. a global
+ * compiler variable defined as @c "" expands to @c ".../lib/gcc_dll""" which is not
+ * an existing directory when put into @c PATH .
+ */
+extern DLLIMPORT wxString cbStripEmptyQuotes(const wxString& str);
+
 /// Escapes spaces and tabs (NOT quoting the string)
 extern DLLIMPORT wxString EscapeSpaces(const wxString& str);
 
 extern DLLIMPORT FileType FileTypeOf(const wxString& filename);
 extern DLLIMPORT wxString cbFindFileInPATH(const wxString &filename);
 
diff --git a/src/plugins/debuggergdb/debuggergdb.cpp b/src/plugins/debuggergdb/debuggergdb.cpp
index 24facd91..e9cdc3da 100644
--- a/src/plugins/debuggergdb/debuggergdb.cpp
+++ b/src/plugins/debuggergdb/debuggergdb.cpp
@@ -897,13 +897,15 @@ int DebuggerGDB::DoDebug(bool breakOnEntry)
         {
             wxString newLibPath;
             const wxString libPathSep = platform::windows ? ";" : ":";
             newLibPath << "." << libPathSep;
 
             CompilerCommandGenerator *generator = actualCompiler->GetCommandGenerator(m_pProject);
-            newLibPath << GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep);
+            // Strip empty quote pairs (e.g. from a global variable defined as ""), otherwise
+            // entries like "E:\wx\lib\gcc_dll""" end up in PATH and are not valid directories.
+            newLibPath << cbStripEmptyQuotes(GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep));
             delete generator;
 
             if (newLibPath.Mid(newLibPath.Length() - 1, 1) != libPathSep)
                 newLibPath << libPathSep;
             newLibPath << oldLibPath;
             wxSetEnv(CB_LIBRARY_ENVVAR, newLibPath);
diff --git a/src/sdk/cbproject.cpp b/src/sdk/cbproject.cpp
index 9f6d363b..4bf60a0f 100644
--- a/src/sdk/cbproject.cpp
+++ b/src/sdk/cbproject.cpp
@@ -2033,13 +2033,15 @@ wxString cbGetDynamicLinkerPathForTarget(cbProject* project, ProjectBuildTarget*
         if (!generator)
               return wxEmptyString;
 
         wxString libPath;
         const wxString libPathSep = platform::windows ? ";" : ":";
         libPath << "." << libPathSep;
-        libPath << GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep);
+        // Strip empty quote pairs (e.g. a global variable defined as ""), they would
+        // make the path entry invalid when used as PATH/LD_LIBRARY_PATH.
+        libPath << cbStripEmptyQuotes(GetStringFromArray(generator->GetLinkerSearchDirs(target), libPathSep));
         if (!libPath.IsEmpty() && libPath.Mid(libPath.Length() - 1, 1) == libPathSep)
             libPath.Truncate(libPath.Length() - 1);
 
         delete generator;
         return libPath;
     }
diff --git a/src/sdk/globals.cpp b/src/sdk/globals.cpp
index 0cde5347..87a7b653 100644
--- a/src/sdk/globals.cpp
+++ b/src/sdk/globals.cpp
@@ -270,12 +270,28 @@ bool NeedQuotes(const wxString &str)
 {
     bool hasSpace = str.Find(_T(' ')) != -1;
     bool hasParen = !platform::windows && (str.Find(_T('(')) != -1 || str.Find(_T(')')) != -1);
     return !str.IsEmpty() && str.GetChar(0) != _T('"') && (hasSpace || hasParen);
 }
 
+wxString cbStripEmptyQuotes(const wxString& str)
+{
+    if (str.Find(_T('"')) == wxNOT_FOUND)
+        return str;
+
+    // An empty quote pair ("") is swallowed by the shell/process launcher, so it does
+    // not hurt in a command line. In a path used as an environment variable (PATH,
+    // LD_LIBRARY_PATH) it makes the whole entry invalid, so remove all of them.
+    wxString result(str);
+    // Repeat, because there can be more than one pair (or nested ones).
+    while (result.Replace("\"\"", wxEmptyString, true) != 0)
+        ;
+
+    return result;
+}
+
 wxString EscapeSpaces(const wxString& str)
 {
     wxString ret = str;
     if (!ret.IsEmpty() && ret[0] != _T('"') && ret[0] != _T('\''))
     {
         // TODO: make it faster
diff --git a/src/sdk/uservarmanager.cpp b/src/sdk/uservarmanager.cpp
index f7c38584..5661c5e4 100644
--- a/src/sdk/uservarmanager.cpp
+++ b/src/sdk/uservarmanager.cpp
@@ -190,13 +190,18 @@ wxString UserVariableManager::Replace(const wxString& variable, std::vector<wxSt
 
             std::set<wxString> ar = {varName};
             m_ui->OpenEditWindow(ar);
             Reload();
         }
     }
-    return value;
+
+    // A variable is sometimes defined as "" (an empty quote pair) just to make
+    // $(#var) expand to nothing. Drop those empty quote pairs here, so that they
+    // can't leak into paths, e.g. "$(#wx.lib)/gcc_dll$(#wx.cfg)" turning into
+    // ".../gcc_dll""" which is an invalid directory when put into PATH.
+    return cbStripEmptyQuotes(value);
 }
 
 std::vector<wxString> UserVariableManager::GetVariableSetNames() const
 {
     std::vector<wxString> names;
     names.reserve(m_VariableSetMap.size());


I'm testing above patch, it try to remove all the "" in the macro replacement in string generation, also in the compiler and debugger plugin.


EDIT:

The patch works fine.
« Last Edit: Today at 06:49:05 am by ollydbg »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.