Strange make implicit rule - makefile

I have written a small makefile for a few simple C programs that compiles them and then tests their execution time:
CC = gcc
CFLAGS = -Wall
PTEST = /usr/bin/time -f "%Us"
ARCH=-march=native
OPTIMIZATION=
NOPTIMIZATION=
%comp : %.c
$(CC) $(CFLAGS) $(NOPTIMIZATION) -o $* $<
$(CC) $(CFLAGS) $(OPTIMIZATION) -o $*_opt $<
$(CC) $(CFLAGS) $(NOPTIMIZATION) $(ARCH) -o $*_arch $<
$(CC) $(CFLAGS) $(OPTIMIZATION) $(ARCH) -o $*_opt_arch $<
%test:
#echo ---$<---
#echo Bez optymalizacji, bez podowania architektury
#$(PTEST) ./$*
#echo Bez optymalizacji, uwzgledniana architektura
#$(PTEST) ./$*_arch
#echo Opcja $(OPTIMIZATION), bez podawania architektury
#$(PTEST) ./$*_opt
#echo Opcja $(OPTIMIZATION), uwzgledniania architektura
#$(PTEST) ./$*_opt_arch
loop%:OPTIMIZATION=-O2
logic%:OPTIMIZATION=-O1
math%:OPTIMIZATION=-O1 -ffast-math
recursive%:OPTIMIZATION=-O2 -foptimize-sibling-calls
recursive%:NOPTIMIZATION=-O2 -fno-optimize-sibling-calls
#all: loopcomp logiccomp mathcomp recursivecomp looptest logictest mathtest recursivetest
loop:loopcomp looptest
clean:
rm -rf loop loop_opt loop_arch loop_opt_arch \
logic logic_opt logic_arch logic_opt_arch \
math math_opt math_arch math_opt_arch \
recursive recursive_opt recursive_arch recursive_opt_arch
When I type make loop it compiles and tests them but then it invokes strange implicit rule that does this:
gcc -Wall loop.c loopcomp looptest -o loop
gcc: error: loopcomp: No such file or directory
gcc: error: looptest: No such file or directory
I know that this is make implicit rule because when I invoke make -r loop everything goes OK. I can't figure it out: which built-in implicit rule is make trying to invoke and how can I override it, preferably without adding -r option when invoking make? If it is possible, I would like to override it or somehow diasable make implicit rules inside makefile.

If you don't want to create a file called "loop" and you just want to be able to say "make loop" as a way to bundle up other targets (like "make all") then you should declare "loop" to be phony and make won't search for implicit rules:
.PHONY: loop
loop: loopcomp looptest
If you don't want to do that but want to ensure that a given target doesn't undergo implicit rule search, then you should declare an explicit rule for it. A simple way to do that is add a do-nothing recipe, like this:
loop: loopcomp looptest
#:
(the ":" command is the shell's "do-nothing" command).

Your default target in the makefile is:
loop: loopcomp looptest
This tells make that to build loop, it must first ensure that loopcomp and looptest are up to date, and then it must find a way to build loop. Since there is a file loop.c, it invokes its default %.c: rule to build loop:
gcc -Wall loop.c loopcomp looptest -o loop
This includes the two files (programs) you told it that loop depends on.
While you have a loop.c, I think you're likely to run into this problem.
There does not seem to be a way to say in the makefile "do not use any built-in rules". If there was, you'd expect it to be a 'Special Built-in Target Name' (§4.8 of the GNU Make manual for version 3.82), such as .DEFAULT.
Your only remaining hope is that declaring .PHONY: loop might suppress this. Otherwise, rewrite the default target rule as:
check-loop: loopcomp looptest
This is a mind-boggling makefile. Porting that to anything other than GNU make will not be trivial.

Related

Makefile error trying to use a template to compile multiple programs with similar steps

I am trying to create a makefile that can compile multiple programs. It has a list of programs and will compile each one separately. Every program has pretty much exactly the same template so I tried this solution:
CFLAGS=-O3 -std=c89 -pedantic -Wall -Wextra -Werror
programs=echo cat yes true false cp
all: $(programs)
$(programs): src/$#.c
$(CC) $(CFLAGS) -o $# $^
clean:
$(RM) $(programs)
install: all
$(CP) $(programs) /usr/local/bin/
For some reason, this doesn't work. I get the error
make: *** No rule to make target 'src/.c', needed by 'echo'. Stop.
I'm trying to make this portable so no GNU extensions. POSIX Make if possible.
Here:
$(programs): src/$#.c
...
You can't use automatic variables like $# in the prerequisite list that way. The rule gets expanded before a target has been specified, so the variable contains nothing. (You can use it this way but it's a headache.)
Use a static pattern rule instead:
$(programs): %: src/%.c
$(CC) $(CFLAGS) -o $# $^

Order of libraries and source files from makefile

I should start by saying I'm a bit of a newbie when it comes to gcc and makefiles.
On an Ubuntu machine that I've recently started using, I find that when running gcc, the order in which I put the source files and the libraries/headers makes a difference. On another machine I could do:
gcc -I../include -L../lib myProgram.c -o myProgram
But on the new machine, this will not link the libraries, and I must do:
gcc myProgram.c -o myProgram -I../include -L../lib
Now, I have the following makefile:
SHELL = /bin/sh
CC = gcc -O3
CFLAGS = -I../include
LDFLAGS = -L../lib
PROGS = myProgram
all: $(PROGS)
$(all): $(PROGS).o
$(CC) -o $# $#.o $(LIBS) $(CFLAGS) $(LDFLAGS)
rm -f $#.o
clean:
rm -f *.o $(PROGS)
But when I do "make", the actual gcc command that it runs has the libraries and source files in the wrong order. My question is: what do I need to do in the makefile to force the "-L../libs" option to come after the source files, so that the libraries will link properly?
I've also tried including the "-Wl,--no-as-needed" option, as I thought that an --as-needed flag might be the reason that the order matters in the first place, but this didn't appear to change anything (i.e. it still fails to link the libraries unless "-L../libs" comes after the source files).
The problem was that you thought you were using that rule, but you weren't. You never defined a variable named all, so the target of the second rule actually expanded to nothing. When you commanded Make to build myProgram, Make found no suitable rule in this makefile. Make has a toolbox of implicit rules it can fall back on in such cases; it wanted to build myProgram, it saw a file named myProgram.c, and one of its rules looks something like this:
%: %.c
$(CC) $(LDFLAGS) $^ -o $#
There you have it, linker flags before sources.
You can write your own pattern rule which Make will use instead:
%: %.o
$(CC) -o $# $^ $(LIBS) $(CFLAGS) $(LDFLAGS)
(Note that this builds myProgram from myProgram.o, and lets Make figure out how to build myProgram.o.)
If your executable is to be built from several object files, add a rule like this:
myProgram: other.o yetAnother.o
If you like you can have one more rule (the first) to tell Make what you want built:
all: myProgram myOtherProgram friendsProgram
(A final note: we've all had tight work deadlines. Asking for help once can be faster than learning the tools, but learning the tools is faster than asking for help N times. Determining the value of N is up to you.)

Makefile for using make as gcc

Is it possible to write universal Makefile which would get any target and act like a wrapper to gcc, but with parameters? For example, this means that
make 01.c
will have the same result as
g++ -o 01.out 01.c
make already has several "implicit rules" to do what you're trying.
For example, even with no makefile,
make 01.o
Will run:
c++ -c -o 01.o 01.cpp
If it finds a file called 01.cpp in your current directory. You can set the CXXFLAGS environment variable if you want to pass more flags. If you're really set on using g++ rather than the system compiler, you can set CXX=g++, too.
Yes - You using implicit rules.
Summat like (if memory serves me right)
.cpp.o:
$(CCC) $(CFLAGS) $< -o $#
Maybe in the set of default implicit rules
You can use a wildcard - %.
However, the thing specified on the commandline is the target, not the source - what you want, not what you have.
It looks like what you want is approximately:
%.out: %.c
g++ -o $# $<
This means: to make (something).out, first make sure you have (something).c, then run g++ -o (something).out (something).c
$# is always the target file, and $< is the first prerequisite.
You will need to run make 01.out, not make 01.c

GNU make unexpected behaviour

I want make to build all .cpp in the directory with tracking header changes. I attempt to do it by first making gcc output a target with dependencies with -MM option and then append the body to that target that will actually call the compilation:
OPTIONS = -std=c++11 -Wall
export
all : $(patsubst %.cpp, %.o, $(wildcard *.cpp))
%.o : %.mkt
make -f $*.mkt
%.mkt : %.cpp
gcc $(OPTIONS) -MM $*.cpp > $&.mkt1
echo gcc $(OPTIONS) -c %.cpp > $*.mkt2
cat $*.mkt1 $*.mkt2 > $*.mkt
Yet somehow this script issues the calls of the form
g++ -c -o something.o something.cpp
for each .cpp file in the directory. The temporary files .mkt1, .mkt2 and .mkt are not created. Why does this happen? How do i achive desired behaviour? I'm doing this on windows with mingw.
You have supplied a chain of two pattern rules (%.cpp->%.mkt, %.mkt->%.o), but Make already has a single implicit rule (%.cpp->%.o) which it will find first, when searching for a way to build something.o.
The simplest way to solve the problem is to use make -r (or make --no-builtin-rules) which will disable the built-in implicit rule.

What are double-colon rules in a Makefile for?

Section 4.13 of the GNU Make manual describes the so-called double-colon rules:
Double-colon rules are rules written with ‘::’ instead of ‘:’ after the target names. They are handled differently from ordinary rules when the same target appears in more than one rule.
When a target appears in multiple rules, all the rules must be the same type: all ordinary, or all double-colon. If they are double-colon, each of them is independent of the others. Each double-colon rule's commands are executed if the target is older than any prerequisites of that rule. If there are no prerequisites for that rule, its commands are always executed (even if the target already exists). This can result in executing none, any, or all of the double-colon rules.
Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.
The double-colon rules for a target are executed in the order they appear in the makefile. However, the cases where double-colon rules really make sense are those where the order of executing the commands would not matter.
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Each double-colon rule should specify commands; if it does not, an implicit rule will be used if one applies. See section Using Implicit Rules.
I kinda grok the meaning of each sentence of this section individually, but it's still not clear to me what double-colon rules are for. As for being rare, I have not yet seen any open-source project whose Makefile did not begin with
all::
Therefore: What's the intended purpose of double-colon rules in Makefiles?
Each :: rule is processed independently, so it can be simpler. For example, the single rule:
libxxx.a : sub1.o sub2.o
ar rv libxxx.a sub1.o
ar rv libxxx.a sub2.o
can be replaced with two simpler rules:
libxxx.a :: sub1.o
ar rv libxxx.a sub1.o
libxxx.a :: sub2.o
ar rv libxxx.a sub2.o
Utilities like AutoMake have an easier time spitting out many simple rules than a few complex ones.
A great answer with more examples was posted, then taken down, then found here:
https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html
Thanks to R.K. Owen for writing it, and Edward Minnix for finding it again!
There are 3 situations where the double colon are useful:
Alternate between the compile rules based on which prerequisite is newer than the target. The following example is based on "Example 19-3. Double-colon rules" from http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html
Sample .c file:
c#desk:~/test/circle$ cat circle.c
#include <stdio.h>
int main (void)
{
printf("Example.\n");
return 0;
}
Makefile used:
c#desk:~/test/circle$ cat Makefile
# A makefile for "circle" to demonstrate double-colon rules.
CC = gcc
RM = rm -f
CFLAGS = -Wall -std=c99
DBGFLAGS = -ggdb -pg
DEBUGFILE = ./debug
SRC = circle.c
circle :: $(SRC)
$(CC) $(CFLAGS) -o $# -lm $^
circle :: $(DEBUGFILE)
$(CC) $(CFLAGS) $(DBGFLAGS) -o $# -lm $(SRC)
.PHONY : clean
clean :
$(RM) circle
Outcome:
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
make: *** No rule to make target 'debug', needed by 'circle'. Stop.
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
c#desk:~/test/circle$ vim circle.c
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c
c#desk:~/test/circle$ vim debug
c#desk:~/test/circle$ make circle
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
Make a pattern rule terminal.
The following example explains this situation: the a.config file is obtained from a.cfg, which in turn is obtained from a.cfg1 (a.cfg being the intermediate file).
c#desk:~/test/circle1$ ls
a.cfg1 log.txt Makefile
c#desk:~/test/circle1$ cat Makefile
CP=/bin/cp
%.config:: %.cfg
#echo "$# from $<"
#$(CP) $< $#
%.cfg: %.cfg1
#echo "$# from $<"
#$(CP) $< $#
clean:
-$(RM) *.config
Outcome (as the %.config rule is terminal, make inhibits the creation of the intermediate a.cfg file from a.cfg1):
c#desk:~/test/circle1$ make a.conf
make: *** No rule to make target 'a.conf'. Stop.
Without the double colon for the %.config, the outcome is:
c#desk:~/test/circle1$ make a.config
a.cfg from a.cfg1
a.config from a.cfg
rm a.cfg
Make a rule that executes always (useful for clean rules). The rule must not have prerequisites!
c#desk:~/test/circle3$ cat Makefile
CP=/bin/cp
a.config::
#echo "Always" >> $#
a.config::
#echo "Always!" >> $#
clean:
-$(RM) *.config
Outcome:
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
c#desk:~/test/circle3$ make a.config
c#desk:~/test/circle3$ cat a.config
Always
Always!
Always
Always!
They are handy for non-recursive makefiles and targets like clean. That is, an individual .mk file can add its own commands to the clean target already defined elsewhere.
Documentation gives an answer:
Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.
Just as the documentation says, double-colon rules are rarely very useful. They are a nice, little way of not naming the individual targets of a composite phony target (like all::), but not really necessary in this role. I can only form one contrived example where they are necessary:
Suppose you have a logfile L that is concatenated from several other logfiles L1, L2, .... You formulate a number of double-colon rules like:
L :: L1
cat $< >> $# && rm $<
L :: L2
cat $< >> $# && rm $<
Nowadays in GNU make, you would of course use $^ for this kind of magic, but it is listed as an inspired feature on GNU make's feature tab.
I'll contribute a simple example to hopefully make the usage clear:
Experiment with the following makefile:
a.faux:: dep1.fake
$(info run a dep1.fake)
touch a.faux
a.faux:: dep2.fake
$(info run a dep2.fake)
touch a.faux
dep1.fake:
touch dep1.fake
dep2.fake:
touch dep2.fake
Run make a.faux, it will causes dep1.fake and dep2.fake to run. Delete dep1.fake and run make a.faux again, only dep1.fake will run.

Resources