I was looking for a solution on this site and also tried google for some time now, but somehow I can't get it to work.
My source should be in the src directory and the object files would be in the obj directory. Now I try to create a simple makefie but I either get an error that there is no rule, or I can't make it work to use the directories.
CC = /usr/bin/gcc
CXXFLAGS = -O2 -g -Wall -fmessage-length=0
SRC:= nohupshd.cpp \
task.cpp
OBJ:= nohupshd.o \
task.o
OBJDIR:= obj
SRCDIR:= src
DEP:= src/task.h
LIBS:=
TARGET:= nohupshd
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $(OBJ) $(LIBS)
clean:
rm -f $(OBJ) $(TARGET)
Variant 1:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
Variant 1a:
%.o: %.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
When I use this pattern I always get an error that there is no rule for nohupshd.o to build.
Variant 2:
$(OBJ) : $(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $(SRCDIR)/$< -o $(OBJDIR)/$#
$(CC) -c $(SRCDIR)/$< -o $(OBJDIR)/$#
When I use this variant, I can see that it tries to build, but I get errors saying that "file".o doesn't fit the target pattern.
Another issue is that "$<" doesn't give me the source name. According to several sites it should, but I can see in the output that there is nothing, so how can I fix this?
Update:
In the meantime my newest version looks like this:
$(OBJDIR)/$(OBJ) : $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -S $< -o $(OBJDIR)/`basename $# .o`.asm
$(CC) -c $< -o $#
This now manages to compile the first objectfile (nohupshd.o) but when make tries to do the second file it fails again saying: target 'task.o' doesn't match a pattern.
You actually have a couple if incorrect things above.
First you write My error was, that I was assuming that the pattern %.o matches ANY pattern ending with .o which it doesn't; that's not true. The pattern does match any string ending in .o. However, the pattern character % that is matched on the target side is replaced on the prerequisite side with the identical string. So if you have a target obj/task.o and it matches the pattern %.o then the stem (what the manual calls it) will be obj/task, and when the prerequisite is %.c that means that make will look for a prerequisite obj/task.c. Since there isn't one, and make doesn't know how to build one, that rule is discarded as not applying. When writing pattern rules you must write them so ONLY the identical parts of the names match the pattern character (%). ALL non-identical parts, including directories, must be specified explicitly.
Second, the rule $(OBJ) : $(SRC) is really not right. That line says that each object file depends on all the source files, so whenever any single source file changes all the object files will be recompiled. That's really not what you want (if that IS what you want you don't need make: you can just write a simple shell script). I don't know what you mean by since the rules is empty it invokes the pattern rule; you don't need this to invoke the pattern rule. The target depends on $(OBJ), and each object file depends on its source file (due to the pattern). You don't need this line at all.
Third, I don't know why you are trying to construct .asm files rather than just compiling directly from source to object, but if you really want them it would be cleaner and more "make-like" to create a separate pattern rule to build them: create a pattern rule $(OBJDIR)/%.o : $(OBJDIR)/%.asm and a rule $(OBJDIR)/%.asm : $(SRCDIR)/%.c. If you want the ASM files to be products of the build you should declare them as a prerequisite of all or similar, otherwise they'll be deleted as intermediate files.
Fourth, using things like basename is unnecessary. There are lots of automatic make variables that can be used instead. For example, $* expands to the stem, so you could write $(OBJDIR)/$*.asm. Of course if you make a separate pattern rule for ASM files you can just use $# or $< directly. There are various make functions that can also be used; see the manual.
Fifth, you define a variable containing a header file, DEP, but then never use it. Because it's not used, if you change that file nothing would be rebuilt. If you know that all the source files include every header you can use $(OBJ) : $(DEP) to define that; but it does mean (as in the second point above) that any change to any header causes all objects to recompile. You would be better off auto-generating the prerequisites; since you're using GCC this is quite simple.
Sixth, you're using C++ files (xxx.cpp) but you're using the C compiler. This will not work (the link line will fail: although the compiler can see you're compiling a C++ file and do the right thing, even if you call gcc, when you link a bunch of objects together it has no idea if those were C objects or C++ objects (or FORTRAN or whatever) so you MUST use the C++ front-end to link or it won't pull in the right C++ libraries). You should be using the make variable CXX to build C++ code, not CC, and setting it to g++ not gcc.
Seventh, you don't need .SUFFIXES: .c .o to use pattern rules. They are only needed for suffix rules, which you don't have here. You can keep the plain .SUFFIXES: though to disable built-in pattern matching which is a slight performance improvement.
Finally, you'll note you don't actually need the $(SRC) variable because make can infer it from the pattern rules. However, if you wanted to have your makefile less onerous to change, you could construct the contents of the OBJ variable from the SRC variable, like SRC = nohupshd.cpp task.cpp then OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(SRC)).
So, all-in, this is how I would recommend you write your makefile (I don't include the auto-generated dependencies here though):
.SUFFIXES:
CXX := g++
CXXFLAGS := -O2 -g -Wall -fmessage-length=0
OBJDIR := obj
SRCDIR := src
TARGET := nohupshd
SRC := nohupshd.cpp task.cpp
DEP := src/task.h
LIBS :=
# ----
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRC))
ASM := $(patsubst %.cpp,$(OBJDIR)/%.asm,$(SRC))
.PHONY: all clean
all: $(TARGET) $(ASM)
$(TARGET): $(OBJ)
$(CXX) -o $# $^ $(LIBS)
clean:
rm -f $(OBJDIR)/* $(TARGET)
$(OBJDIR)/%.o : $(SRCDIR)/%.asm
$(CXX) $(CXXFLAGS) -c -x assembler-with-cpp $< -o $#
$(OBJDIR)/%.asm : $(SRCDIR)/%.cpp
$(CXX) $(CPPFLAGS) -S $< -o $#
Don't repeat the directory names in the compiler line. $< and $# already have the directory names.
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
$(CC) -S $< -o $#
$(CC) -c $< -o $#
So finally I found the answer on how to write this makefile, for an exaplanation of my mistakes look at the posting I marked as correct answer:
The resulting makefile looks like this, and for completeness I post it here including dependencies for header files (remove the ASM parts if you don't need 'em):
.SUFFIXES:
.SUFFIXES: .o .cpp
.SUFFIXES: .o .d
CC := g++
LNK:= ar
CXXFLAGS = -O2 -g -Wall -fmessage-length=0
OBJDIR:= obj
SRCDIR:= src
HDIR:= include
INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
CPP_FILES := propertyfile/propertyfile.cpp \
propertyfile/propertyitem.cpp \
propertyfile/propertyfactory.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
ASM := $(patsubst %.cpp, $(OBJDIR)/$*.asm, $(CPP_FILES))
LIBS:=
TARGET:= libsupport.a
all: $(TARGET)
$(TARGET): $(OBJ)
#echo "Linking..."
#$(LNK) rvs $(TARGET) $(OBJ)
#cp $(TARGET) ../lib
#cp -r include ..
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -S $< -o $(OBJDIR)/$*.asm $(INCLUDE_PATHS)
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
I hope this helps other user. All examples that I found were either extremly simple and listed multiple files individually and not part of a rule, but didn't really explain how it works, or were so complicated that I couldn't find out how it can help me.
Related
I am having an issue with this makefile. I cannot figure out how to build the object files from their coresponding sources. Every obj gets built with the main source, instead of its one.
TARGET = af_optional
SOURCES := $(wildcard src/*.cpp)
OBJECTS := $(patsubst src/%.cpp,obj/%.o,$(SOURCES))
DEPENDS := $(patsubst src/%.cpp,obj/%.d,$(SOURCES))
CXXFLAGS = -g -I.
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: bin/$(TARGET)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(TARGET)
# Linking the executable from the object files
bin/$(TARGET): $(OBJECTS)
#echo "target : $(TARGET)"
#echo "sources: $(SOURCES)"
#echo "objects: $(OBJECTS)"
#echo "depends: $(DEPENDS)"
#mkdir -p bin
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
-include $(DEPENDS)
$(OBJECTS): $(SOURCES) makefile
#mkdir -p obj
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
I have written this makefile while researching a while ago, but I broke something after I had got it working and I haven't noticed until now, since all the project's I've had to work with since were single source.
This rule is wrong:
$(OBJECTS): $(SOURCES) makefile
What does this expand to? If you have sources src/foo.cpp, src/bar.cpp, and src/baz.cpp then it will be this:
obj/foo.o obj/bar.o obj/baz.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
This is an extremely common problem: people seem to have this idea that make will somehow massage all these targets and prerequisites to match them up somehow so that each object file depends only on the corresponding source file.
But, make does NOT do that. The above rule is exactly identical to writing all these rules:
obj/foo.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
obj/bar.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
obj/baz.o : src/foo.cpp src/bar.cpp src/baz.cpp makefile
Now maybe you can see why you see the behavior you do: the first prerequisite for every target is exactly the same file src/foo.cpp so when you use the $< automatic variable, that's the one you always get.
You have to write ONE rule that builds ONE object, then let make figure out how to apply that rule for all the appropriate objects.
So, to build one object file from one source file you can use a pattern rule like this:
obj/%.o : src/%.cpp makefile
#mkdir -p obj
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
That's all you need.
I'm new to Makefiles. I've been making a simple C++ library using WiringPi for my RaspberyPi related projects. So far its very simple with things like an LED class, DuelLED, Motor, Button, etc (both .h and .cpp). I was able to piece together a Makefile but I am getting an error "No rule to make target RumPi.o needed by RumPi". (Note: The name of my library is called RumPi)
Thanks for all the help, Here is the final fix:
CXX = g++
CXXFLAGS = -std=c++11
LDLIBS = -lwiringPi
HEADERS = Components/Headers/RumPi.h ./Common.h Components/Headers/Component.h Components/Headers/Vehicle.h Components/Headers/Motor.h Components/Headers/Receiver.h Components/Headers/DualLED.h Components/Headers/LED.h Components/Headers/RGBLED.h Components/Headers/Relay.h
OBJECTS = RumPi.o Vehicle.o Motor.o Receiver.o DualLED.o LED.o RGBLED.o Relay.o
default: RumPi
RumPi: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $#
%.o: Components/Implementations/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
$(OBJECTS): $(HEADERS)
clean:
-rm -f $(OBJECTS)
-rm -f RumPi
That message means make can't figure out how to build that target (RumPi.o). Do you have a Components/Implementations/RumPi.cpp file? Do all the header files you've listed in the $(HEADERS) variable actually exist? If either of those is not true, then your pattern rule will not match. If your pattern rule doesn't match (and the default rule doesn't match) then make can't figure out how to build the object file.
If you want full details you can run make -d and examine the debug output. You might want to redirect it to a file so you can look at it with less or a text editor since there's a lot of output.
By the way, you should not add the -lwiringPi option to your compile line. Libraries are only used at link time, not compile time.
ETA
Something else you should consider is rewriting your pattern rule so that only the source file is listed as a prerequisite and moving the headers to a separate line:
%.o: Components/Implementations/%.cpp
gcc -c $< -o $# -lwiringPi
$(OBJECTS): $(HEADERS)
The advantage to this is you'll get a clearer error message if one of the headers is not found. When you use a pattern rule, make will try to match all the patterns it can and if none match it tells you it doesn't know how to build the target. Since there are usually many different ways to build a target, make doesn't show an error for every one that doesn't match.
But if you declare a direct explicit prerequisite relationship between two files, rather than using a pattern that may or may not match, then if there is a missing file make will tell you directly.
ETA2
In your original makefile you had a rule like this:
RumPi: $(OBJECTS)
gcc $(OBJECTS) -o $# -lwiringPi
but then later you removed it. Why did you take this out? You need this rule to tell make how to link your executable file RumPi.
Also, you shouldn't be using gcc as the compiler/linker for C++ code; gcc is for C, not C++. You should use g++ for C++ code. And it's best to contain this information in variables so it's easy to find and modify (even from the command line if you like). The standard variable names for the C++ compiler is CXX etc.
Your makefile should look something like this:
CXX = g++
CXXFLAGS = -std=c++11
LDLIBS = -lwiringPi
HEADERS = Components/Headers/RumPi.h ./Common.h Components/Headers/Component.h \
Components/Headers/Vehicle.h Components/Headers/Motor.h Components/Headers/Receiver.h \
Components/Headers/DualLED.h Components/Headers/LED.h Components/Headers/RGBLED.h \
Components/Headers/Relay.h
OBJECTS = RumPi.o Vehicle.o Motor.o Receiver.o DualLED.o LED.o RGBLED.o Relay.o
default: RumPi
RumPi: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $#
%.o: Components/Implementations/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
$(OBJECTS): $(HEADERS)
clean:
-rm -f $(OBJECTS)
-rm -f RumPi
I'm brushing up on C++ by completing many small programs, each contained in a single cpp file. I also want to learn a little bit more about Makefiles, and decided to write a Makefile that will compile all of my little programs and produce an executable per program. With my current Makefile, I have to:
Append the name to the end of "BINARIES"
Copy the repeated target and replace the target name with the binary name
How can I edit this Makefile to be even more generic, so that I can simply append the name of my new program to the end of "BINARIES" and not have to continue to copy and paste the repeated targets?
BIN=./bin/
SOURCE=./src/
CXX=g++
CXXFLAGS=-g -c -Wall
BINARIES=sums-in-loop sum-in-loop sum-of-two
RM=rm -f
all: sums-in-loop sum-in-loop sum-of-two
sums-in-loop:
$(CXX) $(CXXFLAGS) $(SOURCE)$#.cpp -o $(BIN)$#
sum-in-loop:
$(CXX) $(CXXFLAGS) $(SOURCE)$#.cpp -o $(BIN)$#
sum-of-two:
$(CXX) $(CXXFLAGS) $(SOURCE)$#.cpp -o $(BIN)$#
clean:
$(RM) $(BIN)*
The usual way is to use pattern rules:
BIN=bin
SOURCE=src
CXX=g++
CXXFLAGS=-g -Wall
BINARIES=sums-in-loop sum-in-loop sum-of-two
RM=rm -f
all: $(addprefix $(BIN)/,$(BINARIES))
$(BIN)/%: $(SOURCE)/%.cpp
$(CXX) $(CXXFLAGS) $< -o $#
clean:
$(RM) $(BIN)/*
With loops in Makefile, you can do something like :
$(foreach bin,$(BINARIES),$(CXX) $(CXXFLAGS) $(SOURCE)$(dir).cpp -o $(BIN)$dir;)
You can find some info --> http://www.gnu.org/software/make/manual/make.html#Foreach-Function
I am trying to create a makefile for my project, but i seem to run into some errors, as I am testing new things. My file structure is as such:
~/main #root project folder
~/main/include #header files (mostly class headers)
~/main/src #source files
~/main/src/obj #object files
Makefile
(Makefile is in the root project folder)
Makefile:
CC=g++
IDIR=include
SDIR=src
ODIR=src/obj
DEPS=$(IDIR)/%.h
OBJS=$(ODIR)/%.o
SRCS=$(SDIR)/%.cpp
CFLAGS=-Wall -std=c++11 -I$(IDIR)
$(OBJS): $(SRCS) $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
all: $(OBJS)
gcc -o run $^ $(CFLAGS)
.PHONY: clean
clean:
rm -f $(OBJS)
For testing purposes I have a single main.cpp in src folder and a random header file in include folder. The error I am getting when running the simple make command is the following:
make: *** No rule to make target `src/obj/%.o', needed by `all'. Stop.
EDIT : With the help of the guys below i came up with the solution
CC=g++
IDIR=include
SDIR=src
ODIR=src/obj
CFLAGS=-Wall -std=c++11 -I$(IDIR)
_DEPS = yo.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
_SRC = main.cpp
SRC = $(patsubst %,$(SDIR)/%,$(_SRC))
$(ODIR)/%.o: $(SRC) $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
all: $(OBJ)
$(CC) -o run $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(OBJS)
There is a difference in using % in your two cases. When you write:
$(ODIR)/%.o : $(SDIR)/%.cpp $(IDIR)/%.h
that will do pattern substitution, and create a bunch of rules like:
$(ODIR)/foo.o : $(SDIR)/foo.cpp $(SDIR)/foo.h
So it's fine there, although you should use the % explicitly there so it's clear to see what the rule is doing.
But when you use it here:
all : $(ODIR)/%.o
That is literally looking for the target $(ODIR)/%.o for which you don't have a rule. There's no substitution. And you don't have a rule to make that target - hence the error. What you meant to do was have all depend on all the actual objects, for which you'll want to use the wildcard function:
SOURCES = $(wildcard $(SDIR)/*.cpp)
OBJECTS = $(SOURCES:$(SDIR)/%.cpp=$(ODIR)/%.o)
all : $(OBJECTS)
gcc -o run $^ $(CFLAGS)
When you use
OBJS=$(ODIR)/%.o
The %.o part does not expand to anything meaningful. It just remains as the literal value %.o. Same problem exists for DEPS and SRCS as well.
You need to use the wildcard and patsub functions. Instead of
DEPS=$(IDIR)/%.h
OBJS=$(ODIR)/%.o
SRCS=$(SDIR)/%.cpp
use
DEPS=$(wildcard $(IDIR)/*.h)
SRCS=$(wildcard $(SDIR)/*.cpp)
OBJS=$(patsub %.cpp,%.o,$(SRCS))
My Makefile:
compiler=g++
cflags=-g -Wall -I.
src=$(shell find . -name *.cc) #find all .cc files, with path name
srcBaseName=$(shell basename -a $(src)) # extract base names by stripping off the path
header=$(shell find . -name *.h) # all header files
obj=$(patsubst %.cc, %.o, $(srcBaseName)) # Problematic line
bin=bin/myProgram
all: $(bin)
$(bin): $(obj)
$(compiler) $^ -o $#
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#
clean:
rm $(obj) $(bin)
results in the following error:
make: *** No rule to make target 'SomeObjectFile.o', needed by
'bin/myProgram'. Stop.
The problematic line:
obj=$(patsubst %.cc, %.o, $(srcBaseName))
If I change $(srcBaseName) to $(src), then everything builds fine. But in that case the .o files are going to be scattered in the corresponding folders with .cc files, which I don't want.
I'd like to have a dedicated (obj/) folder to store all the .o files.
How can I do it?
First try:
obj=$(patsubst %.cc, %.o, obj/$(srcBaseName))
Second try:
obj=$(patsubst %.cc, %.o, obj\/$(srcBaseName))
Why did they NOT work?
/**********************Edited on 16th Feb 2015**********************/
Based on the suggestions in the answers, I updated my Makefile to be this:
compiler=g++
# source compilation flags
cflag=-g -Wall -std=gnu++0x -I./header/
# source link flags
lflag=
# lib used by proj
lib=
tflag=-g -Wall -std=gnu++0x
# test link flags
tlflag=
# test libs
testLib=lib/libgtest.a
# source code
src=$(shell find "./src" -name "*.cc")
srcBaseName=$(shell basename -a $(src))
obj=$(addprefix obj/, $(patsubst %.cc, %.o, $(srcBaseName)))
vpath %.cc $(dir $(src))
# header files
header=$(shell find "./header" -name "*.h")
# test files
testSrc=$(shell find "./test" -name "*.cc")
testSrcBase=$(shell basename -a $(testSrc))
testObj=$(addprefix obj/, $(patsubst %.cc, %.o, $(testSrcBase)))
vpath %.cc $(dir $(testSrc))
# binary files
bin=bin/Driver
testBin=bin/Test
all: prog test
prog: $(bin)
$(bin): $(obj)
$(compiler) $(lflag) $^ $(lib) -o $#
#$(obj): $(src) $(header)
obj/%.o: %.cc $(header)
$(compiler) $(cflag) -c $< -o $#
test: $(testBin)
$(testBin): $(testObj)
$(compiler) $(tlflag) $^ $(testLib) -o $#
obj/%.o: %.cc
$(compiler) $(tflag) -c $< -o $#
clean:
rm $(obj) $(bin) $(testObj) $(testBin)
Here's the intention behind the make:
make prog:
make should find all the source files(.cc) under ./src directory, and produce an .o file with the same file name in the ./obj directory, insensitive to the levels of subdirectories so that I can freely add new cc files without the need to update the Makefile. Each .o file depends on the corresponding(just the one with the same name, not all) .cc file and ALL headers(make does not automatically know what header files a cc file includes without parsing the file; if you have a clever method to achieve this, do let me know!). For example, ./src/subdirectory1/sample1.cc should produce ./obj/sample1.o and ./obj/sample1.o depends on ./src/subdirectory1/sample1.cc + ./header/sample1.h + ./header/sample2.h + ...
make test:
it should do similar things to the test source files in the ./test folder, with the exception that there's no header involved. In case this detail helps, I'm using Google Test.
However, my Makefile is not quite working in the intended way because it has the following problems:
1, if I run make test, the recipe $(compiler) $(tflag) -c $< -o $# is not executed(tflag means 'test compilation flag', which doesn't have the -I./header/ part; cflag means 'source code compilation flag', it has the -I./header/ part). Instead, the recipe in phony prog $(compiler) $(cflag) -c $< -o $# is executed. This observation comes from the output in which '-I./header/' shows up. I guess this is because the cflag pattern rule in phony prog overrides the tflag one in phony test? I vaguely remember make picks the best matching pattern rule - the two are essentially the same(I have the intention that the pattern rule under a specific phony should get executed when that phony is executed, which doesn't seem to be feasible?), so make will always pick the first one. This conclusion is verified by swapping the order of two pattern rules in the Makefile, and this time the tflag rule always gets picked. So a natural question to ask is, how do I execute the pattern rule under a specific phony when that phone is executed?
2, Assuming it's not feasible to do what I wanted to do in point 1, I start to think about alternatives. Can I do something like: #$(obj): $(src) $(header) so that I can get rid of the pattern rule to work around the way make picks the pattern rule. However, this is obviously not correct as it's saying, each .o file in $(obj) depends on ALL src files and ALL header files. Is it at all a right direction?
Thanks a lot, looking forward to hearing from you.
3 key questions have been highlighted in bold and italicized.
Your problem is this line:
%.o: %.cc
That line tells make that to create some/path/file.o you will use some/path/file.cc.
If you want all .o files in one single directory, but still want to have the source files in different directories you will need one such rule for each source directory. Or, you could add all directories to the VPATH variable, something like:
VPATH=$(dir $(src))
Or maybe better:
VPATH=$(dir $(SRC))
Usuing capital letters for your variables in a Makefile is a good way to avoid confusing them with function names.
I will do my best to also answer your new questions:
1) As you are using the gnu compilers it is possible to automatic find the dependencies of .h files in .c files. You could add rules like this to your Makefile:
# Where .d-files will be created for dependencies
DEP=dep
# Dependency files
DEPS = $(srcBaseName:%.cc=$(DEP)/%.d)
# Before compiling object file, also make sure dependency file is
# created to test the need for future recompilation
obj/%.o: %.cc $(DEP)/%.d
$(compiler) $(cflags) -c $< -o $#
# Use gnu compiler to create dependency files
$(DEPS): $(DEP)/%.d: %.cc $(filter-out $(wildcard $(DEP)), $(DEP))
$(compiler) -MM $(cflags) -MT $# $< > $#
# Create directories which might be needed
$(DEP) $(OBJ) $(BIN) $(MO):
mkdir -p $#
# Let Makefile use any generated dependency files
ifneq ($(wildcard $(DEPS)),)
include $(wildcard $(DEPS))
endif
Please note that in the compilation rule I replaced $^ with $< as we don't want to compile the dependency file.
2) I would avoid two pattern rules looking the same. Instead I would change cflag depending on the target, something like this:
ifeq ($(MAKECMDGOALS),debug)
CFLAGS += -g
else
CFLAGS += -O2
endif
I hope these answers will guide you in the right direction
The main problem is that make cannot use the pattern rule
%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#
to build obj since it cannot find common stems between your .o files and your .cc files to match %. An easy way to fix this is to tell make where those files are through the vpath directive, e.g. by adding
vpath %.cc $(dir $(src))
vpath %.o obj/ #not a good idea for .o files though, see below
and changing the pattern rule (needed by the use of vpath %.o) into
%.o: %.cc
$(compiler) $(cflags) -c $^ -o obj/$#
EDIT: MadScientist has made a very good point that I completely missed, based on which, a better solution that does not involve vpath %.o is
vpath %.cc $(dir $(src))
obj=$(addprefix obj/,$(patsubst %.cc, %.o, $(srcBaseName)))
obj/%.o: %.cc
$(compiler) $(cflags) -c $^ -o $#