Good Practice Makefile

I have the following directory structure in my project:

bin/ dist/ include/ β”œβ”€β”€ module_a/ └── module_b/ Makefile src/ β”œβ”€β”€ module_a/ └── module_b/ 

The include/ folder contains *.hpp , and *.cpp is located in src/ . I would like to compile all the sources in bin/ and then link them together with dist/ . Seems like a pretty reasonable wish for me.

I would like to learn the best Makefile practices for this case. All I can find is %.o: %.cpp target, but actually it doesn’t work due to different source and binary folders.

I tried to use something like this:

 D_SRC = src D_BIN=bin F_CPP := $(shell find $(D_SRC) -iname '*.cpp' -type f) F_OBJ := $(shell echo $(F_CPP) | sed s:\ :\\n:g | sed s:$(D_SRC):$(D_BIN): | sed 's:^\(.*\)\.cpp$$:\1\.o:') $(F_OBJ): $(F_SRC) $(foreach file, $(F_SRC), \ $(GXX) $(CXXFLAGS) -c $(file)\ ) 

This target does not work because $(F_OBJ) starts with bin/ , and foreach compiles the sources into the current working directory. I could compile it with bin/ , but this will only happen with a few sed expressions, and it is ugly enough as it is.

This is probably so difficult for me because I don’t know make everything is good, but I can’t be the only one with this project setup. In my opinion, this should be fairly common. I know that I can write a Makefile for each module separately, but is this really the best choice here?

EDIT: I was wondering what I would do with several Makefiles. If someone was at the root and another in src/module_a , how would the latter know about bin/ ? If you execute it with make -f src/module_a/Makefile , it will be the same as executing it from the root directory, because its working directory will be root. Another way, I think, would be to change the directory before executing it, for example: make -C include/module_a , but in this case, how would he find bin/ ? I would not want to have something like D_BIN = ../../bin in the Makefile.

+6
source share
1 answer

What I usually do is make a Makefile in the src directory (which can be called from the top-level Makefile if you want), and then use these rules:

 D_BIN = ../bin $(D_BIN)/%.o: %.cpp 

You can also experiment only with a makefile in the top-level directory and use rules that look like this:

 D_BIN = bin D_SRC = src $(D_BIN)/%.o: $(D_SRC)/%.cpp 

but I didn’t use such rules, so I don’t know the pros and cons of how I usually do it. The way I usually do this works fine, I even have rules that are structured like this:

 $(D_BIN)/%.d: %.cpp 

and the link rule will look like this:

 ../dist/outexe: $(F_OBJ) 

Using foreach is usually disapproving, because it does not use all the functions built into the usual makefile rules (i.e. there is no dependency on the verification based on each file, or you build everything or nothing), and as such foreach should be used only as a last resort but in this case you can make it work without using foreach.

In addition to this, there are much simpler ways to create file lists; you do not need to use a shell or sed.

 F_CPP = $(wildcard *.cpp) F_OBJ = $(F_CPP:.cpp=.o) 

Update: this is how I usually produce recursive make:

 SUBDIRS = src .PHONY: $(SUBDIRS) all: $(SUBDIRS) $(SUBDIRS): @echo "Building $@... " $(MAKE) -C $@ $(MFLAGS) 

Then, indeed, in your submaterial, you will need to use .. / bin, for example.

However, if the project is as simple as yours, you might be better off if you only have one makefile at the root level and use these rules:

 D_BIN = bin D_SRC = src $(D_BIN)/%.o: $(D_SRC)/%.cpp 

Recursive make files are fine (fine, but not really) if you have a really complicated directory structure, where you will add / remove / modify new tree trees as you continue. But for a simple project where you just want to have separate directories for code and objects, this is probably too large.

+6
source

All Articles