Makefile clean all target is called twice when explicitly invoked - makefile

I am still figuring out why in the below Makefile, when I execute it in the command like make clean all it runs twice the "clean all" target part?
FLAGS = -g -Wall -Wextra -Werror
a.out : check.cpp
$(CXX) $(CFLAGS) -o $# $<
clean all:
rm -rf *.o *.out *.txt

The target "clean all:" is equivalent to:
clean:
rm -rf *.o *.out *.txt
all:
rm -rf *.o *.out *.txt
You can't have spaces in target names, each word would be considered a target. So when you do make clean all, make thinks you want to build target "clean" and target "all" and so you have 2 targets being executed. It does look like a mistake in the makefile since having all doing the same as clean is weird.

Related

Simple makefile command not found

I was given a makefile that looks like this, and told not to change it.
all: clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp clean: rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
I am trying to run this makefile in a folder with files named: scanner.lex, parser.ypp, output.hpp and output.cpp
I copied it to a file like this:
all:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
When I run the make command in my terminal I get an error:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
/bin/sh: clean: command not found
make: *** [all] Error 127
Am I doing something wrong? Again, I was given this line and told not to change it.
Thanks a lot.
Line breaks are essential in most computer environments. If you were given a Makefile without the line breaks and you try to cut it randomly you will have difficulties before if finally works. Try this, maybe:
all: clean
flex scanner.lex
bison -d parser.ypp
g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
And use tabs to indent the indented lines, not spaces.
Explanations: all and clean are what is called a target in make parlance. They are the names of the things you want make to do. clean to delete some files, all to do everything else. The
target: prerequisite1 prerequisite2...
recipe1
recipe2
...
template is the basic make template. It means that target depends on prerequisite1, prerequisite2 and that in order to build it make shall pass recipe1 to the shell for execution, then recipe2...
Note that this Makefile is poorly written. As all and clean are not real file names they should be declared as phony, such that, if a file with that name exists make does the job anyway. As is, it wouldn't. Give it a try:
$ make all
$ touch clean
$ make clean
make: 'clean' is up to date.
See? Because a file named clean exists you cannot make clean anymore, make considers that there is nothing to do for clean. Add this at the beginning of your Makefile:
.PHONY: all clean
A second issue is that make works by comparing last modification times of targets and prerequisites to decide if targets must be rebuilt or not. With your Makefile make will always recompile everything, even if the inputs did not change and the outputs are up-to-date. This is a waste. A better (but untested) Makefile would be something like:
.PHONY: all clean
CFILES := $(filter-out lex.yy.c,$(wildcard *.c))
CPPFILES := $(filter-out parser.tab.cpp,$(wildcard *.cpp))
all: hw2
hw2: lex.yy.c parser.tab.cpp $(CFILES) $(CPPFILES)
g++ -std=c++11 -o $# $^
lex.yy.c: scanner.lex
flex $<
parser.tab.cpp: parser.ypp
bison -d $<
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
Understanding it and why it is better is left as an exercise.

Fortran90 Makefile with pre-compilation and modules

I'm trying to write a Makefile to compile a Fortran90 project that consists of several source files containing subroutines and modules. To make things more complicated, I'm using pre-compilation (creating *.for files from *.F files). I could not find any answer to this, but this may be because I get confused by the different styles of Makefile syntax.
I created a stripped-down version for reproducing my problem (available on https://github.com/stineb/stackoverflow). This contains a main program (sayhello.F), two subroutines in separate source files (schleppe.F and schnuppi.F), and two modules in separate source files (words_schleppe.mod.F and words_schnuppi.mod.F). The executable is hello.
I am able to build it with a simple Makefile and avoiding the pre-compilation. This file (Makefile_simple) looks like this:
FCOM=gfortran
EXE = hello
standard:
$(FCOM) -c words_schleppe.mod.F
$(FCOM) -c words_schnuppi.mod.F
$(FCOM) -c schleppe.F
$(FCOM) -c schnuppi.F
$(FCOM) words_schleppe.mod.o words_schnuppi.mod.o schleppe.o schnuppi.o sayhello.F -o $(EXE)
.PHONY: clean
clean:
rm $(EXE) *.o *.mod
However, my project will be a bit bigger than this so I want to make use of the cryptic features of a more complex Makefile for defining rules. And crucially: I want to pre-compile source files *.F into .for. This is where I haven't managed to define the rules to create the .mod files from the modules and build the whole thing. Disregarding the modules, I do get it running with the following Makefile (Makefile_complex on my github repository):
FCOM=gfortran
CPPFLAGS=-e
COMPFLAGS=
EXE=hello
SOURCES=sayhello.F schleppe.F schnuppi.F
OBJS=$(SOURCES:.F=.o)
all: $(OBJS)
# this may also be replaced by the ar command (creating archive)
$(FCOM) $(OBJS) -o $(EXE)
%.for: %.F
rm -f $*.for
$(FCOM) $(CPPFLAGS) $*.F > $*.for
$(OBJS): %.o: %.for
$(FCOM) -c -o $# $(COMPFLAGS) $*.for
# clean: remove .for, .o, .do, and .stb files
.PHONY: clean
clean:
-rm -f *.for *.o *.stb *.mod
What do I have to add to this in order to include the modules in the build? The dependencies are as follows: subroutine schleppe <- module words_schleppe; and subroutine schnuppi <- module words_schnuppi.
Help, anyone?
Thanks a bunch!
I FOUND THE SOLUTION! Simply, the rule for all: must include the module source files, and these must precede the other source files. Plus, rules of creating the object files from the module source files have to be added. The working Makefile looks like this:
FCOM=gfortran
CPPFLAGS=-E
COMPFLAGS=
EXE=hello
SOURCES=sayhello.F schleppe.F schnuppi.F
MODS=words_schleppe.F words_schnuppi.F
OBJS=$(SOURCES:.F=.o)
MODOBJS=$(MODS:.F=.o)
# this may also be replaced by the ar command (creating archive)
all: $(MODOBJS) $(OBJS)
$(FCOM) $(OBJS) $(MODOBJS) -o $(EXE)
%.for: %.F
rm -f $*.for
$(FCOM) $(CPPFLAGS) $*.F > $*.for
$(MODOBJS): %.o: %.for
$(FCOM) -c -o $# $(COMPFLAGS) $*.for
$(OBJS): %.o: %.for
$(FCOM) -c -o $# $(COMPFLAGS) $*.for
# clean: remove .for, .o, .do, and .stb files
.PHONY: clean
clean:
-rm -f *.for *.o *.stb *.mod

Two targets with no dependencies

Consider the following makefile:
TARGET=fmake
TARGET2=test_second
fmake: $(TARGET2).c foo.c\
$(TARGET).c test.h clean
$(CC) -o $(TARGET) $(TARGET).c foo.c
$(CC) -o $(TARGET2) $(TARGET2).c
foo.c:
echo Some text
clean:
rm -f fmake test_second
CC=$(VAR2)
VAR2=gcc
After the make bash command the following display
rm -f fmake test_second
gcc -o fmake fmake.c foo.c
gcc -o test_second test_second.c
As said here foo.c doesn't processed because there is no dependencies for this target. But both foo.c and clean have no dependencies, but clean is processed. Why?
Because a file called foo.c exists, whereas no file called clean exists. So Make thinks that one needs to be made. Note that clean should really be declared as a phony target.

Simple pattern rule in make

I've written a simple make to test with pattern rule. Here it is:
default:
echo This is default target
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
I have a three *.c files in pwd. After make command I have:
echo This is default target
This is default target
but I expected that any *.c file in pwd will be compiled.
The first target in the makefile is the one that is built when you do not specify a specific target name.
In your makefile, default is first, so it is created.
Often, you'll create a target all as the first target, and list the programs that should be built by some more or less devious means.
.PHONY: default all clean
default:
#echo "You must specify which program you want built (or specify all)"
SRCS = $(wildcard *.c)
PROGS = ${SRCS:.c=}
all: ${PROGS}
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
The .PHONY target specifies that default, all and clean are not real files but phony targets.
I have a directory with many source files in it, and I have a default rule similar to the above as the first target, but I also have an all target so that make all works sensibly.
I prefer to use the ${...} notation around make variables, which make has always accepted; many people use $(...) notation the whole time.
I think default is your program target, but it did not link any objects? see my makefile:
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
default:
#echo This is default target
Program: $(OBJS)
gcc $^ -o $#
$(OBJS): $(SRCS)
gcc -c $^
clean:
rm -f $(OBJS) $(Program)
if you type make, it just echo This is default target, if you want to make real target, you can type make Program

Makefile as a dependency for a make target

Is it ever a bad idea to include a Makefile as a dependency for a make target?
Eg.
hello.o: hello.cxx Makefile
$(CXX) -c $(CFLAGS) $< -o $#
That way anytime the Makefile is modified the target is recompiled.
No its not a bad idea. Conventionally we never do that but if you have makefile calling other makefile then including it would be a great idea though.
I believe what you're trying to do is run clean (or other equivalent target) whenever the Makefile gets modified.
This can be achieved so. (I've been using this recipe in couple of my C/C++ projects).
CLEANUP_TRIGGER := .makefile
BASE_MAKEFILE := $(firstword $(MAKEFILE_LIST))
FINAL_TARGET := hello.o
all: $(CLEANUP_TRIGGER) $(FINAL_TARGET)
hello.o : hello.c
$(CXX) -c $(CFLAGS) $< -o $#
$(CLEANUP_TRIGGER): $(BASE_MAKEFILE)
if [ -f $(CLEANUP_TRIGGER) ]; then $(MAKE) clean; fi
touch $#
clean:
rm -rf *.o
rm -f $(CLEANUP_TRIGGER)
.PHONY: all clean
The essence is to make sure CLEANUP_TRIGGER is part of the rules which get invoked commonly, run make clean whenever Makefile is newer than CLEANUP_TRIGGER.

Resources