views:

256

answers:

3

In a project that uses make and bison, I'm having difficulty specifying that the compiled grammar grammar.tab.c depends on the grammar input grammar.y, that each object file depends on a corresponding source file (including grammar.tab.o), and that the executable depends on all object files.

The problem is that running make when grammar.tab.c does not yet exist means that there is no attempt to build it, and when the executable is built the yyparse function is missing.

My Makefile is:

CFLAGS = -g -Wall
YACC = bison -d -r all
OBJ=$(patsubst %.c, %.o, $(wildcard *.c))
HEADERS=grammar.tab.h hex.h compiler.h types.h

all: grammar.tab.h c

clean:
    rm -f $(OBJ) *.tab.c *.tab.h c c.exe *.output

c: $(OBJ)
    $(CC) -o $@ $(OBJ) $(CFLAGS)

grammar.tab.c: grammar.y
    $(YACC) grammar.y

grammar.tab.h: grammar.y
    $(YACC) grammar.y

%.o: %.c $(HEADERS)
    $(CC) -c $< $(CFLAGS)

If I change it with:

OBJ=$(patsubst %.c, %.o, $(wildcard *.c)) grammar.tab.o

Then it will build the compiled grammar if it doesn't already exist. But if it does already exist, then when building the executable, there will be an error about yyparse being provided twice (presumably because $OBJ contains grammar.tab.o twice).

What I'm aiming for is a Makefile that:

  1. Will correctly build the executable on a make command, rebuilding intermediate files as necessary.
  2. Will pick up all *.c files in the directory (i.e. doesn't need to be changed when new source files are added).
  3. Is easy to read and understand. I don't mind learning new make features as long as it's only one or two at a time.

How do others' grammar-building Makefiles work?

Edit Ok, those are great answers. I went with the filter-out one, since it was the smallest change. I'm really glad that everyone seemed to know exactly what I'm talking about -- I was apprehensive about being told to use something byzantine like automake ;-).

Thanks everyone.

+2  A: 

If you're using GNU make, you can use the filter-out predicate to manually exclude a particular file from the dependencies of a target. Like so: OBJ=$(filter-out $(grammar.tab.o), $(patsubst %.c, %.o, ...)) grammar.tab.o.

You first exclude grammar.tab.o from the existing object files (it might not be there), then add it back in all cases. Admittedly a bit roundabout, but it works. That's what we use at work.

Arthur Reutenauer
+2  A: 
# you can consolidate both rules into one:
grammar.tab.c grammar.tab.h: grammar.y
        $(YACC) grammar.y

# but I find ``make'' more workable without many-to-one target-to-prerequisites
grammar.tab.c: grammar.tab.h
        touch $@
grammar.tab.h: grammar.y
        $(YACC) $<


# your problem, though, does seem to be with linking ``grammar.tab.o''

# you can exclude grammar.tab.o
OBJ =: $(filter-out grammar.tab.o,$(patsubst %.c,%.o,$(wildcard *.c))) grammar.tab.o

# you can remove duplicates from $(OBJ)
OBJ =: $(sort $(patsubst %.c,%.o,$(wildcard *.c)) grammar.tab.o)

# you can remove duplicates when linking
c: $(OBJ)
        $(CC) $(LDFLAGS) -o $@ $(sort $^) $(LDLIBS)

# but personally, I prefer not to use $(wildcard) at all,
# explicitly updating the makefile as needed
ephemient
I have wondered whether a largish but simple Makefile that spells out correct and minimal dependencies for all files would be a good approach to take. Something to consider if things get more complicated, perhaps.
Edmund
+3  A: 

For the general 'run yacc' rule you want something like

%.tab.c: %.y
        $(YACC) $<

%.tab.h: %.tab.c
        @touch $@

To get all the sources you want

OBJ=$(sort $(patsubst %.c, %.o, $(wildcard *.c)) $(patsubst %.y, %.tab.o, $(wildcard *.y)))

You need the 'sort' mostly for its automatic removal of duplicates

Chris Dodd
Cool trick, I didn't know sort.
Arthur Reutenauer
Why don't you upvote the answer then?
Kinopiko
What makes you think I didn't? ;-)
Arthur Reutenauer