A simple answer is make
's behavior. But it doesn't give understanding how it works, so let's go deeper.
We begin with the first Makefile. Because my directory has only one file fizzbuzz.s
, the variable BIN
will be equal fizzbuzz
. Make
searches the fizzbuzz
target, but there is no the target. For that reason make
processes built-in rules. It searches files with extension added to fizzbuzz
target and if it has searched the files it processes own rules. I tried to remove the Makefile and run command: make fizzbuzz
and it runs another
cc fizzbuzz.s -o fizzbuzz
.
It's equal to the first Makefile.
Now, we'll use the second Makefile.
When I changed the .s
extension on .asm
it worked. Interesting behavior, it's because make
doesn't have built-in rules for .asm
extension. I wanted to get understanding so I returned .asm
to .s
back.
My second Makefile has a rule for target without extension:
%: %.o
$(LNK) -melf_i386 $< -o $@
But it doesn't work as expected and works like without Makefile. This happens, I suppose, because %
has the last priority execution after built-in rules. We can change the behaviour by adding MAKEFLAGS += --no-builtin-rules
in the Makefile, and everything works fine.
But I noted one weird thing without the option. I did the command make fizzbuzz.o
and it has been built fizzbuzz.o
(it processes command from my Makefile). So, OK. Let's run make
again. I run it and it built me the final fizzbuzz
target. Surprise!
So the rule
%: %.o
$(LNK) -melf_i386 $< -o $@
is working when there are object files(.o) in the current directory. I don't know what it is, a bug or a feature(IMHO a weird feature), but it works so.
Finally, we have two solutions to make second Makefile working and they are the following:
- omit built-in rules by replacing
.s
extension by .asm
or any other which doesn't have built-in rules in make
- disable built-in rules by adding to Makefile an option
MAKEFLAGS += --no-builtin-rules
or run with make -R
or make -r