Is it possible to conditionally compile / run code based on a macro OR a variable?
We have several projects in development sharing the same codebase. Certain pieces of code are only relevant to one or other of those projects.
We have a couple of requirements:
The first requirement is that we want our final releases not to compile in code from the other projects.
One solution (the one we like) is to use the preprocessor to remove that code: (this is what we do in some places).
#if defined PROJECT1
{
// some code
}
#endif
The second requirement is, that while we are developing, it is helpful to make sure that a change of code still works across all projects, so we would like to compile ALL the project code at once, and be able to switch between projects without a recompile - so in other places in our code, we use a variable to determine the project instead:
if (project == 1)
{
// some code
}
What I'd like to be able to do is to combine the benefits of both - code which in some situations (let's say determined by a #define REMOVECODE) is not included in the final exe at all, but in other situations (determined by the non-definition of the REMOVECODE define) to include the code in the compiled .exe
One more thing - sometimes we have code which exists in a couple of projects, so the solution would need to handle tests like "if project == 1 || project == 2"
I'm thinking it would look 开发者_Python百科something like the following (this doesn't work because I don't think you can nest preprocessor directives), but I'm not sure if it is even possible with macros. Maybe there's some kind of template solution?
#ifdef REMOVECODE
#define BEGINTEST #if
#define ENDTEST #endif
#define CONDITION1 defined PROJECT1
#else
#define BEGINTEST if
#define ENDTEST
#define CONDITION1 project == 1
#endif
BEGINTEST(CONDITION1)
{
// some code
}
ENDTEST
If anyone can help out, I'd be much obliged.
If the condition in the test is a compile-time constant, any half-decent optimizing compiler will remove the dead code completely from the object file.
So something as simple as this should work fine:
#ifdef REMOVECODE
#ifdef PROJECT1
#define CONDITION1 1
#else
#define CONDITION1 0
#endif
#else
#define CONDITION1 project == 1
#endif
...
if (CONDITION1)
{
...
}
Run your compiler with -S
(or equivalent) and look at the generated assembly to confirm.
It won't work; you can't generate 'pre-processor directives' from inside macros, etc.
Or, more accurately (since you can generate what looks a pre-processor directive, as shown), if you do generate what looks like a pre-processor directive via a macro, a standard-conforming preprocessor will not recognize it as a directive.
The same comments apply to C and C++:
ISO/IEC 14882:1998 (C++ Standard)
16.3.4 Rescanning and further replacement [cpp.rescan]
¶3 The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one.
ISO/IEC 9899:1999 (C Standard)
6.10.3.4 Rescanning and further replacement
¶3 The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, ...
(The ellipsis goes on to mention the C99 _Pragma
feature.)
How about having another define saying "build everything". And then use
#if defined(PROJECT1) || defined(BUILDALL)
...
#endif
Or to avoid adding || defined(BUILDALL)
everywhere you could stick this somewhere where it will be visible:
#ifdef BUILDALL
#define PROJECT1
#define PROJECT2
//...
#endif
Or just compile with all project macros defined
And what's wrong with having a nightly automated sanity that rebuilds all projects and runs an automated test suite on each one and you'll know if something is broken?
What I see here will likely end up in a #ifdef clusterfuck or additional code complexity + errors for nothing.
Refactor your design. Break the code into smaller, independent libraries. Only link in what you need to each project. Otherwise, you're going to end up with a very complex mess.
Defines to control actions either define these or not If HARD_P1 is not defined block of code are excluded. So a function can be taken out of the compiled result. If SOFT_P1 is defined lines of code are included. If SOFT_P1 is not defined these lines are commented out.
#define HARD_P1
#define SOFT_P1
Then
#ifdef HARD_P1
#define P1
#ifdef SOFT_P1
#define USEP1
#else
#define USEP1 /##/
#endif
#endif
Note the use of /##/, the preprocessor will replace USEP1 with /##/ paste the / together to produce // the // will then comment out the rest of the line. So this can be used to exclude individual lines of code.
Code
#ifdef P1
void test()
{
USEP1 if(project==1)
{
}
}
#endif
精彩评论