1

I am new in make file.

I have a program made of

main.cpp
types.hpp
application/coordinator.hpp
application/correlation.hpp
application/handler.hpp
application/settings.hpp
libraries/basket.hpp
libraries/config.hpp
libraries/graphics.hpp
...

I have so many files and the list of my files will be updated so many times. I want the make file recognizes automatically which .o file to be generated or updated. I don't want to update my make file each time I create and include a new file. The output must be generated in a directory called bin

main.cpp is my only cpp file and the rest of my files are hpp.

Till now, this link has inspired me to write this code:

CC=g++
CFLAGS= -g -Wfatal-errors 

CFLAGS+= -std=c++11
LIBS= -lboost_filesystem -lboost_system

all: run

run: $(OBJS)
    $(CC) $(CFLAGS) $^ main.cpp -o $@

$(OBJS): bin/%.o : bin/%.hpp

How to improve it to working code and what I want?

Community
  • 1
  • 1
barej
  • 1,330
  • 3
  • 25
  • 56
  • The usual way to go, is letting the compiler generate a list of dependencies for the `.h`/`.hpp` files (using the `-Mx` option family), and include that generated `.d` (files) with your makefile. – πάντα ῥεῖ Feb 19 '15 at 09:28
  • See here for more info: http://stackoverflow.com/questions/2394609/makefile-header-dependencies , and here http://stackoverflow.com/questions/5229561/gnu-make-generating-automatic-dependencies-with-generated-header-files – πάντα ῥεῖ Feb 19 '15 at 09:56
  • Since you have only one `cpp` file, you'll have only one `.o` file – Bulletmagnet Feb 19 '15 at 10:10
  • _@barej_ _"do yo think making `.o` file from `hpp` files"_ You don't, `.o` is produced from `.cpp`/`.c` files. Headers are included by these. Did you mean you have inlined code in header files? There's no difference in compile time for doing so. – πάντα ῥεῖ Feb 19 '15 at 10:46
  • @Bulletmagnet, you refered to a good point. Do yo think making .o file from hpp files is a good idea to reduce compile time due to segmentation of `.o` file? (my hpp files include template implementation too) – barej Feb 19 '15 at 10:48
  • Template implementations must appear in header files. – πάντα ῥεῖ Feb 19 '15 at 10:49
  • 1
    @barej If you include a .hpp into main.cpp, you can't also generate a .o from .hpp, because it will contain definitions of the same classes/objects/methods, and you'll get link errors (duplicate definitions). You need to think about separating the interface (which goes into headers) and implementation (which goes into cpp files) of your software. Then you can include the header into both the implementation source and the source which uses it. Then you need to link the generated object files together. – Bulletmagnet Feb 19 '15 at 10:59

2 Answers2

4

If you intend to only ever have one cpp file, you could write the makefile in the following way:

CXX := g++
CXXFLAGS := -g -Wall -pedantic -Wextra

HEADERS := types.hpp $(wildcard application/*.hpp) $(wildcard libraries/*.hpp)

all: run

run: main.cpp $(HEADERS)
    $(CXX) $(CXXFLAGS) $< -o $@

$(wildcard) will find all headers in application and libraries. The executable will depend on all the headers and main.cpp so if any of them changes, the binary will be rebuilt.

$< means "first dependency". This way, only the cpp file is passed to the compiler.

Note: in GNU make conventions, CC and CFLAGS refer to the C compiler. For C++, the variables are named CXX and CXXFLAGS.

Bulletmagnet
  • 5,665
  • 2
  • 26
  • 56
  • plus 1 for adding `-Wextra` – barej Feb 19 '15 at 10:32
  • Still it is a concern not to add all hpp files. I have a lot of files such as `trash_old.hpp` and so on. could you tell me how to use `$^` in this case? – barej Feb 19 '15 at 10:33
  • 1
    `$(wilcard)` is a blunt tool which assumes you want to use every header in those directories. If you want a more precise list, you can write the `HEADERS:=` line by hand. Or you could use `$(filter)` / `$(filter-out)` to the output of `$(wildcard)` – Bulletmagnet Feb 19 '15 at 10:54
  • 1
    @Bulletmagnet _"you can write the `HEADERS:=` line by hand"_ or use the compiler's `-MM` option to generate a header dependency file as mentioned. – πάντα ῥεῖ Feb 19 '15 at 10:57
  • @Bulletmagnet what is your opinion about [this](http://pastebin.com/AzCh4qMn)? sorry about previous messy codes. – barej Feb 19 '15 at 11:04
3

Here's a different scheme: generate the dependency information while you build the software. This works with multiple cpp files creating multiple object files.

CXX := g++
#CPPFLAGS := preprocessor flags, e.g. -I and -D
CXXFLAGS := -g -Wall -pedantic -Wextra -Wfatal-errors -std=c++11 -MD -MP

SOURCES := main.cpp
OBJECTS := $(SOURCES:.cpp=.o)
DEPFILES:= $(OBJECTS:.o=.d)

all: run

# Link the executable
run: $(OBJECTS)
    $(CXX) $(LDFLAGS) $^ -o $@ $(LIBS)

-include $(DEPFILES)

When .o files are built, the -MD -MP flags tell the compiler to generate the dependency file as a side-effect. These dependency files are included into the makefile if they are present.

This uses GNU make's built-in %.o : %.cpp rule. We just supply parameters to it (CXX, CPPFLAGS, CXXFLAGS).

Make already knows to rebuild .o files if the corresponding .cpp file is newer (either GNU make's built-in rule or a hand-written one). With .d files included into the makefile, we tell make that the object file also depends on the header files and should be rebuilt when one of them changes. But the rule to rebuild the .o is always %.o : %.cpp

Bulletmagnet
  • 5,665
  • 2
  • 26
  • 56
  • thank you so much. It is very close to what I need. could you please tell my why my attempt to put `main.d`, `main.o` and the executive file in bin directory fails giving me error: `make: *** No rule to make target 'bin/main.o', needed by 'run'. Stop.` my code it [here](http://pastebin.com/gU1nBDGd) – barej Feb 19 '15 at 12:59
  • @barej That's because make cannot match the `bin/` folder with your source pathes. One way to fix is using the `$(vpath)` make variable and put the path were your `.cpp` resides there. – πάντα ῥεῖ Feb 19 '15 at 14:21
  • The easiest use of `vpath` is to put the makefile in the bin folder, so all object files and executables can be referred without paths. `vpath` will enable make to find the sources which are elsewhere. – Bulletmagnet Feb 19 '15 at 16:21
  • @Bulletmagnet _"... to put the makefile in the bin folder ..."_ Keeping a makefile in the build folder is pretty inconvenient though (e.g. I usually don't have build folders managed with the SCCS). I have to admit that `$(vpath)` is probably not the best solution, but writing explicit rules as you proposed serves much better. I'm actually using make templates and path substitution to generate these. – πάντα ῥεῖ Feb 19 '15 at 18:21