why make behaves different with quotes? - makefile

I know quotes are not supposed to be used within Makefile, but just out of curiosity, why make behaves differently with make foobar and make. See detailed code below.
Makefile:
TARGET = 'foobar'
$(TARGET): foobar.cpp
g++ -g $^ -o $#
clean:
rm foobar
output:
$ make
g++ -g foobar.cpp -o 'foobar' <-- correct
$ make clean
rm foobar
$ make foobar
g++ foobar.cpp -o foobar <-- incorrect but works. Why?
$ make clean
rm foobar
$ make baz <-- doesn't work, which is normal
make: *** No rule to make target 'baz'. Stop.
$

This only "works" because the shell is stripping the single quotes from your first example for you.
The quotes are literally in the value of the $(TARGET) make variable. make doesn't dequote the right-hand side of the TARGET = 'foobar' assignment.
You can see this by using $(info $(TARGET)) in your makefile.
So your target line:
$(TARGET): foobar.cpp
is creating a target with the name 'foobar' and not foobar like you expect.
This is why running make does the "right" thing and make foobar does something else.
make foobar is running the make built in rule for %: %.cpp.
The fact that your default 'foobar' target works to create foobar is because the shell sees the single quotes and strips them.
You'll notice that if you make make; make make will build your 'foobar' target twice but make foobar; make foobar will tell you there is nothing to be done the second time. That's because the first target creates a file different from what make is expecting.
If you were to quote $# in your recipe line you would see different behavior.
$(TARGET): foobar.cpp
g++ -g $^ -o '$#'
for example would have make run g++ -g foobar.cpp -o ''foobar'' and generate a foobar file while
$(TARGET): foobar.cpp
g++ -g $^ -o "$#"
would have make run g++ -g foobar.cpp -o "'foobar'" and generate a 'foobar' file (which would cause make; make to report nothing to be done for the second make run).
You want the quotes in the recipe line not in the variable here.
TARGET = foobar
$(TARGET): foobar.cpp
g++ -g $^ -o '$#'
clean:
rm foobar
That being said since you can't have spaces in make target names (not reliably at least) the need for those single quotes (or any quoting) is diminished since you only need it if the filename contains shell metacharacters.

It's because make uses a default rule when it does not find specific rules to build a target.
You can compile program from program.cpp even without or with an empty Makefile. Try
make -f /dev/null foobar
The default rules are specified by POSIX and your make implementation has probably some of its own.
Trying to build baz fails, because none of the default rules knows how to build a baz.c or baz.cpp or any of the other built-in source files that could be used to build baz.

Related

why do echo work in %: foo.o rule but not in %: %.o?

This is my current makefile
.PHONY = all clean
all: foo
#echo "Dependencies: $<"
%: %.o
#echo "Checking.. $#, <- $<"
gcc -lm foo.o -o foo
#echo "\n"
%.o: %.c
#echo "Creating object.. $#, <- $<"
gcc -c foo.c
#echo "\n"
clean:
#echo "Cleaning up..."
rm -rvf foo.o foo
When I run make, it doesn't print out any echoed strings, but I still get the executable file. This is all the things that get printed to the terminal
gcc foo.c -o foo
echo "Dependencies: foo"
When I replace %: %.0 rule with %: foo.o, everything is printed to the terminal normally
Creating object.. foo.o, <- foo.c
gcc -c foo.c
Checking.. foo, <- foo.o
gcc -lm foo.o -o foo
Dependencies: foo
rm foo.o
In both cases, I still get the executable file foo and it works normally, but why do I get 2 different results in the terminal?
When I run make, it doesn't print out any echoed strings, but I still get the executable file.
Since you do not have an explicit rule for building foo, (GNU) make performs an implicit rule search, by which it attempts to find a chain of one or more pattern rules, whether user-provided or built-in, by which it can build foo. Although it could choose to apply your rule to build foo.o from foo.c and then your rule to build foo from foo.o, it has a shorter chain available: a built-in rule for building foo directly from foo.c. It chooses the latter because it's shorter.
When I replace %: %.0 rule with %: foo.o, everything is printed to the terminal normally
This is a bit of a quirk of the implicit rule search procedure. When you make that change, make identifies the revised rule as "applicable" for building foo on account of the only prerequisite having an explicit name (this is item 5.3 in the algorithm described in the manual). The built-in rule for building directly from %.c is also applicable, but the one given in the makefile has precedence (among rule chains of the same length). The fact that make has to figure out separately how to make foo.o doesn't enter into consideration in this case (this is the quirky part, but follows clearly from the docs).
Of course, this particular quirk is rarely triggered, because a rule of the form of your revised one is almost always inappropriate. It says that whatever target is to be built, it can be built from foo.o, via the provided recipe, but that recipe really works only for building foo. Instead of %: foo.o, then, you really ought to make it foo: foo.o:
.PHONY = all clean
all: foo
#echo "Dependencies: $<"
foo: foo.o
#echo "Checking.. $#, <- $<"
gcc -o $# $< -lm
#echo "\n"
%.o: %.c
#echo "Creating object.. $#, <- $<"
gcc -c foo.c
#echo "\n"
clean:
#echo "Cleaning up..."
rm -rvf foo.o foo
Additional notes:
link library options such as -lm should come at the end of the link line. The relative order of these and object files on the command line matters.
Avoid repeating yourself. Rules' recipes should use automatic variables where possible to avoid repeating the target or prerequisite names.

Using Makefile to run multiple programs

Whenever I try to run this, the only output I get is "make: foo.o is up to date." It seems as if the rest of the program does not run and I do not know why. My instructions are as follows: "Compile a C program. Run a C program. Run a Python program. Compile and run a java program. Check for a README, display it. Compare 2 files. Clean up intermediary files."
cc = gcc
EXE = foo
JAVAC = javac
JRE = java
PAGER = less
TEST_OUT = test.out
EXP_OUT = expected.out
foo.o: foo.c foo.h
$(cc) -c foo.c
main.o: main.c foo.h
$(cc) -c main.c
$(EXE): foo.o main.o
$(cc) -o$(EXE) main.o foo.o
run-c: $(EXE)
./$(EXE)
run-py:
./foo.py
read: README
$(PAGER)
foo.class: foo.java
$(JAVAC) foo.java
run-java: foo.cass
$(JRE) foo
save-java:
./(run-java) >> $(TEST_OUT)
test-java: $(TEST_OUT) $(EXP_OUT)
#if diff $(TEST_OUT) $(EXP_OUT) &> /dev/null ; then \
echo "Passed!" ;\
else \
echo "Not the same!" ;\
fi
clean:
-rm test.out
Whenever I try to run this, the only output I get is "make: foo.o is up to date."
By default, make runs the topmost rule when no target is specified. You have to run for example make run-c to invoke a corresponding recipe, or you can just put an all rule before any others which depends on and does all the things.
read: README
$(PAGER)
I suspect you might have missed putting $# after $(PAGER) as the argument.
save-java:
./(run-java) >> $(TEST_OUT)
You can't just "include" other recipes this way. Instead, repeat what's in run-java and append the redirection.
If you want to specify "pseudo" targets, I recommend you to specify them as .PHONY, such as:
.PHONY: all run-c run-py run-java save-java test-java clean
To mark some targets as intermediate files, use the .INTERMEDIATE directive. GNU Make manual (texinfo) is available both online and via the info command.

Makefile stops running at the middle [duplicate]

Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot

Strange make implicit rule

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.

How do I shut up make when it doesn't need to do anything?

How I stop make from saying make: Nothing to be done for 'all'. or make: 'file' is up to date? I'd like my build to be silent when it's not doing anything - there are other places where echo is called to track build progress, so this message is just cluttering things up. I am currently silencing it like this:
all: dependency1 dependency2
#:
Something tells me there must be a better way. Any ideas?
Edit:
I would like to keep command echo working when it does need to build something, however. A good example of what I'm hoping for is along the lines of --no-print-directory, but I can't find any other flags to shut up selected messages.
Maybe make -s?
So after a couple days of reading around the web, it looks like there isn't any better way than what I'm doing. Some people recommended something along the lines of:
all: dependency1 dependency2 | silent
silent:
#:
That is, just depending on the silent target would be enough to quiet things down. Since I didn't come up with any other workable solutions, I'm going with what I have.
You might try...
$ make -q || make
The advantage of doing it this way is that nothing is printed when there is nothing to do but make produces the normal output when it does need to proceed...
To quote (from memory) from the old make(1) man page, BUGS section: There are some things you can't get make to shut up about. Meanwhile, the -s or --silent option may help.
You can set the -s commandline argument to make in the makefile itself, by setting MAKEFLAGS. Nothing is printed unless you explicitely print it, so I use the following makefile to echo invoked commands.
MAKEFLAGS += -s
PROJECT = progname
CC = g++
SDIR = src
ODIR = obj
BDIR = bin
IDIR = include
OBJS = $(patsubst $(SDIR)/%.cc,$(ODIR)/%.o,$(wildcard $(SDIR)/*.cc))
.PHONY: all debug clean
all: $(BDIR)/$(PROJECT)
debug: CFLAGS += -g -Wall -Wextra
debug: all
$(BDIR)/$(PROJECT): $(OBJS)
#mkdir -p $(BDIR)
#echo LINKING $<
#$(CC) -o $# $(OBJS) -I$(IDIR)
$(ODIR)/%.o: $(SDIR)/%.cc
#mkdir -p $(ODIR)
#echo "COMPILING $<"
#$(CC) -o $# -c $< $(CFLAGS)
clean:
#echo "CLEAN"
#rm -rf $(BDIR) $(ODIR)
Removing the MAKEFLAGS variable will print all invoked commands. The Makefile compiles any c++ project where source files (with .cc extension) are put into the src directory and header files are put into the include directory.
make 2>&1 | egrep -v 'Nothing to be done|up to date'

Resources