patternModerate
Makefile that places object files into an alternate directory (bin/)
Viewed 0 times
placesdirectorymakefilebinintofilesthatobjectalternate
Problem
I'm trying to learn how to use makefiles, and this is my attempt at making a makefile that compiles source files in a source directory (src/) into object files that are created in a bin directory.
This makefile works, I just want to make sure I'm doing everything correctly. Any changes you guys would suggest?
##########################################
# Editable options #
##########################################
# Compiler options
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
EXECUTABLE_NAME=testes
# Folders
SRC=src
BIN=bin
OBJ=$(BIN)/obj
# Files
SOURCE_FILES=\
main.cpp \
test.cpp
##########################################
# Don't touch anything below this #
##########################################
OBJECT_FILES=$(addprefix $(OBJ)/, $(SOURCE_FILES:.cpp=.o))
build: create_directories create_executable
@echo "Build successful!"
create_executable: create_objects
@$(CC) $(LDFLAGS) $(OBJECT_FILES) -o $(BIN)/$(EXECUTABLE_NAME)
@echo "Created executable."
create_objects: $(SOURCE_FILES)
@echo "Created objects."
create_directories:
@mkdir -p $(OBJ)
%.cpp:
@echo "Compiling "$@
@$(CC) $(LDFLAGS) -c $(SRC)/$@ -o $(OBJ)/$(patsubst %.cpp,%.o,$@)
clean:
@rm -r -f $(BIN)This makefile works, I just want to make sure I'm doing everything correctly. Any changes you guys would suggest?
Solution
You are not using the make system properly. As a result, it will always relink the executable, even when everything is already up to date. On the other hand, it might fail to recompile some source files into object files.
When you run
-
It will try to create the
-
It will try to create the prerequisites of
-
For
Having thus falsely satisfied the prerequisites for
The main remedy is to specify real targets and real dependencies, rather than phony labels like
Here is how I would write it. Other than the major problems cited above, I have also noted many minor issues in the comments.
When you run
make…-
It will try to create the
build target. No file named build exists, so…-
It will try to create the prerequisites of
build, namely create_directories and create_executable, neither of which are names of existing files.- In an attempt to create a file called
create_directories, it runsmkdir -p $(OBJ).
-
For
create_executable, it needs to rebuild create_objects.- For
create_objects, it just verifies that all of the source files are present.
- For any of the
$(SOURCE_FILES)that is missing, it "creates" it using the%.cpp:rule, which actually tries to compile the missing .cpp into a .o.
- Once all of the
$(SOURCE_FILES)are present, it echoes"Created objects.". That's a false claim due to the error above.
Having thus falsely satisfied the prerequisites for
create_executable, it proceeds to attempt to link the executable, even if any of the $(OBJECT_FILES) is missing.The main remedy is to specify real targets and real dependencies, rather than phony labels like
create_executable.Here is how I would write it. Other than the major problems cited above, I have also noted many minor issues in the comments.
#########################################################
# Replacing everything that you told me not to touch... #
#########################################################
EXECUTABLE_FILES = $(EXECUTABLE_NAME:%=$(BIN)/%)
OBJECT_FILES = $(SOURCE_FILES:%.cpp=$(OBJ)/%.o)
# ^^^ A more succinct expression for $(OBJECT_FILES), using
# http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
build: $(EXECUTABLE_FILES)
clean:
rm -r -f $(BIN)
@# ^^^ I don't recommend suppressing the echoing of the command using @
# http://www.gnu.org/software/make/manual/make.html#Phony-Targets
.PHONY: build clean
$(EXECUTABLE_FILES): $(OBJECT_FILES)
@$(CC) $(LDFLAGS) -o $@ $^
@# ^^^ http://www.gnu.org/software/make/manual/make.html#Automatic-Variables
@echo "Build successful!"
# http://www.gnu.org/software/make/manual/make.html#Static-Pattern
$(OBJECT_FILES): $(OBJ)/%.o: %.cpp
@echo Compiling %%CODEBLOCK_0%%lt;
@# ^^^ Your terminology is weird: you "compile a .cpp file" to create a .o file.
@mkdir -p $(@D)
@# ^^^ http://www.gnu.org/software/make/manual/make.html#index-_0024_0028_0040D_0029
@$(CC) $(CFLAGS) -o $@ %%CODEBLOCK_0%%lt;
@# ^^^ Use $(CFLAGS), not $(LDFLAGS), when compiling.Code Snippets
#########################################################
# Replacing everything that you told me not to touch... #
#########################################################
EXECUTABLE_FILES = $(EXECUTABLE_NAME:%=$(BIN)/%)
OBJECT_FILES = $(SOURCE_FILES:%.cpp=$(OBJ)/%.o)
# ^^^ A more succinct expression for $(OBJECT_FILES), using
# http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
build: $(EXECUTABLE_FILES)
clean:
rm -r -f $(BIN)
@# ^^^ I don't recommend suppressing the echoing of the command using @
# http://www.gnu.org/software/make/manual/make.html#Phony-Targets
.PHONY: build clean
$(EXECUTABLE_FILES): $(OBJECT_FILES)
@$(CC) $(LDFLAGS) -o $@ $^
@# ^^^ http://www.gnu.org/software/make/manual/make.html#Automatic-Variables
@echo "Build successful!"
# http://www.gnu.org/software/make/manual/make.html#Static-Pattern
$(OBJECT_FILES): $(OBJ)/%.o: %.cpp
@echo Compiling $<
@# ^^^ Your terminology is weird: you "compile a .cpp file" to create a .o file.
@mkdir -p $(@D)
@# ^^^ http://www.gnu.org/software/make/manual/make.html#index-_0024_0028_0040D_0029
@$(CC) $(CFLAGS) -o $@ $<
@# ^^^ Use $(CFLAGS), not $(LDFLAGS), when compiling.Context
StackExchange Code Review Q#74136, answer score: 16
Revisions (0)
No revisions yet.