5

I want to have a C pre-preprocessor which is filtering some #define statements from the sourcecode without changing anything else.

Why? This should be used to remove some client specific code from the sources if the source is handed out to another client.

Does anyone know of an existing solution?

Thanks! Simon

  • I'd move the client specific code to its own header instead. You can run through just the pre-processor, but it will expand everything. – Pete Kirkham Sep 15 '09 at 11:08
  • That's not an option. Cause there are many of these defines and it would break the logic of the functions if they are moved out to a header. But thanks for that suggestion! –  Sep 15 '09 at 11:11
  • I don't understand what's wrong with the standard C pre-processor. Can you clarify? – MarkJ Sep 15 '09 at 12:30

9 Answers9

9

You can use something like awk instead of CPP ? Add some flags in your code surrounding the piece of code to be removed. For example:

(...)
//BEGIN_REMOVE_THIS_CODE

printf("secret code");

//END_REMOVE_THIS_CODE
(...)

then write a awk script to remove this code, something like...

BEGIN { write=1;}
/^\/\/BEGIN_REMOVE_THIS_CODE/ { write=0; next;}
/^\/\/END_REMOVE_THIS_CODE/ { write=1; next;}
    {
    if(write==1) print $0;
    }
Pierre
  • 34,472
  • 31
  • 113
  • 192
  • As proposed, this involves modifying the source code so that the special patterns can be recognized. If the code does not exist yet (so you can start off with this scheme), then its fine. If your code already exists and uses #ifdef, then I recommend (strongly) using one of the many tools that deal with 'XXX is always defined' and 'YYY is always undefined'. – Jonathan Leffler Sep 15 '09 at 14:08
2

I recommend using an additional macro language layer for code filtering, like filepp. You may use a C preprocessor friendly syntax to express which parts belongs to which clients.

//%ifdef CLIENT_A
  code for client A
//%endif

//%ifdef CLIENT_B
  code for client B
//%endif

//%if "CLIENT_A" || "CLIENT_B"
  code for client A and B
//%endif

The '//%' prefix enables You to compile the code unmodified. You may run filepp before You giving out the code to a client.

sambowry
  • 2,436
  • 1
  • 16
  • 13
2

This sounds like what I asked about in Is there a C pre-processor which eliminates ifdef blocks based on values defined. The best answer I got was sunifdef, or 'Son of unifdef', which has worked reliably for me on some excessively contorted conditional code (the accumulated crud from over 20 years of development on a wide variety of platforms with an inadequate theory of how to do platform-specific compilation).

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

I don't think you need a preprocessor for this. If you don't have nested #ifdef's in your code, any regex engine can remove anything that is located between #ifdef CLIENT and #endif (use non-greedy matching to match first #endif, not last).

qrdl
  • 34,062
  • 14
  • 56
  • 86
  • I don't think regex is the right tool for this job. It's not always the first `#endif` you want to match. If the code looks like `#if CLIENT... #if FOO... #endif... #endif` you want to match the second `#endif`. If the `if`s are the other way around, you want to match the first. – Graeme Perrow Sep 15 '09 at 11:20
  • @Graeme - that's why I wrote "If you don't have nested #ifdef's" part. However new Perl regex engine has a support for matching opening/closing braces so it can do the job even in case of nested #ifdefs – qrdl Sep 15 '09 at 11:29
  • @qrdl - sorry, I somehow missed that part of your answer. – Graeme Perrow Sep 15 '09 at 13:14
1

I would put the client specific code in a separate directory or possibly part of a different project that would need to be checked out of the source control.

Put a function call that would be stubbed out or (I forget the proper term) loosely linked so that another function can be put in its place.

Robert Deml
  • 12,390
  • 20
  • 65
  • 92
0

If you're using gcc, then you can use:

gcc <insert files here> -E

The -E option tells gcc to only preprocess the sources, and not to compile them.

Or, you could use grep to filter out specific files and let the preprocessor loose on them only.

grep -r '#define CLIENT_CODE' ./*.h 
aviraldg
  • 9,531
  • 6
  • 41
  • 56
  • Note : You are highly recommended *not* to do what you're saying you want to do. Preprocessing sources beforehand can break compatibility macros if your client is using a different system. – aviraldg Sep 15 '09 at 11:14
  • Would downvoters care to leave a comment explaining what's wrong with this answer? I'm giving it +1 as it looks perfect to me. Even if you aren't using gcc as a compiler you could still download it and use it as a preprocessor for this task. – MarkJ Sep 15 '09 at 12:32
  • @MarkJ - Aviraldg's comment explains why this is not an ideal solution. I didn't downvote it myself, but unless the application is going to be built on an identical system to the one on which the preprocessing is done, this could lead to at best compilation failure and at worst very difficult-to-find bugs. – Graeme Perrow Sep 15 '09 at 13:16
  • @MarkJ: I didn't down vote, but might have done had it been at a positive number. The trouble is that the C pre-processor pre-processes the source, and includes the contents of and so on. This is not likely to be what the questioner had in mind - they want the source except for some bits. So, I'm with Graeme and Aviraldg - this is not the right answer. – Jonathan Leffler Sep 15 '09 at 14:23
0

You can also try unifdef which is rather simpler than sunifdef.

Tony Finch
  • 173
  • 4
0

Why don't you do something like:

client_a_specific_functions_definition.c

double discount_for_paying_upfront() { return 0.1; };
// ...

client_b_specific_functions_definition.c

double discount_for_paying_upfront() { return 0.05; };
// ...

When you hand out the code it is just a matter of selecting the right file with their specific definitions.

Then you would create a header file to include it where you need to access the client specific code with something like:

client_functions.h

#pragma once 

double discount_for_paying_upfront();

#define stringify(x) #x
#define FILE2(a) stringify(client_##a##_specific_functions_definition.c)
#define FILE(a) FILE2(a)

#include FILE(CLIENT_NAME)

#undef stringify
#undef FILE2
#undef FILE

Then say you #include "client_functions.h" in your main.c. You could compile it with:

 gcc -DCLIENT_NAME=a main.c -o a.exe
 gcc -DCLIENT_NAME=b main.c -o b.exe
caiohamamura
  • 2,260
  • 21
  • 23
-2

as far as I know... the preprocessor can be run as a separate step (using the correct compiler optios) . This way you can do whatever you want with the processed code.

Toad
  • 15,593
  • 16
  • 82
  • 128
  • Hi, that was the first I was thinking about. But I haven't found a simple option to use the preprocessor to replace only specific #define statements. Do you have an example for this? –  Sep 15 '09 at 11:18
  • looks like aviraldg beat me to it with the compiler options and all. – Toad Sep 15 '09 at 11:33
  • on a side note... in the good old days, the preprocessor was a separate step and a separate executable. It's very possible a separate preprocessor can still be found. – Toad Sep 15 '09 at 11:34
  • @reiner It is still a separate step in some environments. GCC, for example, doesn't do preprocessing itself - it calls cpp to do the job. cpp is available as separate binary. – qrdl Sep 15 '09 at 12:30
  • @reiner: your answer was downvoted because, although you can run the C preprocessor separately (either by compiler options or as a separate executable), what the questioner wants is not what the pre-processor does. For example, if the code contains '#include ', the output should still contain '#include ', and the macros (such as getchar()) should be left unchanged. On the other hand, some bits of code - those protected by #ifdef CLIENT / remove this / #else / keep this / #endif should only have the 'keep this' section of output. The standard preprocessor can't do that. – Jonathan Leffler Sep 15 '09 at 17:10