Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C preprocessor - Prepending path for existing define [duplicate]

Lets say I have a define coming from gcc -D option, e.g.

gcc -DBINDIR=\"/usr/bin\"

What I want is to prepend a path to this existing define so BINDIR is something like "/home/user/testbuild/usr/bin"

What I tried:

#define STRINGIZE_NX(A)         #A
#define STRINGIZE(A)            STRINGIZE_NX(A)

#define PRE_PATH                "/home/user/testbuild"
#pragma message                 "PRE_PATH: " STRINGIZE(PRE_PATH)

#ifndef BINDIR
#   error "BINDIR must be defined"
#else
#   pragma message              "BINDIR: " STRINGIZE(BINDIR)
#   define TMP                  BINDIR
#   pragma message              "TMP: " STRINGIZE(TMP)
#   undef  BINDIR
#   define BINDIR               PRE_PATH TMP
#   pragma message              "BINDIR: " STRINGIZE(BINDIR)
#   undef  TMP
#endif

When looking to the compiler output, it seems to me that TMP is not assigned to the value of BINDIR in the way I expected:

note: #pragma message: PRE_PATH: "/home/user/testbuild"
note: #pragma message: BINDIR: "/usr/bin"
note: #pragma message: TMP: BINDIR
note: #pragma message: "/home/user/testbuild" BINDIR

And finally compiler will fail where the defines should get concatenated:

error: expected ')' before 'TMP'
#  define BINDIR    PRE_PATH TMP

What am I doing wrong?

Thanks for every help!

like image 237
Odysseus Avatar asked Feb 05 '20 10:02

Odysseus


2 Answers

It is not possible to modify the value of a macro without losing its initial value. You have to remember that defining a macro is not equivalent to assigning to a variable. In the latter case, the right-hand expression is evaluated, and the resulting value is assigned. In the former case, you define a name (a macro) for a sequence of tokens, which do not get evaluated until the macro is expanded. So when you define this:

#define TMP BINDIR

the TMP macro does not "contain" the path "/usr/bin", it contains "BINDIR", literally. When TMP expands, it expands to BINDIR, which in turn expands to "/usr/bin". When you undefine BINDIR, the value it had is lost and TMP expansion will result in just "BINDIR".

What you could do is to use a different macro for the complete path instead of BINDIR. Something like this:

#define FULL_BINDIR PRE_PATH BINDIR
like image 120
Andrey Semashev Avatar answered Nov 05 '22 04:11

Andrey Semashev


I know this is not exactly what you ask for. However, instead of doing obscure preprocessor magic what about putting to a header file something like:

#undef BIN_DIR
#define BIN_DIR bin_dir
extern char *bin_dir;

and to one of code files and BEFORE including the above header:

char *bin_dir = PRE_PATH BIN_DIR;
like image 4
Marian Avatar answered Nov 05 '22 05:11

Marian