Jump to content

  • Log In with Google      Sign In   
  • Create Account

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.

  • You cannot reply to this topic
9 replies to this topic

#1 Maeriden   Members   -  Reputation: 140

Like
0Likes
Like

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?



Sponsor:

#2 wintertime   Members   -  Reputation: 1877

Like
0Likes
Like

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.



#3 Maeriden   Members   -  Reputation: 140

Like
0Likes
Like

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



#4 Karsten_   Members   -  Reputation: 1655

Like
0Likes
Like

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.

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.


#5 Maeriden   Members   -  Reputation: 140

Like
0Likes
Like

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



#6 Karsten_   Members   -  Reputation: 1655

Like
0Likes
Like

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.

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.


#7 Bacterius   Crossbones+   -  Reputation: 9281

Like
0Likes
Like

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.


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#8 Maeriden   Members   -  Reputation: 140

Like
0Likes
Like

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.

Thank you all for your advice, I really apreciate it :)

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


#9 King Mir   Members   -  Reputation: 2050

Like
0Likes
Like

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.



#10 Maeriden   Members   -  Reputation: 140

Like
0Likes
Like

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.



PARTNERS