在使用make
和bison
的项目中,我很难指定编译的语法grammar.tab.c
依赖于语法输入grammar.y
,即每个目标文件取决于相应的源文件(包括grammar.tab.o
),并且可执行文件依赖于所有目标文件。
问题是当grammar.tab.c尚不存在时运行make
意味着没有尝试构建它,并且当构建可执行文件时,yyparse
函数丢失。< / p>
我的Makefile
是:
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)
如果我改为:
OBJ=$(patsubst %.c, %.o, $(wildcard *.c)) grammar.tab.o
然后它将构建已编译的语法(如果它尚不存在)。但如果确实存在,那么
在构建可执行文件时,会出现两次yyparse
提供错误的错误(大概是因为$OBJ
包含grammar.tab.o
两次)。
我的目标是Makefile:
make
命令上正确构建可执行文件,并根据需要重建中间文件。*.c
个文件(即添加新的源文件时不需要更改)。make
功能,只要它一次只有一两个。其他人的语法构建Makefile如何运作?
编辑好的,这些都是很棒的答案。我选择了滤出器,因为它是最小的变化。我很高兴每个人似乎都知道我正在谈论的内容 - 我很担心被告知使用类似于automake的东西; - )。
谢谢大家。
答案 0 :(得分:5)
对于一般的'run yacc'规则,您需要类似
的内容%.tab.c: %.y
$(YACC) $<
%.tab.h: %.tab.c
@touch $@
获取您想要的所有来源
OBJ=$(sort $(patsubst %.c, %.o, $(wildcard *.c)) $(patsubst %.y, %.tab.o, $(wildcard *.y)))
您需要'排序'主要是为了自动删除重复项
答案 1 :(得分:2)
# 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
答案 2 :(得分:0)
如果您正在使用GNU make,则可以使用过滤出谓词手动从目标的依赖项中排除特定文件。像这样:OBJ=$(filter-out $(grammar.tab.o), $(patsubst %.c, %.o, ...)) grammar.tab.o
。
首先从现有的目标文件中排除grammar.tab.o(可能不存在),然后在所有情况下将其添加回来。不可否认有点迂回,但它的确有效。这就是我们在工作中使用的东西。
答案 3 :(得分:0)
Something like this... you'll have to play around with it. This is kind-sort-a how
I did this in the 90's... it's unconventional but served its purpose
SRCS = foo.c bar.c lex.c yacc.c
OBJS = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.o)
OBJS.d = $(SRCS:%.c=$(OBJ_DEST_DIR)/%.d)
CC_RULE = $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
YACC_RULE = cd $(@D); $(YACC) $(YFLAGS) -o $(@F) $<
LEX_RULE = cd $(@D); $(LEX) $(LEXFLAGS) -o$(@F) $<
CC_DEP_RULE = @echo -n "$(@D)/" > $@;
CC_DEP_RULE += gcc -M $(DEFINES) $(INCLUDES) $< |
CC_DEP_RULE += sed -e 's@:@: $(MAKEFILE_DEPS) @' >> $@;
$(OBJ_DEST_DIR)/%.o: $(OBJ_DEST_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.l
$(LEX_RULE)
$(OBJ_DEST_DIR)/%.c: $(SRC_DIR)/%.y
$(YACC_RULE)
$(OBJ_DEST_DIR)/%.o: $(SRC_DIR)/%.c
$(CC_RULE)
$(OBJ_DEST_DIR)/%.d: $(OBJ_DEST_DIR)/%.c
$(CC_DEP_RULE)
$(OBJ_DEST_DIR)/%.d: $(SRC_DIR)/%.c
$(CC_DEP_RULE)
-include $(OBJS.d)
这是其中一个.d文件的样子
/tmp/builds/objs/opt/libiberty/static/alloca.o: /tmp/src/binutils-2.20/libiberty/alloca.c \
/tmp/src/binutils-2.20/libiberty/config.h \
/tmp/src/binutils-2.20/include/libiberty.h \
/tmp/src/binutils-2.20/include/ansidecl.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stddef.h \
/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/stdarg.h \
/usr/include/stdio.h /usr/include/_types.h /usr/include/sys/_types.h \
/usr/include/sys/cdefs.h /usr/include/machine/_types.h \
/usr/include/i386/_types.h /usr/include/secure/_stdio.h \
/usr/include/secure/_common.h /usr/include/string.h \
/usr/include/secure/_string.h /usr/include/stdlib.h \
/usr/include/Availability.h /usr/include/AvailabilityInternal.h \
/usr/include/sys/wait.h /usr/include/sys/signal.h \
/usr/include/sys/appleapiopts.h /usr/include/machine/signal.h \
/usr/include/i386/signal.h /usr/include/i386/_structs.h \
/usr/include/sys/_structs.h /usr/include/machine/_structs.h \
/usr/include/mach/i386/_structs.h /usr/include/sys/resource.h \
/usr/include/machine/endian.h /usr/include/i386/endian.h \
/usr/include/sys/_endian.h /usr/include/libkern/_OSByteOrder.h \
/usr/include/libkern/i386/_OSByteOrder.h /usr/include/alloca.h \
/usr/include/machine/types.h /usr/include/i386/types.h \
您可以使用MAKEFILE_DEPS变量来插入其他依赖项