Prevent same macro having different definitions in multiple translation units

723 Views Asked by At

I'm creating a library that will need different command-line defined macros (-D option) per resulting binary (.exe, .so, .dll) that uses it. I would like to ensure each translation unit that will be a part of resulting binary, was compiled with the same macro definition. This is to e.g. prevent accidental ODR violations and other unexpected behavior.

For instance, this should be prevented:

g++ -DMY_MACRO=5 a.cpp
g++ -DMY_MACRO=7 b.cpp
ld a.o b.o -o result

The library will provide header - library.hpp - that will be included in all translation units using it. My idea is to use that header as a place to create checks for misuse.

The question is, what's the best way to do it?

Preferably misuse would be detected, in order of preference, during:

  • compilation
  • linking
  • runtime

It's likely not possible during compilation due to way how C/C++ compilers work. But maybe at least during linking?

I would like to avoid using external tools/scripts. I know one could write a script that goes through all object files and checks if all used the same value. But maybe there is a way less intrusive for the buildsystem, just reusing how C++ linker or compiler works.

Platform independent solution would be best, but ways for doing it independently for gcc/clang and msvc would also be useful.

Macro definition will always be an integral number.

2

There are 2 best solutions below

0
Matthias On BEST ANSWER

How about something along these lines:

main.cpp:

int checkMyMacro#MY_MACRO;

a.cpp and b.cpp:

static int *checkMyMacro = &checkMyMacro#MY_MACRO;

resulting in a unresolved external error from linker on misuse.

You could insert the second part into the header defining that macro.

1
SoronelHaetir On

If you merely wish to protect against accidental misuse something like the following would likely be enough:

#if defined(MY_MACRO) && MY_MACRO_MIN > MY_MACRO || MY_MACRO_MAX < MY_MACRO
#error MY_MACRO is out of range
#endif

Protecting against malicious misuse at any point prior to run-time is basically impossible under the circumstances you describe.