问题描述
我正在尝试对使用 GNU bison & flex 的项目使用源外构建进行解析和词法分析。
Build 由 GNU Make 管理,一切都很顺利,直到我将逻辑从主 .y
文件分离到一个新的 .c
文件。
Makefile 来自 this post。
主要问题是 .tab.h
是由 bison 生成的,它是在 build 目录中生成的:./build/src/parser.tab.h
。
通过使用相对路径 .tab.h
包含 #include "../build/src/parser.tab.h"
并将 .tab.c
添加到 C 文件的依赖项,我设法以临时方式解决了这个问题。
这被认为是一个好习惯吗?
有没有办法在 Makefile 中隐式声明这一点和/或包含生成的 .tab.h
文件?
这是我的 C 文件:
#include "../build/src/parser.tab.h"
int main(int argc,char *argv[])
{
yyparse();
return 0;
}
和Makefile
:
TARGET_EXEC := parser
BUILD_DIR := ./build
SRC_Dirs := ./src
SRCS := $(shell find $(SRC_Dirs) -name *.c -or -name *.y -or -name *.l)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)
INC_Dirs := $(shell find $(SRC_Dirs) -type d)
INC_FLAGS := $(addprefix -I,$(INC_Dirs))
CC := gcc
CFLAGS := -O0 -Wall -Wextra -Wpedantic -std=c17
CPPFLAGS := $(INC_FLAGS) -MMD -MP
LDFLAGS := -ly -ll
YACC := bison
YFLAGS := -d
LEX := flex
LFLAGS :=
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
$(BUILD_DIR)/%.c.o: %.c build/src/parser.tab.c
mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
%.y.o: %.tab.c
mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
%.l.o: %.yy.c
mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/%.tab.c: %.y
mkdir -p $(dir $@)
$(YACC) $(YFLAGS) $< -o $@
$(BUILD_DIR)/%.yy.c: %.l
mkdir -p $(dir $@)
$(LEX) $(LFLAGS) -o $@ $<
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
-include $(DEPS)
这里是 MWE 词法分析器和解析器:
%{
#include "parser.tab.h"
#include <stdio.h>
%}
ws [ \t]+
%%
{ws} { ; } // skip whitespaces
. { printf("unkNown token %c\n",yytext[0]); }
%%
prgm: ;
前后树:
.
├── Makefile
├── build
│ ├── parser
│ └── src
│ ├── lexer.l.d
│ ├── lexer.l.o
│ ├── lexer.yy.c
│ ├── main.c.d
│ ├── main.c.o
│ ├── parser.tab.h
│ ├── parser.y.d
│ └── parser.y.o
└── src
├── lexer.l
├── main.c
└── parser.y
.
├── Makefile
└── src
├── lexer.l
├── main.c
└── parser.y
解决方法
首先,您的 makefile 比实际需要的更令人困惑,因为您在某些地方使用了 $(BUILD_DIR)
变量,而在其他地方使用了硬编码的 build
:在任何地方都使用该变量。
第二,不,您不应该在源文件中包含路径。这意味着每当您更改 makefile 以移动某些内容时,您也必须编辑源文件。
相反,只需将搜索头文件的路径添加到编译器命令行即可。您已经有一个 INC_FLAGS
变量,其中包含告诉编译器在哪里查找头文件的选项;只需添加一个新的:
INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -I$(BUILD_DIR)/src
现在您可以在源代码中使用 #include "y.tab.h"
。