Я будую парсер, використовуючи Bison і Flex. Щоб скомпілювати все, я використовую простий файл makefile. Файл makefile працює, за винятком декількох речей:
Зміна вихідного коду у файлі file.cpp не виявляється за допомогою makefile.
Нічого не можна зробити.
А. 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
Відповіді:
2 для відповіді № 1Покласти file.cpp
як залежність для збирання файлів cpp. Це зробить файл make для компіляції цих двох файлів при зміні u 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)
2 для відповіді № 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
будуватиме обидва з них і двічі запускати ту ж команду (це буде цікаво, якщо ви намагаєтеся побудувати паралельно).
Якщо ви можете дозволити собі змінити систему збирання, ви можете подивитися на Сплани що робить це трохи більш інтуїтивно.
Я також хотів би трохи розбити вашу марку, щоб кожен .o був побудований незалежно, так що ви маєте щось подібне:
file.o: file.cpp
lex.yy.o: lex.yy.c parser.tab.hpp
parser: lex.yy.o parser.tab.o file.o
тому що це означає, що він менш схильний до відновлення речейви не хочете і більше ймовірно, щоб відновити речі, які ви хочете - ви дійсно не хочете, щоб відновити.