Okoboji
Okoboji

Reputation: 3

Makefile specific to directory structure

I'm trying to compile my project using a makefile. I'm new to makefiles so forgive my ignorance. The problem I'm running into is that I would like the output command to build all of the .o files but If I run it as such it will not build the .o files and instead will try to compile all .o files in the /obj directory.

How would I compile all .o file rules in the output rule?

The directory structure for this project is:
recipe_book
|-GFX         (source directory)
|-PageManager (source directory)
|-Pages       (source directory)
|-main        (source directory)
|-obj         (.o files directory)
|-out         (application output)

Here is my Makefile:

#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
COMPILER_FLAGS = -w -g

#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lSDL2 -lSDL2_image

G++ = g++ -std=c++17 $(LINKER_FLAGS) $(COMPILER_FLAGS)

#Source Directories:
GFX := GFX
PAGE_MANAGER := PageManager
PAGES := Pages

#Object Directory:
OBJ := obj

# Complile the objects into the executable
output: main/main.cpp main/main.hpp $(OBJ)/*.o
    $(G++) main/main.cpp $(OBJ)/*.o -o out/recipe_book.out

#make all object files
#'.' turns them into macros?
#GFX
$(OBJ)/%.o: $(GFX)/%.cpp $(GFX)/%.hpp
    $(G++) -I$(GFX) -c $< -o $@

#PageManager
$(OBJ)/%.o: $(PAGE_MANAGER)/%.cpp $(PAGE_MANAGER)/%.hpp
    $(G++) -I$(PAGE_MANAGER) -c $< -o $@

#Pages
$(OBJ)/%.o: $(PAGES)/%.cpp $(PAGES)/%.hpp
    $(G++) -I$(PAGES) -c $< -o $@

clean:
    rm out/*.out obj/*.o

Upvotes: 0

Views: 100

Answers (2)

Asteroids With Wings
Asteroids With Wings

Reputation: 17454

Your output target has, as prerequisites, $(OBJ)/*.o.

But, when nothing's been built yet, that wildcard expands to nothing!

You're going to need to list the objects that are required for the final link of the project, e.g.

output: main/main.cpp main/main.hpp $(OBJ)/GFX.o $(OBJ)/PageManager.o $(OBJ)/Pages.o

This will then trigger the creation of those files (via compilation) where needed.

You can streamline it by putting GFX PageManager Pages in a variable, then performing a substitution to prepend $(OBJ)/ to each one and to append .o to each one.

As an aside, I'd probably roll main into this, rather than treating it specially.

Upvotes: 0

MadScientist
MadScientist

Reputation: 100836

This line:

output: main/main.cpp main/main.hpp $(OBJ)/*.o

cannot work correctly as written. What does this do? It tells make, the target output (which, by the way, you never actually create: this rule creates a totally different file out/recipe_book.out, but leave that aside for now) depends on the files main/main.cpp, main/main.hpp, and the expansion of the glob expression obj/*.o. So, make looks up the files that match the glob expression obj/*.o, which is all the object files that already exist.

If all the object files already exist, then all of them will be linked. If you haven't created any object files, then none of them will be found (just like if you run ls obj/*.o no files are found) and so none of them will be linked.

You have to list the explicit set of object files that you want t link here. You can't use glob expressions to find them.

You can use glob expressions to find the source files, which always (presumably) exist, then convert those into the object files. Maybe something like this:

SOURCES := $(wildcard $(GFX)/*.cpp $(PAGE_MANAGER)/*.cpp $(PAGES)/*.cpp)
OBJECTS := $(addprefix $(OBJ)/,$(patsubst %.cpp,%.o,$(notdir $(SOURCES))))

output: main/main.cpp main/main.hpp $(OBJECTS)

(and by the way, you really should use the real file name for this target not output: in make, all non-phony targets should always have the name of the actual file they create).

Upvotes: 1

Related Questions