7

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!

Odysseus
  • 805
  • 2
  • 11
  • It's not possible. – KamilCuk Feb 05 '20 at 10:27
  • Which part doesn't work? I've tried [this and the output seems ok.](https://godbolt.org/z/mUVKjM). – Groo Feb 05 '20 at 11:01
  • It partially anwers it, but I dont get why I cant store the value of a define within another define. As soon as I #undef the source it is also lost in the new define - even if I am undefing it afterwards.So there is no way I i cant store the value and not make some kind of reference to the original makro? @Groo Well if using a new define it works, but my intention was to reuse BINDIR – Odysseus Feb 05 '20 at 11:02
  • Oh, you want to change the `BINDIR` macro itself? Are you sure this is really needed? Perhaps you could share some details to make sure we're not hunting a XY problem. – Groo Feb 05 '20 at 11:03
  • Excatly - The real purpose is to adjust some destination paths when not cross-compiling. I am sure the right way to achieve this is to change the build-environment properly but in my case that would need reworking a bunch of Makefiles of a very large project so I thought of an alternative – Odysseus Feb 05 '20 at 11:11

2 Answers2

4

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;
Marian
  • 6,897
  • 2
  • 18
  • 31
  • 1
    Minor nitpick: I would recommend using `char const * const bin_dir`. – user694733 Feb 05 '20 at 10:59
  • Well thats a clever workaround but with this solution I also cant use the original BINDIR define and need an extra variable. So I think I would favor defining a new makro `#define BINDIR_NEW PRE_PATH BINDIR` instead – Odysseus Feb 05 '20 at 12:05
4

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
Andrey Semashev
  • 8,115
  • 1
  • 14
  • 25
  • Thanks for the explanation why my approach does not work and this seems to be the most simple way to work around the problem – Odysseus Feb 05 '20 at 12:42