Search code examples
cmakefilebisonflex-lexeryacc

Makefile automatically call `yacc`


Hi I have a makefile like this:

# Variables =====================================================================================
PHONY           = 
proj            = 

ALL_FILES   := $(filter $(proj).%,$(shell ls | grep "^$(proj)\.[a-z]*$$"))
LEX_FILE    := $(filter %.l, $(ALL_FILES))
BISON_FILE  := $(filter %.y, $(ALL_FILES))
C_FILE      := $(filter %.c, $(ALL_FILES))
H_FILE      := $(filter %.h, $(ALL_FILES))

BISON_OUT_H := $(subst .y,.tab.h,$(BISON_FILE)) 
BISON_OUT_C := $(subst .y,.tab.c,$(BISON_FILE))
BISON_OUT   := $(BISON_OUT_C) $(BISON_OUT_H)
LEX_OUT     := $(subst .l,.yy.c,$(LEX_FILE))
LEX_TRG     := $(LEX_FILE)
LEX_DEP     := $(LEX_FILE) $(BISON_OUT_H)
GCC_TRG     := $(BISON_OUT_C) $(LEX_OUT) $(C_FILE) 
GCC_DEP     := $(GCC_TRG) $(H_FILE) $(BISON_OUT_H)


CFLAGS      = -g
test:
    @echo $(proj)
    @echo $(ALL_FILES)
    @echo $(LEX_FILE)
    @echo $(BISON_FILE)
    @echo $(C_FILE)
    @echo $(BISON_OUT_C)
    @echo $(LEX_OUT)
    @echo $(GCC_TRG)
    @echo $(GCC_DEP)
# Flex ==========================================================================================
$(LEX_OUT):$(LEX_DEP)
ifneq (,$(LEX_TRG))
    flex --outfile=$@ $(LEX_TRG)
endif

# Bison =========================================================================================
$(BISON_OUT):$(BISON_FILE)
ifneq (,$(BISON_FILE))
    bison -d $<
endif

# Run ===========================================================================================
$(proj).out:$(GCC_DEP)
ifneq (,$(GCC_TRG))
    gcc $(CFLAGS) $(GCC_TRG) -o $@
endif

run:$(proj).out
    ./$<

run_lex:$(proj).out
    @echo "Please type in file names: "; \
    read file; \
    ./$< $$file

PHONY += run run_wc run_lex
# Clean =========================================================================================
clean:
    -rm *.out *.lex *.yy.c *.tab.h *.tab.c *.s
cleansp:
    -rm $(proj).out $(proj).lex $(BISON_OUT) $(LEX_OUT)

PHONY += clean cleansp
# GitHub ========================================================================================
commit: clean
    git add -A
    @echo "Please type in commit comment: "; \
    read comment; \
    git commit -m"$$comment"
sync: commit 
    git push -u origin master

PHONY += commit sync
# PHONY =========================================================================================
.PHONY: $(PHONY)

In the current folder I have

[shore@shore-82b6 flex-bison]$ ls
calc2.c  calc2.h  calc2.l  calc2.tab.c  calc2.tab.h  calc2.y  calc2.yy.c  calc.l  calc.y  ccr.l  lc.l  makefile  Note.md  samples  st.l  wc.l

The thing vary confused me is that when I run make run proj=calc2, if calc.y is changed then the make file will run extra instructions and output to calc.c as a result. The following is the shell output:

[shore@shore-82b6 flex-bison]$ make run proj=calc2
bison -d calc2.y
flex --outfile=calc2.yy.c calc2.l
yacc  calc2.y 
mv -f y.tab.c calc2.c
calc2.yy.c calc2.tab.c calc2.c

Notice this will only happen if calc.y is changed.

So how should I fix this and letting the makefile run the instructions suppose to be in my makefile.


Solution

  • You are being bitten by one of make's built-in rules:

    %.c: %.y
    #  recipe to execute (built-in):
             $(YACC.y) $<
             mv -f y.tab.c $@
    

    This says, "if I have a file foo.y and I want to build a file foo.c, here's how to do it". This is the normal naming convention for building yacc files.

    In your situation you have a file calc2.y which is the yacc file and another file calc2.c which is a normal source file, but make doesn't know that it's a normal source file.

    If you want to have your calc2.y not be related to your calc2.c, and instead have calc2.y be related only to calc2.tab.c, you'll have to cancel the built-in rule by declaring it without any recipe like this:

    %.c: %.y