2

我正在使用 Bison 和 Flex 构建解析器。为了编译所有内容,我使用了一个简单的 makefile。但是,我不是创建 makefile 的专家。makefile 正在工作,除了一些事情:

makefile 未检测到更改 file.cpp 中的源代码。 无计可施。 Amake clean解决了这个问题,但这当然不是必需的。我找到了很多makefile教程,但没有任何讨论此类问题。

CC=g++
CFLAGS=-Wall -std=c++11 -ll
EXECUTABLE=parser 
OBJS=parser.tab.cpp lex.yy.c 

FILES= file.cpp

all: parser

parser.tab.cpp parser.tab.hpp: parser.ypp
    bison -d parser.ypp

lex.yy.c: parser.l parser.tab.hpp
    flex parser.l

parser: $(OBJS) $(FILES)
    $(CC) $(CFLAGS) $(OBJS) $(FILES) -o $(EXECUTABLE) 

clean:
    rm -rf *o $(EXECUTABLE) $(OBJS)

当然,我可以使用make -B all,然后我发现了一些奇怪的东西:

bison -d parser.ypp
bison -d parser.ypp
flex parser.l
g++ -Wall -std=c++11 -ll parser.tab.cpp lex.yy.c file.cpp -o parser

为什么bison -d parser.ypp要做两次?

[解决了]

我们现在使用以下makefile:

CC = g++
CFLAGS = --std=c++0x -O2

SOURCES = $(wildcard */*.cpp *.cpp) parser/parser.cpp
OBJECTS = $(SOURCES:.cpp=.o) scanner/scanner.o parser/parser.o

EXECUTABLE = calculator

all: parser/parser.cpp scanner/scanner.cpp $(EXECUTABLE)

parser/parser.cpp:
    cd parser && bison -d -o parser.cpp grammar.ypp && cd ..

scanner/scanner.cpp: parser/parser.hpp
    cd scanner && flex -o scanner.cpp lexer.l && cd ..

$(EXECUTABLE): $(OBJECTS)
    $(CC) $^ -o "$@"

%.o: %.cpp
    $(CC) $(CFLAGS) -c "$<" -o "$@"

clean:
    rm -rf $(OBJECTS) $(EXECUTABLE) parser/parser.cpp parser/parser.hpp scanner/scanner.cpp
4

2 回答 2

2

file.cpp作为要构建的 cpp 文件的依赖项。这将使 makefile 在您更改时编译这两个文件file.cpp

CC=g++
CFLAGS=-Wall -std=c++11 -ll
EXECUTABLE=parser 
OBJS=parser.tab.cpp lex.yy.c 

FILES= file.cpp

all: parser

parser.tab.cpp : parser.ypp $(FILES)
    bison -d parser.ypp

lex.yy.c: parser.l parser.tab.hpp $(FILES)
    flex parser.l

parser: $(OBJS) $(FILES)
    $(CC) $(CFLAGS) $(OBJS) $(FILES) -o $(EXECUTABLE) 

clean:
    rm -rf *o $(EXECUTABLE) $(OBJS)
于 2013-06-18T09:52:48.333 回答
2

你的问题之一是这个

 a b: c
    do something

在一个makefile说:

  • a取决于c; 构建它,运行do something
  • b取决于c; 构建它,运行do something

不像您可能希望的那样,这a两者b都是由do something. 由于您同时拥有parser.tab.cppparser.tab.hpp作为显式依赖项(分别为parserlex.yy.c),make因此将构建它们,并两次运行相同的命令(如果您尝试并行构建,这会很有趣)。

如果你有能力改变你的构建系统,你可能想看看Scons,它更直观地做到了这一点。

我也倾向于分解你的制作,以便每个 .o 都是独立构建的,所以你有这样的东西:

file.o: file.cpp
lex.yy.o: lex.yy.c parser.tab.hpp

parser: lex.yy.o parser.tab.o file.o

因为这意味着它不太可能重建你不想要的东西,而更有可能重建你想要的东西——如果你改变了 .hpp,你真的不想重建 lex.yy.c。但是您确实想重建 .o 文件

于 2013-06-18T10:18:31.243 回答