I'm using a makefile to build my flex/bison project. I'm having problems as it is adding a call to yacc and a mv command thus overwriting one of my files.
user#dk ~/calc ±master⚡ » make clean
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
user#dk ~/calc ±master » make
bison -d calc.y
flex calc.lex
g++ -o calc calc.tab.c lex.yy.c calc.c
user#dk ~/calc ±master⚡ » make clean
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
user#dk ~/calc ±master » touch calc.y
user#dk ~/calc ±master » make
bison -d calc.y
flex calc.lex
yacc calc.y
mv -f y.tab.c calc.c
g++ -o calc calc.tab.c lex.yy.c calc.c
... Failure ...
I simplified the makefile to the bare minimum to reproduce this. Using bison to create two files: calc.tab.c and calc.tab.h. I do not have the .h file as a target as I'm not sure what the correct way to do that is. The call to bison will generate both of the calc.tab.* files so that is not my main concern.
What is the correct way to structure this makefile to avoid the calls to yacc and mv from being generated?
calc: calc.tab.c lex.yy.c calc.c
g++ -o calc calc.tab.c lex.yy.c calc.c
calc.tab.c: calc.y
bison -d calc.y
lex.yy.c: calc.lex calc.tab.h
flex calc.lex
clean:
rm -rf lex.yy.c calc.tab.h calc.tab.c calc
The mv comes from make's built-in rules, which contain:
%.c : %.y
$(YACC.y) $<
mv -f y.tab.c $#
It looks like make is trying to create calc.c from calc.y. Some solutions to this are to redefine that rule yourself, or rename calc.y to something that won't trigger that rule for calc.c, or disable make's built-in rules.
You can list all built-in rules with make -p.
Related
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.
I have the following simple makefile
#all: binsem.a ut.a ph
FLAGS = -Wall -L./
binsem.a:
gcc $(FLAGS) -c binsem.c
ar rcu libbinsem.a binsem.o
ranlib libbinsem.a
ut.a:
gcc $(FLAGS) -c ut.c
ar rcu libut.a ut.o
ranlib libut.a
clean:
rm -f *.o
rm -f a.out
rm -f *~
rm -f ph
rm -f *a
The problem is it only generates binsem.a and not ut.a, probably because of dependencies issues.
I tried looking at the flags but did not find the answer.
Thanks a lot.
By default, if you don't specify a target on the command line, make will build the first target it finds (and it's dependencies if it has any). Your first target is binsem.a, and you don't list any dependencies, so that's the only thing that gets built.
Try something like adding this at the top:
all: binsem.a ut.a
And mention the dependencies in your other targets:
binsem.a: binsem.c
...
ut.a: ut.c
Here's my makefile:
all: lex yacc compile
lex: sql.l
lex -i sql.l
yacc: sql.y
yacc -d -v sql.y
compile: y.tab.c lex.yy.c
$(CC) -o sql_parser y.tab.c lex.yy.c -ly -ll
test: all
#./parsesql.sh selecttest.sql
#./parsesql.sh insertintotest.sql
#./parsesql.sh deletefromtest.sql
#./parsesql.sh createtest.sql
cleanup:
rm test.tab.cacc
rm y.output
Running make will always trigger a full recompile, even if nothing has changed:
parsesql> make
lex -i sql.l
yacc -d -v sql.y
cc -o sql_parser y.tab.c lex.yy.c -ly -ll
parsesql> make
lex -i sql.l
yacc -d -v sql.y
cc -o sql_parser y.tab.c lex.yy.c -ly -ll
parsesql> make
lex -i sql.l
yacc -d -v sql.y
cc -o sql_parser y.tab.c lex.yy.c -ly -ll
None of the files have changed, so why is it doing this? The lex and yacc commands should only trigger if sql.l or sql.y respectively have changed, no?
Your targets are all not real files. Make them the names of the actual files you're generating so that make can find them and check timestamps.
Example:
all: sql_parser
lex.yy.c: sql.l
lex -i sql.l
y.tab.c: sql.y
yacc -d -v sql.y
sql_parser: y.tab.c lex.yy.c
$(CC) -o sql_parser y.tab.c lex.yy.c -ly -ll
test: all
#./parsesql.sh selecttest.sql
#./parsesql.sh insertintotest.sql
#./parsesql.sh deletefromtest.sql
#./parsesql.sh createtest.sql
cleanup:
rm test.tab.cacc
rm y.output
You can add .PHONY: all test cleanup to indicate to make that those targets are not intended to be real files.
There is a given r-tree code by Toni Guttman(it's been modified for my homework), however, if I change an parameter(the dimension of the node), then "make" will cause such errors:
yacc y.spec
make: yacc:command not found
make: *** [y.tab.c] error 127
I've installed bison and flex, and "which yacc" shows that
alias yacc='bison'
/usr/bin/bison
What should I do to solve the problem?
Here is the "Makefile":
# %W% %G%
# use flag -O for optimized code, slower compile
FLAGS=
SRC= main.c index.c newtid.c node.c rectangle.c \
printstats.c clock.c y.spec allocate.c error.c\
split.l.c \
split.q.c \
split.e.c
HEADERS= options.h macros.h index.h assert.h
ALL= $(SRC) $(HEADERS) split.l.h split.q.h split.e.h
OBJ= main.o index.o newtid.o node.o rectangle.o \
printstats.o clock.o y.tab.o allocate.o error.o
OBJLIN= split.l.o
OBJQ= split.q.o
OBJEXP= split.e.o
$(OBJ): $(HEADERS)
$(OBJLIN): $(HEADERS) split.l.h
$(OBJQ): $(HEADERS) split.q.h
$(OBJEXP): $(HEADERS) split.e.h
# assembler chokes if graphics.c is compiled with -g option, do it without.
# graphics.o: graphics.c $(HEADERS)
# cc -c graphics.c
# assembler chokes if y.tab.c is compiled with -g option, do it without.
# y.tab.o: y.tab.c $(HEADERS)
# cc -c y.tab.c
.c.o: $(HEADERS)
cc -c $(FLAGS) $*.c
linear: $(OBJ) $(OBJLIN)
cc $(FLAGS) $(OBJ) $(OBJLIN) -lm -o linear
quad: $(OBJ) $(OBJQ)
cc $(FLAGS) $(OBJ) $(OBJQ) -lm -o quad
exp: $(OBJ) $(OBJEXP)
cc $(FLAGS) $(OBJ) $(OBJEXP) -lm -o exp
y.tab.c: y.spec $(HEADERS)
yacc y.spec
edit:
sccs edit $(SRC) $(HEADERS) split.l.h split.q.h split.o.h
unedit:
sccs unedit $(ALL)
rm -f tags
delta:
sccs delta $(ALL)
rm -f tags
get:
sccs get $(ALL)
clean:
rm -f *.o core y.tab.c tags
tags: $(SRC)
ctags *.c
lint:
rm -f lint.out
lint *.c > lint.out
You don't have yacc installed, as you've seen. Changing an alias in your shell won't help, because it's make that is trying to run the yacc command, not the shell. You have to edit your makefile, and add a line like:
YACC = bison -y
(the -y flag makes bison behave like yacc)
Since you didn't show your actual makefile we can't be sure that this will do it, but it's likely.
EDIT:
I your makefile above, change the reference to yacc to say bison -y instead.
Your makefile is not following many best practices but that's for another day.
manually add this script /usr/bin/yacc is simply a script containing:
#! /bin/sh
exec '/usr/bin/bison' -y "$#"
If I erase the gcc lines from this file shouldn't it take compilation as the implicit rule? Why isn't it allowing me to run the program ./calc with that makefile configuration?
Makefile:
all: calc
clean:
rm -rf calc arit.o calc.o
calc: calc.o arit.o
#gcc -o calc calc.o arit.o
calc.o: calc.c arit.h
#gcc -c calc.c
arit.o: arit.c arit.h
#gcc -c arit.c
Because the comment is indented by a tab stop, it is treated as a command (and executed by the shell, which treats it as a comment).
If the '#' symbols were in column 1, then they would be pure (make) comments.
Further to Jonathan Leffler's answer, the following minimal GNUMakefile should do all compilation and linking through implicit rules only:
calc: calc.o arit.o
arit.o: arit.c arit.h
calc.o: calc.c arit.h
clean:
rm -rf calc arit.o calc.o