EL_9
EL_9

Reputation: 414

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.

Upvotes: 0

Views: 1921

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 28910

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.

Upvotes: 1

Related Questions