make don't build file even if dependency is updated - makefile

this is my make file:-
VER = Debug
CC = g++
OBJECTFIELS = main.o Time.o
main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFILES): Time_.h
clean:
rm $(OBJECTFIELS) main
every time I change the Time_.h file, nothing happens:-
$ make
make: 'main' is up to date.
$ touch Time_.h
$ make
make: 'main' is up to date.
other files compile when changed :-
$ touch main.o
$ make
g++ main.o Time.o -o main
please I am complete noob. Please tell why is this happening

You need to generate new .o files in your rule for Time_.h.
$(OBJECTFILES): Time_.h
This says make should run a command whenever Time_.h is updated, and that the command will generate both main.o and Time.o. But no command is given!
Time.o: Time_.h
$(CC) Time_.cpp -o Time.o
This is the kind of rule you want. Whenever Time_.h changes, we run $(CC) Time_.cpp -o Time.o, which will generate Time.o. Now if some other rule depends on Time.o, make will know that this command can be used to create Time.o, but that it only needs to be run if Time_.h changed since the last time make was run.
I'm specifying "Time.o" explicitly, since your source filenames don't seem to exactly match the object files you're expecting. (Time.o vs Time_.o)

Related

Why makefile is not saving output files to different directory?

I'm playing with makefile and I have this issue - it's not saving output files to different directories.
CC = g++
CFLAGS = -c -Wall
ODIR = obj
BDIR = bin
$(BDIR)/test: test.o print.o
$(CC) test.o print.o -o test
$(ODIR)/%.o: %.cpp %.h
$(CC) $(CFLAGS) $< -o $#
.PHONY : clean
clean:
rm -f $(ODIR)/*.o $(BDIR)/test
Even if I create these directories manually it doesn't work as expected. Both dirs are empty after "make" without any errors. Output files are always created in main directory. Will be gret if you can give me an advice.
This rule:
$(BDIR)/test: test.o print.o
tells make that to build $(BDIR)/test it first needs to build test.o and print.o. So, it does build those two files. You have defined a rule to build $(ODIR)/%.o, but test.o does not match the pattern $(ODIR)/%.o so that rule is not used.
Instead make uses its own default built-in rules that know how to create %.o; that pattern DOES match your target test.o.
If you want make to build objects in another directory, you have to list them there when you write your rules:
$(BDIR)/test: $(ODIR)/test.o $(ODIR)/print.o
Now, make knows you want to build targets in the $(ODIR) directory so it will use a rule that can do so.

How to create a makefile that will place object code in different folder

I am very new to Makefile. I had build the following makefile(Which don't work).I wan't put genarated object codes in differnt folder(the folder is in current directory).
$ ls
main.cpp Makefile object_code Time.cpp Time_.h
how can I do this ??
VER = Debug
CC = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
clean:
rm $(OBJECTFIELS) main
this is error.
$ make
g++ ./object_code/main.o ./object_code/Time.o -o ../Debug/main
g++: error: ./object_code/main.o: No such file or directory
g++: error: ./object_code/Time.o: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:8: recipe for target '../Debug/main' failed
make: *** [../Debug/main] Error 1
please this is last question.
I don't see how you can possibly get that output given the makefile you've posted here.
Either the object files already exist in which case the link will succeed rather than printing that error.
Or the object files don't exist in which case make will complain because it doesn't know how to make them. There must be some difference between the makefile you're using and the one you've posted here.
In any event, make knows how to build a file foo.o from a file foo.cpp for any string foo. There's a built-in rule that tells it how to do that.
But, make doesn't know how to build a file ./object_code/foo.o from a file foo.cpp, regardless of foo. There's no built-in rule that tells make how to build object files in some random other directory. If you want make to do that, you'll have to tell it how. You should remove the lines:
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
and replace them with a pattern rule describing how to build object files into the object_code directory (I'm using CXX as the compiler variable here: by convention CC is the C compiler and CXX is the C++ compiler, and you should always stick with convention unless there's a good reason not to):
VER = Debug
CXX = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CXX) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/%.o : %.cpp
$(CXX) -c -o $# $<
clean:
rm $(OBJECTFIELS) main

Switching from g++ to clang++ in makefile

I 've got following makefile:
all: xmltest
xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h
This works fine - after executing make all executable 'xmltest' is produced.
However, I want to switch compiler to clang++. So I've added this line at the beginning of the file:
CXX=clang++
and now executing make all produces an error:
clang++ xmltest.cpp tinyxml2.cpp tinyxml2.h -o xmltest
clang++.exe: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated
clang++.exe: error: cannot specify -o when generating multiple output files
<builtin>: recipe for target 'xmltest' failed
make: *** [xmltest] Error 1
How to fix this with minimal modifications to original make file?
You might as well just write a shell script: there's no advantage to using the makefile in your solution. Any time you change any file, the entire thing will be rebuilt, so you might as well just run:
clang++ -g -o xmltest xmltest.cpp tinyxml2.cpp
whenever you change anything and skip the makefile.
If you wanted a makefile which took advantage of some of the capabilities of make, you would write it something like this:
CXX = clang++
all: xmltest
xmltest: xmltest.o tinyxml2.o
xmltest.o tinyxml2.o: tinyxml2.h
Now you have something useful, where only the files that need to be rebuilt based on what you've changed will be rebuilt. If your program gets more complex, you can use even more make facilities to keep it manageable.
You shouldn't list the header file as a translation unit (those are the cpps)
You should usually make the .h prerequisites:
xmltest.cpp: tinyxml2.h
tinyxml2.cpp: tinyxml2.h
And compile/link the translation units:
all: xmltest
xmltest: xmltest.cpp tinyxml2.cpp
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
IIRC you /might/ also put the 'dependency only' items on the same line using |
xmltest: xmltest.cpp tinyxml2.cpp | tinyxml2.h
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
But I'm unable to check that right now

Without .PHONY target is getting built when a file named as target already exists in current directory

While going through MakeFiles I found that when the file named as target is present even then without using .PHONY, target is getting built.
But when I am doing the same with another target i.e. clean, then target is not getting built and saying "clean is up-to-date" which is OK.
I just want to know why the other target is getting built when the file exists in the current directory.
makefile:
CC:= gcc
CCFLAGS:=-Wall -Wextra
hello: hellomake.o hellofunc.o
$(CC) $(CCFLAGS) hellomake.c hellofunc.c -o file
hellomake.o : hellomake.c
$(CC) $(CCFLAGS) -c hellomake.c
hellofunc.o : hellofunc.c
$(CC) $(CCFLAGS) -c hellofunc.c
clean:
rm -rf *.o
rm -rf file
My current directory has file named same as the target, as "hello".
It should give result as "hello is up-to-date" but it is not doing it and giving the output as :
make hello
gcc -Wall -Wextra hellomake.c hellofunc.c -o file
Please tell why is this building the target when the TARGET IS NOT .PHONY AND THE FILE NAMED AS TARGET ALREADY EXISTS IN CURRENT DIRECTORY.
Because make looks at the last-modified times to decide what to build. From the make manual:
The make program uses the makefile database and the last-modification times of the files to decide which of the files need to be updated.
The command make examines the time relationships between the target and its prerequisites. If the prerequisites have been modified after the target it means that the target is out of date and the rebuild is triggered even if the file is present. So most likely your dependencies have been modified after the target.
In order to avoid this behavior, you can:
Use touch to change the target timestamp.
Use make -t hello or make --touch hello before invoking make hello. From the docs:
‘-t’
‘--touch’
Marks targets as up to date without actually changing them. In other words,
make pretends to update the targets but does not really change their
contents; instead only their modified times are updated.

make: *** No rule to make target `all'. Stop

I keep getting this error:
make: *** No rule to make target `all'. Stop.
Even though my make file looks like this:
CC=gcc
CFLAGS=-c -Wall
all: build
build: inputText.o outputText.o main.o
gcc main.o inputText.o outputText.o -o main
main.o: main.c
$(CC) $(CFLAGS) main.c -o main.o
inputText.o: inputText.c
$(CC) $(CFLAGS) inputText.c -o inputText.o
outputText.o: outputText.c
$(CC) $(CFLAGS) outputText.c -o outputText.o
Yes there should be a tab space underneath the target and there is in my make file.
I can get it to work if I try one of the targets like main.o, inputText.o and outputText.o but can't with either build or all.
EDIT:
I just randomly tried running make and telling it the file using the following command:
make -f make
This works but why doesn't just typing make work?
Your makefile should ideally be named makefile, not make. Note that you can call your makefile anything you like, but as you found, you then need the -f option with make to specify the name of the makefile. Using the default name of makefile just makes life easier.

Resources