我正在使用Bison和Flex构建解析器。要编译所有内容,我使用一个简单的makefile。但是,我不是创建makefile的专家。 makefile正在运行,除了以下几点:
makefile未检测到file.cpp中的更改源代码。
无所事事。
make 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
答案 0 :(得分:2)
将file.cpp
作为要构建的cpp文件的依赖项。当你改变file.cpp
时,这将使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.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)
答案 1 :(得分:2)
你的一个问题是这个
a b: c
do something
makefile
中的表示:
a
取决于c
;要构建它,请运行do something
b
取决于c
;要构建它,请运行do something
不是,正如您所希望的那样,a
和b
都是do something
的结果。由于您同时将parser.tab.cpp
和parser.tab.hpp
作为显式依赖项(分别用于parser
和lex.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文件