• FEATURED

View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# Subdirectories in makefile

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

9 replies to this topic

### #1Maeriden  Members

Posted 29 January 2013 - 08:50 AM

In an effort to try to learn makefiles I wrote this

C = $(CXX) CFLAGS = -g -Wall -Wextra -I$(SRC_DIR) -std=c++0x

SRC_DIR = src
BIN_DIR = bin
OBJ_DIR = obj

vpath %.cpp $(SRC_DIR) vpath %.h$(SRC_DIR)
vpath %.o $(OBJ_DIR) GPATH = src obj SRC = main.cpp resources.cpp ui.cpp OBJ =$(SRC:.cpp=.o)

.PHONY: clean all

all: $(OBJ)$C -o $(BIN_DIR)/exe$^

main.o: main.cpp defaults.h
$C -c$< -o $(OBJ_DIR)/$@ $(CFLAGS) resources.o: resources.cpp resources.h$C -c $< -o$(OBJ_DIR)/$@$(CFLAGS)

ui.o: ui.cpp ui.h defaults.h
$C -c$< -o $(OBJ_DIR)/$@ $(CFLAGS) clean: rm -f$(OBJ_DIR)/*.o


When I run make and the obj directory is empty it compiles all the .cpp files and places them in $(OBJ_DIR)/$@ -> obj/file.o

However when it is time to execute the all target, g++ doesn't find .o files, because $^ contains only the files without the directory prepended According to http://www.gnu.org/software/make/manual/make.html#Search-Algorithm this is the intended behavior (though not what I want at all) and it says I can modify it using the GPATH variable, which I set but seems to be ignored by make Notes: if I run make again it finds the files in the obj directory, and since they don't need to be recompiled the path is preserved, so I can't even modify all to be $C -o $(BIN_DIR)/exe$(addprefix $(OBJ_DIR)/$^)

A first invocation of make would build and link the files correctly, but the second time it would try to link obj/obj/file.o and fail

What am I doing wrong?

### #2wintertime  Members

Posted 29 January 2013 - 10:55 AM

Using make when not all files are in the same dir is notoriously complicated (maybe switch to a less time consuming tool?).

It could help if in your link command under all: you change $^ to$(OBJ_DIR)/$^ so those files can be found. ### #3Maeriden Members Posted 29 January 2013 - 01:31 PM That's what I thought at the beginning (see the note). In that case if any .o is not found it gets built in$(OBJ_DIR), then make links files in $(OBJ_DIR) and makes me happy. But every time that a file does NOT need to be rebuilt, the path where make finds it is remembered (so main.o becomes obj/main.o) when used both as target and dependency. Proceeding to the link command it becomes g++ -o bin/exe obj/obj/main.o What really makes my head hurt is why make ignores GPATH. I wouldn't have any problem if only that worked ### #4Karsten_ Members Posted 29 January 2013 - 02:44 PM If you set the SRC .cpp files to include the directory for each one, it might work however I don't really recommend that. Why do you need you .o files in a separate folder? If you do "rm -f$(OBJ)" it will clean them all up anyway.

Also, I dont know if you care, but I personally try to keep away from GNU extensions so that it works with different make tools (i.e BSD make).
main.o: main.cpp defaults.h
$C -c$< -o $(OBJ_DIR)/$@ $(CFLAGS) resources.o: resources.cpp resources.h$C -c $< -o$(OBJ_DIR)/$@$(CFLAGS)

ui.o: ui.cpp ui.h defaults.h
$C -c$< -o $(OBJ_DIR)/$@ $(CFLAGS)  You also dont need this bit, you can just make a rule to generate .o files from .cpp (this is the main reason for make) An example of such a rule would be ".cpp.o:". If you need an example, I am very happy to post my template. http://tinyurl.com/shewonyay - Thanks so much for those who voted on my GF's Competition Cosplay Entry for Cosplayzine. She won! I owe you all beers Mutiny - Open-source C++ Unity re-implementation. Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game. ### #5Maeriden Members Posted 29 January 2013 - 06:12 PM Why do you need you .o files in a separate folder? If you do "rm -f$(OBJ)" it will clean them all up anyway.

Well, I don't actually plan on cleaning the .o files very often, and I prefer not to keep them in the project root directory

Also, I dont know if you care, but I personally try to keep away from GNU extensions so that it works with different make tools (i.e BSD make).

I don't specifically need to write a file that works with other tools, but I suppose it would be better to learn how to do it. Which extensions did I use?

You also dont need this bit, you can just make a rule to generate .o files from .cpp (this is the main reason for make) An example of such a rule would be ".cpp.o:".

I've been wondering about this kind of rules. I've seen "$(OBJ): %.o: %.cpp" (here) but I can't understand how that would handle recompilation in the case a header file included by the source is modified Thanks for the offer, but I've already seen quite a bit of examples. What I need is someone who would explain them ### #6Karsten_ Members Posted 31 January 2013 - 10:47 AM but I can't understand how that would handle recompilation in the case a header file included by the source is modified Yeah, this is a little bit tricky (which is where a lot of devs use a tool to generate the makefile for them). You ideally need to work out the dependencies of each cpp to work out which header they rely on. GCC does support this with the use of .d files. I have never really looked into this. Personally... when working with a smallish project I just get a list of all my .h files and add them as a rule dependency. I.e if any header in the project changes, the whole thing gets re-compiled. When I work on a large project... I break the project up into seperate modules (each with their own Makefile) and am back to working with a smallish project ;D Edited by Karsten_, 31 January 2013 - 10:49 AM. http://tinyurl.com/shewonyay - Thanks so much for those who voted on my GF's Competition Cosplay Entry for Cosplayzine. She won! I owe you all beers Mutiny - Open-source C++ Unity re-implementation. Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game. ### #7Bacterius Members Posted 31 January 2013 - 12:37 PM Using make when not all files are in the same dir is notoriously complicated (maybe switch to a less time consuming tool?). It could help if in your link command under all: you change$^ to $(OBJ_DIR)/$^ so those files can be found.

Well, I had the same problem a while ago, and wanted to find a general-purpose solution, and sort of found one, at least for Linux. What I did was mirror the src directory structure onto obj, and use some arcane commands to make it work. I had to ask on stackoverflow... Anyway here it is, at least for one of my projects:

EXECUTABLE = epsilon
INCLUDE = -Iinclude/
CXX = g++

OBJECTS = $(subst cpp,o,$(subst src/,obj/,$(shell find src/ -name '*.cpp'))) HEADERS =$(shell find include/ -name '*.hpp')

CPPFLAGS = -O2 -std=c++11 -march=native
LDLIBS = -lOpenCL

$(EXECUTABLE):$(OBJECTS)
@mkdir -p bin/
@echo Linking $(EXECUTABLE)... @$(CXX) $(OBJECTS) -o$(addprefix bin/, $(EXECUTABLE))$(LDLIBS)

$(OBJECTS): obj/%.o : src/%.cpp$(HEADERS)
@mkdir -p $(@D) @echo Building$@ from $<... @$(CXX) $(CPPFLAGS)$(INCLUDE) -c $< -o$@

clean:
@echo Cleaning $(EXECUTABLE)... @rm -f$(addprefix bin/, $(EXECUTABLE)) @rm -f obj/ --recursive  I don't remember if you need to create the root obj/ directory first, try it out, I guess. I think it is not very efficient, however, but that may just be my own incompetence at writing makefiles. Yes, using a shell find is probably a horrible idea and any experienced member will likely laugh at the code above, but it has worked for me so far and designing pretty makefiles is not one of my priorities. “If I understand the standard right it is legal and safe to do this but the resulting value could be anything.” ### #8Maeriden Members Posted 01 February 2013 - 04:16 PM Mmm it's not very different from mine. To get around the issue of directories the target objects are written directly with obj/ prepended. I wanted to avoid this solution because I didn't understand how to make make (no pun) work out the headers dependencies with a rule like$(OBJECTS): obj/%.o : src/%.cpp and thus decided to write a rule for each .o to avoid recompiling the whole project. Doing so meant that I had to manually write the directory variable in each rule, which seemed kind of dumb.

From the informations I was able to gather (I couldn't find an example that explained problems with GPATH) it looks like the solutions are: writing the path manually for each rule, using the general rule and have all the sources recompiled every time an header changes, or learning to use .d files (which will wait since I got fed up with make for a while).
Or use a different make system.

Edited by Maeriden, 01 February 2013 - 04:48 PM.

### #9King Mir  Members

Posted 02 February 2013 - 09:59 PM

Make does have variables, so you can have the directory be a variable, so you only have to change it in one place.

### #10Maeriden  Members

Posted 03 February 2013 - 09:54 AM

I know. It just didn't seem a smart solution so I looked for something else

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.