3

We have a large C++ project and would like to ship only the code that a customer asks for, thus removing all code that is not needed. I.e. if we have some metaprograms like:

/** File: calc.c */
#ifdef ENABLE_SOME_ADVANCED_FEATURE
/** Advanced calculations */
void AdvancedCalc(int a, int b) {
   // ...
}
#else
/** Basic calculations */
void BasicCalc(int a, int b) {
   // ...
}
#endif

I would like some script that does preprocessing of C++ metaprograms, thus if I only wanted the basic calculations after running the script the file would look like this:

/** File: calc.min.c */
/** Basic calculations */
void BasicCalc(int a, int b) {
   // ...
}

Thus, all the code we did not want to ship has been stripped away.

I'm sure there must be something like this out there.

Update:

I think How to get rid of ifdef's in a large c project has the solution I was looking for.

Community
  • 1
  • 1
  • 4
    Doesn't the c++ preprocessor do this already? I don't understand what you're after. – πάντα ῥεῖ Feb 07 '14 at 09:09
  • 4
    @πάνταῥεῖ the one downside is that the code will probably be completely unreadable afterwards. And all included headers will be in one file. – RedX Feb 07 '14 at 09:26
  • 3
    If I understand the question you want to preprocess the file but only on certain parts, that is only on specific lines such as `#ifdef ENABLE_FOO` but not on others such as `#include `. Also see this discussion: http://stackoverflow.com/questions/8713336/run-preprocessor-only-but-with-only-for-certain-statements One idea there is to comment out the preprocessor lines you don't want expanded, then to run `gcc -E`, then to un-comment out the preprocessor lines that you commented out in the first step – Brandin Feb 07 '14 at 09:35
  • 1
    Do you ship the *source code* to the customer or the *compiled binary*? – Martin R Feb 07 '14 at 09:41
  • 1
    @RedX OK I see! Didn't catch the OP's going to ship the source code. I'd try to write a text processing script to do this, catching balanced `#if`/`#else`/'#endif` blocks isn't that hard. – πάντα ῥεῖ Feb 07 '14 at 09:42
  • @Brandin i think `gcc -E` strips out all the comments. – RedX Feb 07 '14 at 09:47
  • I too think that this can be done in `python` in about an hour. – Vorac Feb 07 '14 at 09:52
  • Boost has a program called `bcp` that does similar. If you want *only* the Boost `shared_ptr` stuff, then you would use `bcp` to copy out only what was needed. But it works at the source-file level, and not a preprocessor-level. – jww Feb 07 '14 at 11:35
  • @Vorac Yup! Looks like I have to fire up the old parser and make something myself :P –  Feb 07 '14 at 12:52
  • @IngeHenriksen, great! If you boss allows it, please post the code here afterwords. You will get quite some upvotes :) – Vorac Feb 07 '14 at 13:05
  • 1
    possible duplicate of [How to get rid of ifdef's in a large c project](http://stackoverflow.com/questions/8679350/how-to-get-rid-of-ifdefs-in-a-large-c-project) –  Feb 07 '14 at 13:16

5 Answers5

1

Clang or G++

g++ -E source.cpp

-E Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.

Input files that don't require preprocessing are ignored.

Visual Studio

preprocessor output to stdout

cl /E source.cpp

preprocessor output to file

cl /P source.cpp

Example of how to cut down the unwanted output (ignore-header.pl)

#!/usr/bin/perl

use warnings;
use strict;

while (my $line = <>) {

    if ($line !~ /^#include/) {
        print $line
    }
}

Execute

cat source.cpp | perl ignore-headers.pl | g++ -E -nostdinc -nostdinc++ -x c++ -

Resources

G++ Manual

Visual Stuido Manual

GCC preprocessor

Community
  • 1
  • 1
Ben Crowhurst
  • 8,204
  • 6
  • 48
  • 78
  • Thanks, but sadly the `-E` compiler outputs a lot of "garbage" that I don't want in my source, example here: http://www.network-theory.co.uk/docs/gccintro/gccintro_36.html , removes my `#include` directives etc. so it's not optimal for my use case. I don't want any of the code rewritten but just remove what's not inside the desired `#define` blocks. I tried your solution with the Intel C++ compiler too but encountered the same problem. –  Feb 07 '14 at 12:49
  • Are yee not a developer? I've updated my answer with an example that will cut down the output. – Ben Crowhurst Feb 07 '14 at 15:01
0

You can use GCC preprocessor

gcc -E

See GCC preprocessor

Community
  • 1
  • 1
synapse
  • 130
  • 4
  • Thanks for the tip, but this would output everything I compile to stdout as one big stream - I was rather expecting a single file like in my example. It also outputs a lot of "garbage", see here http://www.network-theory.co.uk/docs/gccintro/gccintro_36.html for an example of what I mean by "garbage". –  Feb 07 '14 at 12:38
0

gcc -E filename should do the trick GCC Options

  • 4
    How is this answer better than the whole bunch that were given 10 minutes or more before? – Jens Gustedt Feb 07 '14 at 09:47
  • Well, I don't think the OP wants the #include-directives to be evaluated (which is done by -E)? – urzeit Feb 07 '14 at 10:16
  • This is a better answer than @synapse as I can do control the compiler output, but it still outputs a lot of "garbage" that I don't want in my source: http://www.network-theory.co.uk/docs/gccintro/gccintro_36.html and removes my `#include` directives etc. so it's not optimal for my use case. I don't want any of the code rewritten but just remove what's not inside the desired `#define` blocks. Thanks though. –  Feb 07 '14 at 12:40
0

Several options:

  1. You can use gcc -E like others suggest, but you can also add the -H flag to get a file listing.

    2 . You could just do your compilation with -MD, and .d files will be generated. You can either process .d files with a script or better yet you can probably create a rule to zip up all dependencies as part of your compile.

  2. I would also look to see how debuginfo packages are generated as they drop sources in /usr/src/debug (at least in the RPM ecosystem)

nhed
  • 5,774
  • 3
  • 30
  • 44
0

I'd prepare a script that:

  • comment-out all the includes and the defines that must not be touched, with some "magic wildcard", like //@TAKE_ME_BACK@ and save it to a temporary file;
  • run cpp -C or whatever preprocessor on the temporary file (cpp -C has the advantage that the file doesn't need to terminate with .c). Important: it must not strip comments (that's the -C for)!
  • uncomment-in all the lines previously commented out, restoring your includes

If you need to deal with recursive #ifdef's, I think that awk range syntax (pattern1,pattern2) could be of great help.

On the other side, if you just need to ignore includes, something like this will do the job:

sed 's|^#include|//@TAKE_ME_BACK@#include|' $file > $file.tmp
cpp -C $file.tmp > $file.tmp2
sed -e '/^#/d' -e 's|//@TAKE_ME_BACK@||' < $file.tmp2 > $file

(you need to take care also of the lines beginning with # dropped by the preprocessor in the last sed).

Note1: in the example I that I have proposed the original file is overwritten: handle with care :)

Note2: working but not tested - just a suggestion to be elaborated/customized.

Sigi
  • 4,826
  • 1
  • 19
  • 23