make calling bison -y without being asked to

2019-07-28 11:41发布

问题:

I have a grammar I'm writing, called portugol. The files names are basic, but I chose to call my c program portugol.c.

So, basically, I have to do:

flex portugol.l      ==> lex.yy.c
bison -dy portugol.y ==> y.tab.c and y.tab.h
gcc y.tab.c lex.yy.c portugol.c -o portugol.bin -lm -ly  ==> portugol.bin

(I also have portugol.h, but it is irrelevant to the problem)

For long time now, I'm using a shell script I called flexyagcc.sh that do this. No error in the process.

So now I decided to learn makefile.

The problem I'm facing is that for some odd reason, "bison -dy" I called is followed by this command I didn't write: mv -f y.tab.c portugol.c

Well, this destroys my handmade source file!

I've tried all I could, but could not get rid of this "mv".

I even did a sleep and tried:

y.tab.c y.tab.h : portugol.y
    @echo --- bison -----------------------------------------------
    mv -f portugol.c ptg.c
    $(BISON) $(BFLAGS) portugol.y
    @echo --- bison sleeping --------------------------------------
    sleep 5
    -mv -f portugol.c y.tab.c
    -mv -f ptg.c portugol.c

But for my surprise, I got the following events (in this order):

$ make all o=pequeno
--- bison -----------------------------------------------
mv -f portugol.c ptg.c
bison -dy portugol.y
--- bison sleeping --------------------------------------
sleep 5
mv -f portugol.c y.tab.c
mv: cannot stat `portugol.c': No such file or directory
make: [y.tab.c] Error 1 (ignored)
mv -f ptg.c portugol.c
bison -dy portugol.y 
mv -f y.tab.c portugol.c

Surprise! The mv command is the last one! No matter what I do. I created other rules, just to make it happen last (or first to trick the recursive process). No way! I also used the directive: .NOTPARALLEL. No way.

I also tried all in the same line, to be sure they execute in the given order:

mv -f portugol.c ptg.c && $(BISON) $(BFLAGS) portugol.y && sleep 5 && mv -f portugol.c y.tab.c && mv -f ptg.c portugol.c

No success.

Well, before I gave up, I decided to use the standard bison output. So, I would have:

flex portugol.l         ==> lex.yy.c
bison -d portugol.y     ==> portugol.tab.c and y.tab.h
gcc portugol.tab.c lex.yy.c portugol.c -o portugol.bin -lm -ly  ==> portugol.bin

But I still get this:

--- bison -----------------------------------------------
bison -d portugol.y
bison -y portugol.y 
mv -f y.tab.c portugol.c

I also tried to chmod -w before and +w after bison, no way.

For now, I run out of ideas.

Is there a way to prevent make to call the second bison? Or to call the mv command? Or to trick it to not overwrite my file portugol.c?

Thanks! Beco

PS- Edited. Using:

 Ubuntu 10.04.2 LTS
 GNU Make 3.81

PPS. Edited. Minor typos.

PPPS. Edited. Answering Ise wisteria:

Thanks for your answer. I've saved your makefile as makefile2 and tried. The answer I got from the make is:

$ make -f makefile2
bison -dy portugol.y
yacc  portugol.y 
mv -f y.tab.c portugol.c
gcc y.tab.c lex.yy.c portugol.c -o portugol.bin -lm -ly
gcc: y.tab.c: No such file or directory
make: *** [portugol.bin] Error 1

I also noted that "today" the second bison call is not a bison call, but a yacc call. Maybe we are talking about some environment variable here? It also changes with my makefile:

$ make all o=pequeno
--- bison -----------------------------------------------
bison --defines=y.tab.h --output=y.tab.c portugol.y
--- flex ------------------------------------------------
flex  portugol.l
yacc  portugol.y 
mv -f y.tab.c portugol.c

PPPPS. Answering Beta. Your advice works. I called make y.tab.c and got a simple:

$ make y.tab.c
--- bison -----------------------------------------------
bison --defines=y.tab.h --output=y.tab.c portugol.y
$

Here is my complete makefile:

# Compila o compilador Portugol usando lex e yacc,
# e opcionalmente gera o .asm.c e o .bin
# a partir do fonte .ptg usando o novo compilador gerado.
#
#/*
#    arquivo: makefile
#    Autor: Ruben Carlo Benante
#    Email: ***@beco.cc
#    Data: 23/04/2009
#    Modificado: 22/03/2011
#    Versao: Portugol v3q
#*/
#
# Exemplo:
# ./flexyagcc portugol teste
#
# inicia os seguintes processos:
#      flex portugol.l                                          (gera lex.yy.c)
#      bison -dy portugol.y                                     (gera yy.tab.c e yy.tab.h)
#      gcc y.tab.c lex.yy.c portugol.c -o portugol.bin -lm -ly  (gera portugol.bin)
#
# inicia opcionalmente (ultimas linhas descomentadas):
#      portugol.bin teste.ptg teste.asm.c                (gera teste.asm.c)
#      gcc -x c teste.asm.c -o teste.bin -lm             (gera teste.bin)
#
#
# entrada:
#          portugol.l (arquivo em linguagem lex, analisador lexico)
#          portugol.y (arquivo em linguagem yacc, analisador sintatico)
#          portugol.c (arquivo em linguagem c, gerador de codigo)
# entrada opcional:
#          teste.ptg  (arquivo em linguagem portugol)
#
# saida:
#        lex.yy.c (saida do lex, em linguagem c)
#        y.tab.c  (saida do yacc, em linguagem c)
#        y.tab.h  (saida do yacc, definicoes da linguagem portugol)
#        portugol.bin (saida do gcc, arquivo executavel, finalmente o compilador portugol)
# saida opcional:
#        teste.asm.c   (saida do compilador portugol, arquivo em codigo de quadruplas)
#        teste.bin     (saida do gcc, arquivo executavel, o fonte .ptg em binario)
#
###################################### 
LEX     = flex
BISON = bison
BFLAGS  = --defines=y.tab.h --output=y.tab.c
CC = gcc
#CFLAGS = -g0 -O3 -Wall
CFLAGS = -g0
OBJS = y.tab.o lex.yy.o portugol.o
#OBJS = portugol.tab.o lex.yy.o portugol.o
DEPS =  portugol.h y.tab.h
SOURCES = y.tab.c lex.yy.c portugol.c
#SOURCES = portugol.tab.c lex.yy.c portugol.c

.PHONY : clean cleanall cleanptg run all makebug teste

.NOTPARALLEL :

#portugol.bin : lex.yy.c y.tab.c y.tab.h portugol.c portugol.h
portugol.bin : $(SOURCES) $(DEPS) $(OBJS)
    @echo --- gcc portugol ----------------------------------------
    $(CC) $(CFLAGS) $(OBJS) -o portugol.bin -lm -ly
#   gcc lex.yy.c y.tab.c portugol.c -o portugol.bin -lm -ly
#   $(CC) $(CFLAGS) $(SOURCES) -o portugol.bin -lm -ly

%.o : %.c
    @echo --- gcc objects -----------------------------------------
    $(CC) $(CFLAGS) -c $< -o $@

#portugol.tab.c y.tab.h : portugol.y
y.tab.c y.tab.h : portugol.y
    @echo --- bison -----------------------------------------------
    $(BISON) $(BFLAGS) portugol.y
#   @echo --- bison y.tab.c ---------------------------------------
#   mv -f portugol.c ptg.c
#   sleep 3
#   -mv -f portugol.c y.tab.c
#   -mv -f ptg.c portugol.c

lex.yy.c : portugol.l
    @echo --- flex ------------------------------------------------
    $(LEX) $(LFLAGS) portugol.l

teste :
    @echo --- testing ---------------------------------------------
    @echo $(o)

#Portugol -----------

%.asm.c : %.ptg portugol.bin
    @echo --- portugol --------------------------------------------
    ./portugol.bin $< $@

%.bin : %.asm.c
    @echo --- gcc asm ---------------------------------------------
    $(CC) -x c $< -o $@ -lm

run : $(o).bin
    @echo --- running! --------------------------------------------
    ./$(o).bin

all : $(o).bin

clean:
    -rm lex.yy.c y.tab.c y.tab.h *.o portugol.bin portugol.tab.c

cleanall:
    -rm lex.yy.c y.tab.c y.tab.h *.o *.bin

cleanasm:
    -rm *.asm.c

VPS. Important edit update. Attention for a possible indication of the real problem:

I changed the name portugol.y to portugol.syn and the problem has stoped!

--- bison -----------------------------------------------
bison --defines=y.tab.h --output=y.tab.c portugol.syn
---------------------------------------------------------

How is that? This indicates, in my opinion, that make has some default evaluation for files ".y" and now we need, to answer this question, to find out the root of this, and how to disable it. Thanks very much.

回答1:

The problem is that make has built-in rules for building .c files from .y and .l files, and it is these builtin rules that are getting triggered and causing you grief.

With GNU make, you can disable these builtin rules by overriding them with blank rules. Put

%.c: %.y
%.c: %.l

in your makefile somewhere and your problems should go away.

You can see all of GNU make's built-in rules by running make -p -f /dev/null



回答2:

Basically, do not try to fight the system. You need to be able to create portugol.o - and have three possible source files: portugol.l, portugol.y, portugol.c. That is at least two too many.

Make sure that the basenames of the source files (minus the extension) are unique. For example, use portugoll.l, portugoly.y, and portugol.c, with object files portugoll.o, portugoly.o and portugol.o. Or use longer suffixes - portugol-lex.l, portugol-yacc.y. Or portlex.l, portyacc.y, or ...



回答3:

Thank you Jonathan,

So you see the one solution I've also perceived: change the name of the file. But, well, that is the point of the question. I have no problems using the script. If I call bison -dy portugol.y from the shell script flexyagcc.sh it gives me y.tab.c and y.tab.h. Why not from a makefile, that is the central point!

I do like my file names, it makes all so coherent: portugol.c: handmade routines, portugol.h:header file, portugol.l:lex scanner, and portugol.y: parser. Also, this is not a project I made today, it has being like that for years now, lots of versions (now 3.0). So, it is not an option to change the file names. Beside that, I would end up with portugol.c anyway! But it would be a file automatically generated from bison, aka y.tab.c. So, it is very confusing to stop using portugol.c to have handmade routines, and start using the same name to have the parser.

I just want to know what is happening with makefile, and how can I use it to substitute the script the way it is. While I can't, unfortunately, I'll be using the script. The script is very simple:

flex portugol.l
bison -dy portugol.y
gcc y.tab.c lex.yy.c portugol.c -o portugol.bin -lm -ly

See, I don't even bother to have the objectives portugol.o, y.tab.o and lex.yy.o. I skip creating them by just running the gcc on the sources directly. I also can do this in the makefile, if after the first attempt to destroy my portugol.c, I rename manually the file created to be y.tab.c.

So the problem is that makefile differs from the above script by attempting to create the following:

  • lex the same: portugol.l for both cases (script and makefile)
  • bison: automagically changed from y.tab.c to portugol.c (here the problem!)
  • c code: I would need to change portugol.c to something else, like portugol-funcs.c

Thanks for your kind attention! Beco



回答4:

Strangely, as far as I tested with small improvised files, the problem you mentioned didn't occur. My make's version is GNU 3.80.
For your information, the following is the makefile I used.

portugol.bin: y.tab.c lex.yy.c portugol.c
        gcc $^ -o $@ -lm -ly

y.tab.c: portugol.y
        bison -dy $<

lex.yy.c: portugol.l
        flex $<

Hope this helps