Within my projects I need to access the value of the $(SolutionDir)
macro at runtime. To do that I've tried adding pre processor entries like DEBUG_ROOT=$(SolutionDir)
or DEBUG_ROOT=\"$(SolutionDir)\"
but this results in various compiler errors due to invalid escape sequences since $(SolutionDir)
contains single \
characters (e.g. $(SolutionDir) = c:\users\lukas\desktop\sandbox\
).
Is there an easy way to pass the value of the $(SolutionDir)
macro into my code?
Backround
I am utilizing function OutputDebugString(..)
quite a lot within my debug builds to see what my code is doing.
/* debug.h */
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define LOCATION __FILE__ "(" TOSTRING(__LINE__) ") : "
#if !defined(DEBUG_ROOT)
#define DEBUG_ROOT "#" /* escape string to force strstr(..) to fail */
#endif
/*
** DBGMSG macro setting up and writing a debug string.
** Note: copying the strings together is faster than calling OutputDebugString(..) several times!
** Todo: Ensure that size of dbgStr is not exceeded!!!
*/
#define DBGMSG(text) \
{ \
char dbgStr[1024]; \
char *pFile; \
pFile = strstr(LOCATION, DEBUG_ROOT); \
if (pFile == LOCATION) \
{ \
wsprintf(dbgStr, ".%s", pFile + strlen(DEBUG_ROOT)); \
} \
else \
{ \
wsprintf(dbgStr, "%s", LOCATION); \
} \
wsprintf(dbgStr, "%s%s", dbgStr, text); \
OutputDebugString(dbgStr); \
}
/* somewhere in the code */
DBGMSG("test")
Using the snipped will cause a printout like c:\users\lukas\desktop\sandbox\testconsole\main.c(17) : test
within the output window of Visual Studio. This speeds up finding the location within your code that caused the printout since you can simply double click on the line of the output window and Visual Studio automatically jumps to the specified code location.
Since depending on the location of the solution the absolute path (__FILE__
expands to the absolute path) the "header" of the debug strings may get quite long. I've seen that Visual Studio is smart enough to understand relative paths to e.g. the solution root directory. To reduce the length of the strings I'm checking if __FILE__
is within a DEBUG_ROOT
directory and if so I'm replacing DEBUG_ROOT
with a simple '.'
to generate a relative path to DEBUG_ROOT
. So if I write #define DEBUG_ROOT "c:\\users\\lukas\\desktop\\sandbox"
the final debug string of the example above will be .\testconsole\main.c(17) : test
. Currently I'm setting the value of DEBUG_ROOT
within the preprocessor definitions of the project.
Since several people are working on the project it is not a smart move to have an absolute path within the project settings since each team member may check-out the source files to a different root directory. So I've tried to use the $(SolutionDir)
macro to create something like DEBUG_ROOT=\"$(SolutionDir)\\"
. But by doing so I'm running into trouble. Since $(SolutionDir) = c:\users\lukas\desktop\sandbox\
expanding of DEBUG_ROOT
leads to undefined escape sequences, unterminated strings and a lot more ugly compiler errors...
Solution
Based on the answer of kfsone I've come up with the following solution which makes it possible to pass any value of a Visual Studio macro such as $(SolutionDir)
into your code. The following solution is independent of the used Visual Studio version and language C/C++.
Adding SOLUTION_DIR=\"$(SolutionDir)"
to the preprocessor entries of your project results in a compiler command line which looks something like that:
/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "SOLUTION_DIR=\"C:\Users\Lukas\Desktop\sandbox\""
/Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /nologo /c /Wp64 /ZI /TP
/errorReport:prompt
Note that $(SolutionDir)
is preceeded by a \"
to create a "
characted infront of the value of $(SolutionDir)
but is terminated by a single "
. Looking at the compiler's command line shows that the terminating "
is escaped by the last \
of $(SolutionDir)
.
Using SOLUTION_DIR
within your code results in unknown escape sequences and the string ends up with all \
characters being removed. This is done by the compiler which expands SOLUTION_DIR
and intepretes \
as begin of an escape sequence.
Using the TOSTRING(x)
macro of my code posted above solves this issue since it forces the compiler to use the string as it is without further processing.
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define SOLUTION_DIR2 TOSTRING(SOLUTION_DIR)
// the following line may cause compiler warnings (unrecognized character escape sequence)
printf("%s\n", SOLUTION_DIR); // prints C:UsersLukasDesktopsandbox
// the following line compiles without any warnings
printf("%s\n", SOLUTION_DIR2); // prints "C:\Users\Lukas\Desktop\sandbox"
From here it is only a simple step to do some string magic to remove the "
characters from SOLUTION_DIR2
.