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

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.

Related

Makefile does not recognize pattern rule

I'm really struggling in understanding why the following makefile won't work:
all: buildFolders main.out
mv main.out build/
-echo "File compiled"
buildFolders:
mkdir -p build src
cp *.c src/
%.s: %.c
gcc -S $< -o $#
%.out: src/%.s
gcc $< -o $#
It is executed in a folder containing only the makefile and a main.c file. It should build the src and build folder, copy the main.c in the src folder and then start compiling the main.out. Unfortunately it throws the error "no rule to make target 'main.out'". Since I have the %.out that matches 'main.out' I don't see why it gives me that error. Instead it should look for the src/main.s file, create it and then use it to generate the main.out.
What am I doing wrong? Thanks
You have a number of problems.
First, listing prerequisites in order doesn't create a dependency relationship. If, for example, you ever wanted to enable parallel builds then this:
all: buildFolders main.out
doesn't force the buildFolders target to be built before main.out. These two targets both must be built before all but this doesn't tell make that there's any relationship between buildFolders and main.out. If buildFolders must be completed before main.out can be built then main.out must list buildFolders as a prerequisite.
Second, you haven't told make how to build a file src/main.c. It's built as a side-effect of the buildFolders target, but make can't know that. You need to explain to make that this file can exist. I recommend adding a rule:
src/%.c: %.c
mkdir -p src
cp $< $#
and removing the buildFolders target altogether.
However, I really question why you want to do this anyway. What's the point of copying the source files in the current directory to some sub-directory to build them? It's dangerous and confusing to have multiple copies of source files lying around because they can get out of sync with each other, then you're building older versions and you spend hours trying to understand why something doesn't work. It's a really bad idea.

About execution order in makefile

in this Makefile:
ifeq ($(shell uname),Darwin)
LDFLAGS := -Wl,-dead_strip
else
LDFLAGS := -Wl,--gc-sections -lpthread -ldl
endif
all: target/double
target/double
target:
mkdir -p $#
target/double: target/main.o target/debug/libdouble_input.a
$(CC) -o $# $^ $(LDFLAGS)
target/debug/libdouble_input.a: src/lib.rs Cargo.toml
cargo build
target/main.o: src/main.c | target
$(CC) -o $# -c $<
clean:
rm -rf target
when i excute make all, get this output:
hello_c_use_rust [master] ⚡ make all
mkdir -p target
cc -o target/main.o -c src/main.c
cargo build
Compiling hello_c_use_rust v0.1.0 (/Users/jelly/code/own/hello_rust/hello_c_use_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
cc -o target/double target/main.o target/debug/libdouble_input.a -Wl,-dead_strip
target/double
4 * 2 = 8
Please tell me why this is the execution order ? txs ^_^.
What puzzled me was why the first step was mkdir -p target;
Your goal is all. all depends on target/double that must thus be done first. In turn target/double depends on target/main.o and target/debug/libdouble_input.a. So target/main.o and target/debug/libdouble_input.a must be done first. Here, you are lucky (we'll see why later): make tries to build target/main.o first. As target/main.o has target as a prerequisite, target must be done first and it is. Qed.
Note: target is an order-only prerequisite of target/main.o, not a regular prerequisite (the | sign starts the list of order-only prerequisites). It means that make pays only attention to its existence. It ignores its last modification time, which is good as last modification times of directories are usually not relevant in a build process.
Why is target a prerequisite of target/main.o? Because you cannot build target/main.o if the target directory does not exist yet. The build would simply fail. So the order-only prerequisite tells make that the directory must exist first.
Why are you lucky? Because if make had tried to build target/debug/libdouble_input.a first and if cargo build does not create the destination directory, it would have failed. Even if you know that target/main.o is built first because it is the first prerequisite of target/double, you should not count on this. One day or another somebody could try to use parallel make (make -j) and things could go wrong. Moreover target could exist but not target/debug...
Note: even if you know that cargo build takes care of creating the destination directory it is probably wise to add one more order-only prerquisite to your Makefile. Just in case something changes one day or another. And also to show readers of your Makefile that you know what you are doing here:
target target/debug:
mkdir -p $#
target/debug/libdouble_input.a: src/lib.rs Cargo.toml | target/debug
cargo build
It is not a big deal and could save you some errors.

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.

make don't build file even if dependency is updated

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)

C Makefile - recompile only changed files

Hello I have a shared library libnsd.so (made up of nsd.c,nsd.h,nd.c,nd.h) linked to main file.
My question is how to write the makefile so that it recompiles only those source files that have been changed.
I have read some topics about this but got somewhat confused, I'm a beginner programmer.
My makefile code so far:
CC=gcc
all : lib alll
alll : main.c
$(CC) main.c -o main -L. libnsd.so
lib : nsd.c nsd.h nd.c nd.h
$(CC) -c -fPIC nsd.c -o nsd.o
$(CC) -c -fPIC nd.c -o nd.o
$(CC) -shared -Wl,-soname,libnsd.so -o libnsd.so nsd.o nd.o
clean:
rm main libnsd.so nd.o nsd.o
Makefiles have the concept of build targets. The build targets are, really, all the intermediate as well as the final files and, by the way they are written, they can be made to use dependencies.
A sample solution for your makefile:
CC=gcc
all: main
main: main.c libnsd.so
$(CC) main.c -o main -L. libnsd.so
libnsd.so: nsd.o nd.o
$(CC) -shared -Wl,-soname,libnsd.so -o libnsd.so $#
%.o: %.c nsd.h nd.h
$(CC) -c -fPIC $< -o $#
A few things to note:
You should properly correct my dependencies on the object file creation (since I consider that each of the C files depends on both of the headers).
You may wish to note the wildcard construction I have used...
If there was nothing special with some of these commands I could have left default commands work. Do note that I have used $< for the first dependency and $# for the output in the wildcard rule.
I haven't copied the clean rule, since it was written correctly in the question itself.
Each of the targets (besides the "phony" target all) creates a file with the same name: The target libnsd.so creates a file with the name libnsd.so. The target main creates a file with the name main.
As a dependency of a target changes date so that the dependency is newer than the output, make will recreate the target, as well as other targets that depend on it. But if you have a target that is not mapped to any output file, that target is always called (in our code, the all target is always called but thankfully it has no commands and it depends only on actual files which may or may not need being recreated)
Do note that GNU Make doesn't need to have compiling in particular. The creation of an output file can happen by any means, and indeed I have seen a target create a .cpio.gz archive. But if that archive is older than any of the dependencies (the folder it would pack in) then it would be recreated, according to make.

Resources