This is my make file.
all: observer
observer: main.o weather_center.o display.o subject.o observer.o
g++ main.o weather_center.o display.o subject.o observer.o -o observer
main.o: main.cpp
g++ -c main.cpp
weather_center.o: weather_center.cpp
g++ -c weather_center.cpp
display.o: display.cpp
g++ -c display.cpp
subject.o: subject.cpp
g++ -c subject.cpp
observer.o: observer.cpp
g++ -c observer.cpp
clean:
rm -f *o observer
Here I'm trying to use
clean:
rm -f *o observer
To clean up the temporary *.o files. But program compiles and generate the target assembly, but doesn't delete the *.o files. Not showing any errors also.
I tried rm -f *o observer in terminal. It works fine.
I have used Tab for indent
there are no files start with clean or rm in the directory.
tried $(RM) instead of rm. but no lucky
I found the issue. Have to specify clean as a target of all otherwise it wont call. generally like this.
all: [your executive names] clean
In above case
all: observer clean
Here is the full make file of above case
all: observer clean
observer: main.o weather_center.o display.o subject.o observer.o
g++ main.o weather_center.o display.o subject.o observer.o -o observer
main.o: main.cpp
g++ -c main.cpp
weather_center.o: weather_center.cpp
g++ -c weather_center.cpp
display.o: display.cpp
g++ -c display.cpp
subject.o: subject.cpp
g++ -c subject.cpp
observer.o: observer.cpp
g++ -c observer.cpp
clean:
rm -f *o observer
As others have mentioned, this is likely an indentation issue. I copied your makefile exactly, touched some dummy .o files and ran it:
$ touch main.o weather_center.o display.o subject.o observer.o
$ make clean
Makefile:4: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
$
After fixing indentation, it seems to work just fine for me:
$ touch main.o weather_center.o display.o subject.o observer.o
$ ls *.o
display.o main.o observer.o subject.o weather_center.o
$ make clean
rm -f *o observer
$ ls *.o
ls: cannot access *.o: No such file or directory
$
The specific indentation fixes I made were:
target lines should not have any leading whitespace at all
recipe lines must start with exactly one tab and no other whitespace
E.g:
clean:
rm -f *o observer
I have saved the fixed version here, because stackoverflow messes with tabs/whitespace. Make sure to copy from the RAW Paste Data.
Having read the question, comments and your self-answer in a little more detail, I think there is possibly some explaining to do about conventional usage of make.
You may call the make executable with a list of targets to build, or no targets at all.
In the case that targets are specified, then make will attempt to build/rebuild those targets. For instance, with the corrected Makefile, make observer would build the observer target (observer executable), make main.o would simply compile main.cpp to produce main.o, and make clean would invoke the clean rule to delete the listed files.
On the other hand, if you invoke make with no targets, then make will simply use the first target defined in the Makefile as the target that it builds. The convention is that this target is called all, but it can be called whatever you like. So in the case of the corrected makefile, invoking make without explicitly passing any targets should result in all and its dependency observer being rebuilt. I suspect this is where the confusion has arisen - invoking make for this makefile with no targets explicitly mentioned should not result in invocation of the clean target. This is the expected make behavior.
all: observer clean #1
observer: main.o weather_center.o display.o subject.o observer.o
g++ main.o weather_center.o display.o subject.o observer.o -o observer
main.o: main.cpp
g++ -c main.cpp
weather_center.o: weather_center.cpp
g++ -c weather_center.cpp
display.o: display.cpp
g++ -c display.cpp
subject.o: subject.cpp
g++ -c subject.cpp
observer.o: observer.cpp
g++ -c observer.cpp
clean:
rm -f *.o #2
1 fix all: observer to [all: observer clean]
2 fix rm -f *o observer to [rm -f *.o]
Related
I'm not sure if there is some built-in variable or rule that I don't know about, or if something is wrong with make, or if I'm just crazy.
For one of my projects, I have a makefile as follows:
CC=g++
CFLAGS=-O3 `libpng-config --cflags`
LFLAGS=-lm `libpng-config --ldflags`
OBJS=basic_render.o render.o mandel.o
BINS=basic_render
.PHONY: all clean
all: $(BINS)
clean:
rm -f $(BINS) $(OBJS)
%.o: %.cpp
$(CC) $(CFLAGS) -c -o $# $<
%: $(OBJS)
$(CC) $(LFLAGS) -o $# $(OBJS)
When building, I want to simply be able to run
make clean
make
to build everything in the BINS list.
This works all right at first, but for some reason, the behaviour changes after I edit a source file.
Before editing source file:
$ make clean
rm -f basic_render basic_render.o render.o mandel.o
$ make
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o basic_render basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o
I can do this over and over again and it works just fine. After I make changes to basic_render.cpp (literally just changing a couple of constants), it suddenly changes to this:
$ make clean
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o makefile basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o
makefile:1: warning: NUL character seen; rest of line ignored
makefile:1: *** missing separator. Stop.
not only did make clean just try to compile the program, it compiled basic_render with the output set in Makefile, overwriting the Makefile itself.
After editing basic_render.cpp, I looked in Makefile, and it hadn't changed, so it's not like my editor is changing the makefile or something.
So, what am I doing wrong here?
Here is an MCVE of your problem:
$ ls -R
.:
bar.c main.c Makefile
$ cat main.c
extern int bar(void);
int main(void)
{
bar();
return 0;
}
$ cat bar.c
int bar(void)
{
return 42;
}
$ cat Makefile
OBJS := main.o bar.o
BINS := prog
.PHONY: all clean
all: $(BINS)
%: $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BINS)
Make first time:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog main.o bar.o
rm bar.o main.o
Pause to notice the undesired consequence of 10.4 Chains of Implicit Rules:
rm bar.o main.o
All of the object files are auto-deleted after the program is linked, defeating the purpose
of Make. The implicit rules to blame for that are our own implicit rule:
%: $(OBJS)
$(CC) -o $# $(OBJS)
plus the built-in implicit rule1:
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
which together make an implicit rule chain that results in all of the object files
becoming intermediate files.
Moving on, let's update a source file:
$ touch main.c
and make a second time:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o Makefile main.o bar.o
rm bar.o main.o
Makefile:1: warning: NUL character seen; rest of line ignored
Makefile:1: *** missing separator. Stop.
There is our Makefile clobbered by the linkage:
cc -o Makefile main.o bar.o
This snafu is explained in the manual 3.5 How Makefiles Are Remade:
Sometimes makefiles can be remade from other files, such as RCS or SCCS files.
If a makefile can be remade from other files, you probably want make to get an
up-to-date version of the makefile to read in.
To this end, after reading in all makefiles, make will consider each as a goal
target and attempt to update it. If a makefile has a rule which says how to update it
(found either in that very makefile or in another one) or if an implicit rule applies to it
(see Using Implicit Rules), it will be updated if necessary.
After all makefiles have been checked, if any have actually been changed,
make starts with a clean slate and reads all the makefiles over again.
(It will also attempt to update each of them over again, but normally this will
not change them again, since they are already up to date.)
(Emphasis mine). Is there an implicit rule that is applicable to Makefile considered
as a target? Yes, it is:
%: $(OBJS)
$(CC) -o $# $(OBJS)
since the target pattern % matches any file whatever. If we restore our clobbered
Makefile and try the same experiment thing again, this time with debugging:
make -d >debug.log 2>&1
the output will show us:
...
Reading makefiles...
Reading makefile 'Makefile'...
Updating makefiles....
Considering target file 'Makefile'.
Looking for an implicit rule for 'Makefile'.
...
...
Found an implicit rule for 'Makefile'.
...
...
Finished prerequisites of target file 'Makefile'.
Prerequisite 'main.o' is newer than target 'Makefile'.
Prerequisite 'bar.o' is newer than target 'Makefile'.
Must remake target 'Makefile'.
cc -o Makefile main.o bar.o
...
We can avoid this upshot, and also the self-defeating auto-deletion of
our object files, by not using a match-anything implicit rule to perform our
linkage. The customary thing is to make a program from its object files by
an explicit rule, e.g.
Makefile (2)
OBJS := main.o bar.o
BIN := prog
.PHONY: all clean
all: $(BIN)
$(BIN): $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
It appears that you cherish the option to have BINS be a list of multiple
programs:
I want to simply be able to run
make clean
make
to build everything in the BINS list.
But consider that with:
BINS := prog1 prog2
and the recipe:
%: $(OBJS)
$(CC) $(LFLAGS) -o $# $(OBJS)
as your way of making everything in the BINS list, you will just make the same program
twice, with two different names. And even if you wanted to do this, the way to do
it would be:
Makefile (3)
OBJS := main.o bar.o
BINS := prog1 prog2
.PHONY: all clean
all: $(BINS)
$(BINS): $(OBJS)
$(CC) -o $# $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
which runs like:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog1 main.o bar.o
cc -o prog2 main.o bar.o
[1] You can get GNU Make to show you all its builtin-rules, and all the rest
of its rules for a particular build, with make --print-data-base ...
I would suggest that the % target is somehow matching the makefile file and therefore using it as the target(1).
My advice would be to change that line to:
$(BINS): $(OBJS)
and that should hopefully prevent make from thinking it should create a new makefile when the objects change.
(1) Apart from the explicit rules you provide, make also has quite a lot of implicit rules.
If even one of those rules decides that it depends on makefile (this is often configured since a change to the makefile usually means that a full rebuild should be done, as the rules may well have changed), then the % target may then be used for the makefile.
And, since the objects have changed, the makefile that depends on them will be rebuilt.
I personally have never seen a % target since I believe that means the rule may match any target, including source files which you probably don't want overwritten.
If you're interested in seeing all those implicit rules, make -d should give you quite a bit of information such as the rules used and conditions checked for whether files need to be rebuilt - just be prepared to wade through a lot of output.
I recently started a small project in C++. I created a simply Makefile:
output: main.o google_api.o
g++ main.o google_api.o -o output
rm *.o
clear
./output
main.o: main.cpp
g++ -c main.cpp
test.o: google_api.cpp google_api.h
g++ -c google_api.cpp
And when I compile my code I get the next error -
non-aggregate type 'vector' cannot be initialized
with an initializer list
I am check for this issue and find that I need to add -std=c++11 support to my makefile to fix the problem. I add this command to the code:
g++ -std=c++11 main.o google_api.o -o output
But this is not make any change. I would love if someone can help me to fix this problem. Thanks
change this:
main.o: main.cpp
g++ -c main.cpp
to:
main.o: main.cpp
g++ -std=c++11 -c main.cpp
You may as well use something like this as basis for your Makefile:
CXX=g++
CXXFLAGS=-g -Wall -MMD -std=c++11
LDLIBS=-lm # list libs here
output: main.o google_api.o
clean:
$(RM) *.o *.d output
-include $(wildcard *.d)
There are also similar questions on stackoverflow: Makefile c++11 support
I have a Makefile that works for how I'm using it, but will anyone tell me if what I'm doing is good practice? Or if there is a better, cleaner or more efficient way to achieve the goal I am reaching?
Here is my Makefile Code.
# Object files to either reference or create
OBJECTS = Proj2.o Blackjack.o Deck.o Card.o Hand.o Player.o
# The executable file that will be created
EXEC = Proj2.out
# The c++ flags to use for compilation
CXXFLAGS = -Wall
# The c++ compiler to use for compilation
CXX = g++
# This section is called on 'make'
# Will call compile, and then call clean
all: compile clean
# Perform action on all object files (May or may not exist)
# The makefile will implicitly compile all .o files needed
# Will also compile them into the EXEC file listed
compile: $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $(EXEC) $(OBJECTS)
# This section is called after compilation is completed
# This will clean all existing .o files listed in the directory
clean:
rm -f *.o
Here is the terminal output when I call make.
g++ -Wall -c -o Proj2.o Proj2.cpp
g++ -Wall -c -o Blackjack.o Blackjack.cpp
g++ -Wall -c -o Deck.o Deck.cpp
g++ -Wall -c -o Card.o Card.cpp
g++ -Wall -c -o Hand.o Hand.cpp
g++ -Wall -c -o Player.o Player.cpp
g++ -Wall -o Proj2.out Proj2.o Blackjack.o Deck.o Card.o Hand.o Player.o
rm -f *.o
Is it good practice to use a Makefile like this? Specifically, am I doing the cleaning part of my Makefile correctly?
You should not make all depend on clean at all. By doing this you are ensuring that every time you run make, you have to recompile everything. If you want to do that then using make is itself useless: just write a shell script that compiles and links your code.
The clean target should be a separate target and if you want to clean your workspace you run make clean explicitly.
The other problem with your makefile is that the link rule lists compile as the target, but it builds $(EXE). It's almost never a good idea to have a rule create a file which is not exactly the target you told make it would build. To ensure this, always use $# as the target to generate. Rewrite it like this:
compile: $(EXE)
$(EXE): $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $^
I am attempting to run my make file however i am getting the following two errors:
make: c: command not found
and
make: o: command not found
I am attempting to do this inside of cygwin. I have g++ and make installed on it, however when I run the make file I receive these errors.
Any ideas?
The makefile:
all: MergeSort clean
MergeSort: main.o MergeSort.o
$g++ -o MergeSort main.o MergeSort.o
main.o: main.cpp MergeSort.h
$g++ -c main.cpp
MergeSort.o: MergeSort.cpp MergeSort.h
$g++ -c MergeSort.cpp
clean:
rm -rf *o
cleanall:
rm -rf *o *exe
You need to remove the $ from the $g++ lines. It's trying to expand some variable that doesn't exist, and is swallowing up the "$g++ -" from your commands.
The syntax for using a variable is:
$(CXX) -c main.cpp
In this case, CXX is the path to the C++ compiler, which is defined for you. You can change it by adding the following line to your makefile:
CXX = g++
If you are trying to avoid echoing back the command make is running, use # instead of $.
$g++ is not defined in that makefile, so the command becomes
-o MergeSort main.o MergeSort.o
and
-c main.cpp
Either drop the $ from $g++ and use g++, or define the variable in your makefile.
CXX = g++
all: MergeSort clean
MergeSort: main.o MergeSort.o
$CXX -o MergeSort main.o MergeSort.o
main.o: main.cpp MergeSort.h
$CXX -c main.cpp
MergeSort.o: MergeSort.cpp MergeSort.h
$CXX -c MergeSort.cpp
clean:
rm -rf *o
cleanall:
rm -rf *o *exe
This is my current makefile.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cpp object.cpp foo.cpp
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cpp.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.d: %.cpp
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
It works perfectly with one exception. If the directory is already clean (no *.d, *.o) and I run 'make clean', it re-creates the dependencies, then immediately deletes them:
[user#server proj]$ make
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
g++ -Wall -O3 -c main.cpp -o main.o
g++ -Wall -O3 -c object.cpp -o object.o
g++ -Wall -O3 -c foo.cpp -o foo.o
g++ -Wall -O3 main.o object.o foo.o -o testcpp
[user#server proj]$ make clean
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$ make clean
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$
I don't understand why the second 'make clean' would re-generate the dependency files. How can I avoid this? This isn't a big deal for this contrived example, but for a large project, it can be quite time-consuming.
Thanks.
It's because the .d files are being -included unconditionally. As far as make knows, they could add dependencies or commands to the clean target. All included files are built first for this reason, otherwise you might get an incorrect or failed build. To disable this, you want to conditionally include the dependency files:
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
An alternative solution is to generate the dependency files using touch and have them replaced by actual data as a side-effect of compilation. This is how automake does its dependency tracking, as it makes one-time builds faster. Look into the -MD and -MMD options to gcc if you want to go this route. Use a pattern rule like:
%.d:
#touch $#
To initially create the dependency files.
If you want to skip the include for multiple targets, you can use the filter function.
MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc
# Include only if the goal needs it
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
-include $(DEPS)
endif
It wants to regenerate the dependency files because it always tries to regenerate all of the makefiles, including -include'd makefiles, before doing anything else. (Well, actually, for me it doesn't do that - I have GNU Make 3.81 - so maybe it's a bug in your version that was fixed, or an optimization that mine has and yours doesn't. But anyway.)
The easiest way around this is to write your rules so they generate the .d files as a side effect of regular compilation, rather than giving explicit rules to generate them. That way, when they're not there, Make doesn't know how to generate them so it doesn't try (in a clean tree, the .cpp.o rules are enough, you don't need the header file dependencies). Look at an Automake-generated makefile -- a simple one -- to see how it's done.
The leading - in -include means that make won't complain if the dependencies are missing and can't be remade, but it doesn't mean it won't try to make them first (and, in this case, succeed) -- after all, anything interesting or important could be in the included files, whence the let's-try-making them attempt. I don't think there's a way to stop that.
For docs on include and -include, see here.