0

Question

I have three files in my current working directory:

  • hello.cpp
  • goodbye.cpp
  • prog.cpp

I would like to only preprocess hello.cpp and goodbye.cpp and dump the output in files hello.i and goodbye.i. Is there a way to achieve this using g++ in a Ubuntu Linux command line using one command? The reason I would like to call g++ only once is because I would eventually like to include this command in my own Makefile.

What I've tried

I basically did the following:

g++ -E -o goodbye.i hello.i goodbye.cpp hello.cpp

Which, unsurprisingly, failed with the following error:

g++ : fatal error: cannot specify '-o' with '-c', '-S' or '-E' with multiple files compilation terminated

I also tried g++ -E goodbye.cpp hello.cpp, which only reminded me that the preprocessor dumps to stdout by default. I do, for the purposes of this exercise, need for g++ to dump the result into an actual *.i file...

What I'm trying to avoid

From the comments, it seems to me that I can provide a further clarification. I'm trying to avoid having multiple commands in my Makefile, as each separate .cpp file would generate a separate command:

all: preprocess_hello preprocess_goodbye

preprocess_hello:
    g++ -E -o hello.i hello.cpp

preprocess_hello:
    g++ -E -o goodbye.i goodbye.cpp

Obviously, this is not ideal, because every new file I add would require adding a new command and updating the all target.

user32882
  • 5,094
  • 5
  • 43
  • 82
  • 2
    "[B]ecause I would eventually like to include this command in my own Makefile" seems like a strange reason. Why does it have to be *one* command because of that? – molbdnilo May 31 '22 at 09:08
  • What prevents you from writing two lines of command to preprocess each of file? Makefiles accepts multiple lines of command. – Louis Go May 31 '22 at 09:09
  • @molbdnilo because I might have 100 files. Should I then write 100 commands? – user32882 May 31 '22 at 09:10
  • @user32882 you can make one rule that applies to multiple files but processes one file at a time. Can you explain what you are trying to do? maybe show your makefile so far? – user253751 May 31 '22 at 09:11
  • @user253751 I don't have a Makefile yet, but I believe the question is clear enough as it is. Making one rule that applies to multiple files but processes one file at a time does sound promising. Would you demonstrate how I can do that with my simple example above? – user32882 May 31 '22 at 09:13
  • @user32882 you should elaborate on the restriction about 100 files. That might be the point. – Louis Go May 31 '22 at 09:14
  • @LouisGo What aspect about the restriction would you like for me to elaborate on exactly? – user32882 May 31 '22 at 09:14
  • A bigger picture like "I want to preprocess a bunch of files and generated each `*.i`" or so. Then we could provide more solutions to your question. Indeed what @user253751 said might be the correct direction, but more context is helpful. – Louis Go May 31 '22 at 09:15
  • 1
    What is the purpose of the .i file? – user253751 May 31 '22 at 09:16
  • @LouisGo please see edit to my question where I clearly show what I'm trying to avoid and why. – user32882 May 31 '22 at 09:19
  • @user253751 it contains preprocessed C++ code. – user32882 May 31 '22 at 09:19
  • 1
    I believe what @user253751 meant is that what would you like to do with `*.i` files. Are you parsing inside makefile or having another script triggered to parse...etc. Also you might want to add a tag for makefile. – Louis Go May 31 '22 at 09:21
  • 1
    If the point is to just generate .i files for all .cpp files, only one time, then you don't even really need make and you can probably do it with a shell script, although it's not difficult with make. – user253751 May 31 '22 at 09:23
  • @LouisGo I would like to turn them into object files and then archive them into a static library. I don't have any shell scripts, just a Makefile and the indicated files, as mentioned in my question. – user32882 May 31 '22 at 09:26
  • @user253751 if it's not difficult with Make like you say, then please post an answer showing me how to do it. – user32882 May 31 '22 at 09:26
  • @user32882 most people turn .cpp files directly into .o files - it's pretty unusual to use .i in the middle – user253751 May 31 '22 at 09:31
  • I think you should find yourself a more substantial introduction to `make` than whatever you're using now. – molbdnilo May 31 '22 at 09:37
  • That said I'd use `.i` with some error checking scripts like: "Do my source file handling all the nums declared in the header". While a static library is an archive of `.o`s which are the result of compilation units. See [this](https://stackoverflow.com/a/34479664/4123703). – Louis Go May 31 '22 at 09:44
  • Just to answer the exact question asked: there's no way to get a single invocation of the compiler (at least not any compiler I'm aware of, including GCC and clang) to process multiple input `.c` files and generate multiple output `.i` files. It's not something the compiler can do. Using a pattern rule such as in the answer below is the right approach. – MadScientist May 31 '22 at 15:35

1 Answers1

3

You can use a pattern rule so Make knows how to generate a .i file from a .c file:

%.i: %.cpp
    g++ -E -o $@ $<

and then if your makefile ever requires hello.i, Make will know that it can use the command g++ -E -o hello.i hello.cpp

E.g. if you have all: hello.i goodbye.i and run make all it will know that it needs hello.i and goodbye.i and it will make them.


If you have a list of .cpp files and you need to convert it to a list of .i files (e.g. if you want to do all: $(CPPFILES) but it doesn't work because those are the .cpp files and not the .i files) you can use patsubst:

all: $(patsubst %.cpp,%.i,$(CPPFILES))

You can even use wildcard to get the list of cpp files. To make all depend on all the .i files for all the .cpp files in the current directory, you could use

all: $(patsubst %.cpp,%.i,$(wildcard *.cpp))
user253751
  • 57,427
  • 7
  • 48
  • 90
  • This smells like the right answer. I'll do some research and accept it when I get it to work. Thanks for taking the time. – user32882 May 31 '22 at 09:28