使用make生成bison语法

发布于 2024-08-10 03:25:24 字数 1377 浏览 1 评论 0原文

在使用 makebison 的项目中,我很难指定编译的语法 grammar.tab.c 取决于语法输入grammar.y,每个目标文件都依赖于相应的源文件(包括grammar.tab.o),并且可执行文件依赖于所有目标文件。

问题是,在 Grammar.tab.c 尚不存在时运行 make 意味着不会尝试构建它,而当构建可执行文件时,yyparse 函数是丢失的。

我的 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:

  1. 将在 make 命令上正确构建可执行文件,并根据需要重建中间文件。
  2. 将拾取目录中的所有 *.c 文件(即添加新源文件时不需要更改)。
  3. 易于阅读和理解。我不介意学习新的 make 功能,只要一次只学习一两个即可。

其他人的语法构建 Makefile 是如何工作的?

编辑好的,这些都是很好的答案。我选择了过滤器,因为这是最小的改变。我真的很高兴每个人似乎都确切地知道我在说什么——我很担心被告知使用像 automake 这样的拜占庭式的东西;-)。

谢谢大家。

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 
lt; $(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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

听风吹 2024-08-17 03:25:24

对于一般的“运行 yacc”规则,您需要类似的内容

%.tab.c: %.y
        $(YACC) 
lt;

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

要获取所需的所有源,

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

您需要“排序”主要是为了自动删除重复项

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

%.tab.c: %.y
        $(YACC) 
lt;

%.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

小清晰的声音 2024-08-17 03:25:24
# 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) 
lt;


# 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
# 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) 
lt;


# 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
哆啦不做梦 2024-08-17 03:25:24

如果您使用的是 GNU make,则可以使用过滤谓词手动从目标的依赖项中排除特定文件。像这样:OBJ=$(filter-out $(grammar.tab.o), $(patsubst %.c, %.o, ...)) Grammar.tab.o

首先从现有对象文件中排除 Grammar.tab.o(它可能不存在),然后在所有情况下将其添加回来。诚然有点迂回,但它确实有效。这就是我们在工作中使用的。

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.

相对绾红妆 2024-08-17 03:25:24
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 $@ 
lt;
YACC_RULE     = cd $(@D); $(YACC) $(YFLAGS) -o $(@F) 
lt;
LEX_RULE      = cd $(@D); $(LEX) $(LEXFLAGS) -o$(@F) 
lt;
CC_DEP_RULE   = @echo -n "$(@D)/" > $@;
CC_DEP_RULE   += gcc -M $(DEFINES) $(INCLUDES) 
lt; |
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 变量来插入其他依赖项

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 $@ 
lt;
YACC_RULE     = cd $(@D); $(YACC) $(YFLAGS) -o $(@F) 
lt;
LEX_RULE      = cd $(@D); $(LEX) $(LEXFLAGS) -o$(@F) 
lt;
CC_DEP_RULE   = @echo -n "$(@D)/" > $@;
CC_DEP_RULE   += gcc -M $(DEFINES) $(INCLUDES) 
lt; |
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)

This is what one of the .d files will look like

/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 \

You can play around with the MAKEFILE_DEPS variable to insert other dependencies too

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文