patterncppMinor
Makefile for C++ OpenGL with GLFW and glad
Viewed 0 times
makefilewithglfwgladforopengland
Problem
This is a makefile I wrote to compile a simple OpenGL test project which is going to use the libraries GLFW and the C library glad.c.
Since this is basically the first makefile I wrote, I could surely use some criticism as to what is good style and what isn't. I also wonder if there is a more elegant way to handle the fact that glad is actually a C library and has to be compiled with
CC = gcc
CXX = g++
COMPILE_FLAGS = -Wall -ggdb -O3
LINK_FLAGS = -lglfw3 -lopengl32 -lglu32 -lgdi32
glfw = d:/external/glfw-3.1
glfw_inc = $(glfw)/include
glfw_lib = $(glfw)/lib64
glad = d:/external/glad-c
glad_inc = $(glad)/include
INCLUDES = -I$(glfw_inc) -I$(glad_inc)
LIBRARIES = -L$(glfw_lib)
cpp_files = main.cpp
objects = $(cpp_files:.cpp=.o)
headers =
all: main.exe
main.exe: $(objects) glad.o
$(CXX) $(LIBRARIES) -o main.exe $(objects) glad.o $(LINK_FLAGS)
$(objects): %.o: %.cpp $(headers) makefile
$(CXX) $(COMPILE_FLAGS) $(INCLUDES) -c -o $@ %%CODEBLOCK_0%%lt;
glad.o: glad.c
$(CC) $(COMPILE_FLAGS) $(INCLUDES) -c -o glad.o glad.cSince this is basically the first makefile I wrote, I could surely use some criticism as to what is good style and what isn't. I also wonder if there is a more elegant way to handle the fact that glad is actually a C library and has to be compiled with
gcc instead of g++, but g++ is used for everything else.Solution
First of all, good for you for learning how to write a proper
With that said, here are some things that may help you improve your
Prefer
The names are equivalent, but since you're using GNU Make, you may as well follow its conventions, and one convention is to name it
We recommend 'Makefile' because it appears prominently near the beginning of a directory listing, right near other important files such as 'README'.
Use standard variable names
There are standard names for some of the variables you're using. For example, use
Add
It's good practice to use variables like
The reason for doing that is in the next point.
Use the implicit rules
GNU Make already has an implicit rule for creating
The result of this is that if you have defined the flags correctly, you can omit an explicit rule and rely instead on the implicit rule. In this particular
To expand this a bit, here's what happens when I run
As you can see, after it has identified a needed target (
Add
Your main rule (pardon the pun) does this:
There are a number of changes I'd make to that line, but one is to consolidate
Use predefined variables
Try to avoid repeating hard-coded names in the production rules. For example, the rule for
Add a
It's often useful (not least when testing makefiles!) to provide a
This also makes it less likely that you'll want to have the makefile itself as a dependency, which makes the set of rules cleaner. This would work even if the first line were omitted, unless there were actually a file named
Add
If you add
Consider isolating
For Windows, executables typically end in
Putting it all together
If we take all of these suggestio
makefile. Few people are any good at it, and it's a really fundamental tool. Even when nice tools such as CMake are used, it's very useful to understand how to write one from scratch.With that said, here are some things that may help you improve your
makefile:Prefer
Makefile to makefileThe names are equivalent, but since you're using GNU Make, you may as well follow its conventions, and one convention is to name it
Makefile instead of makefile. Either will work, but quoting from the GNU Make man page:We recommend 'Makefile' because it appears prominently near the beginning of a directory listing, right near other important files such as 'README'.
Use standard variable names
There are standard names for some of the variables you're using. For example, use
CFLAGS instead of COMPILE_FLAGS and CXXFLAGS which is the same thing, but for invocations of g++ (or more accurately invocations of $(CXX)). Similarly, use LDFLAGS instead of LINK_FLAGS.Add
INCLUDES to CFLAGSIt's good practice to use variables like
INCLUDES to keep things tidy, but it would be better if you added that to CFLAGS:CFLAGS += $(INCLUDES)The reason for doing that is in the next point.
Use the implicit rules
GNU Make already has an implicit rule for creating
.o files from .c files. That rule looks like this:%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) %%CODEBLOCK_1%%lt; -o $@The result of this is that if you have defined the flags correctly, you can omit an explicit rule and rely instead on the implicit rule. In this particular
Makefile, it means that you can entirely omit the rule for glad.o. As long as glad.c is in the current directory, and main.cpp is in the current directory, the built-in rules will understand how to create both glad.o using gcc and main.o using g++.To expand this a bit, here's what happens when I run
make -d to get it to emit more detailed debugging information:Considering target file 'main.exe'.
Considering target file 'main.o'.
Looking for an implicit rule for 'main.o'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.c'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.cc'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.C'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.cpp'.
Found an implicit rule for 'main.o'.
Considering target file 'main.cpp'.As you can see, after it has identified a needed target (
main.o) it starts looking for implicit rules to create that target. It finds one eventually because main.cpp exists. To see the full list in order on your machine, create an empty subdirectory, navigate to it and execute make -d foo.o. Since foo.o won't exist (it's an empty subdirectory) it will attempt to find an implicit rule that will allow it to create that file and with the -d option, it will tell you all of the things it's trying. On my machine, that generates 734 lines of output, so there's really quite a number of implicit rules. There are rules to create object files from C and C++, but also from Fortran, Pascal, Modula, assembly language, and for trying to check out a .o file from various version control systems. Add
LIBRARIES to LDFLAGSYour main rule (pardon the pun) does this:
$(CXX) $(LIBRARIES) -o main.exe $(objects) glad.o $(LINK_FLAGS)There are a number of changes I'd make to that line, but one is to consolidate
$(LIBRARIES) and $(LINK_FLAGS) into a single variable with a standard name, which is LDFLAGS.Use predefined variables
Try to avoid repeating hard-coded names in the production rules. For example, the rule for
main.exe could be much simplified to this:$(CXX) -o $@ $^ $(LDFLAGS)Add a
clean psuedotargetIt's often useful (not least when testing makefiles!) to provide a
clean psuedotarget to remove all of the files that were generated, providing a "clean slate" from which to start. It might be written like this:.PHONY : clean
clean :
-rm main.exe $(objects) glad.oThis also makes it less likely that you'll want to have the makefile itself as a dependency, which makes the set of rules cleaner. This would work even if the first line were omitted, unless there were actually a file named
clean. To tell the makefile that it's not a real file, we use the line .PHONY : clean. Add
glad.o to objectsIf you add
glad.o to the objects list, you can simplify the rules.Consider isolating
TARGETFor Windows, executables typically end in
.exe but not so for most other platforms. For that reason you could either have a specific variable for the executable extension or keep the target name in a variable:TARGET = main.exePutting it all together
If we take all of these suggestio
Code Snippets
CFLAGS += $(INCLUDES)%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@Considering target file 'main.exe'.
Considering target file 'main.o'.
Looking for an implicit rule for 'main.o'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.c'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.cc'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.C'.
Trying pattern rule with stem 'main'.
Trying implicit prerequisite 'main.cpp'.
Found an implicit rule for 'main.o'.
Considering target file 'main.cpp'.$(CXX) $(LIBRARIES) -o main.exe $(objects) glad.o $(LINK_FLAGS)$(CXX) -o $@ $^ $(LDFLAGS)Context
StackExchange Code Review Q#78855, answer score: 8
Revisions (0)
No revisions yet.