среда, 27 апреля 2011 г.

GNU Make и автоматическая генерация зависимостей для файлов исходного кода C/C++

Для знающих проблема известная и давно решённая, но я с этим столкнулся только сегодня.

Итак, у нас имеется небольшой проект на C/C++, который собирается с помощью make. Пусть это будет программа под названием «program». В Makefile написано примерно следующее:
OUT = program

CXXFLAGS = -Wall -c -O2

SRC = $(wildcard *.cpp)
# Expand SRC wildcard and replace extension from .cpp to .o
OBJ = $(patsubst %.cpp, %.o, $(SRC))

$(OUT): $(OBJ)
    $(CXX) -o $(OUT) $(OBJ)
Когда мы изменяем какой-нибудь файл исходного кода foo.cpp и собираем проект, всё работает как часы: make замечает изменение foo.cpp, заново его (и только его) компилирует и запускает линковщик. Но make не замечает изменений в заголовочном файле foo.h, который подключается из foo.cpp.

Лобовой способ поправить положение добавить все заголовочные файлы в зависимости ко всем  файлам исходного кода:
foo.cpp bar.cpp: foo.hpp baz.hpp bar.hpp
Это сработает, но заставит make компилировать ВСЕ файлы исходного кода, даже если изменился всего один заголовочный файл.

Вариант для трудолюбивых: вручную перечислить все файлы исходного кода и проставить зависимости к ним (примеры взяты из мануала по make):
main.o: defs.h
kbd.o: defs.h command.h
command.o: defs.h command.h
display.o: defs.h buffer.h
insert.o: defs.h buffer.h
search.o: defs.h buffer.h
files.o: defs.h buffer.h command.h
utils.o: defs.h
Те же яйца, вид сбоку:
$(objects): defs.h
kbd.o command.o files.o: command.h
display.o insert.o search.o files.o: buffer.h
Понятно, что этооо ... Короче всем понятно чтО это :)

На самом деле бородатые мужи давно придумали красивое решение: всего несколько строк магии sed объясняет make'у наши претензии. У меня получилась такая штука (применяется для сборки статичной библиотеки под Linux):
OUT = libfractal.a  # library name :)

CXXFLAGS = -Wall -c -O2

SRC = $(wildcard *.cpp) $(wildcard fractal_compress/*.cpp) \
      $(wildcard fractal_compress/domain/*.cpp)
# Expand SRC wildcard and replace extension from .cpp to .o
OBJ = $(patsubst %.cpp, %.o, $(SRC))
DEPS = $(patsubst %.cpp, %.P, $(SRC))

$(OUT): $(OBJ)
 ar -rc $(OUT) $(OBJ)
 ranlib $(OUT)

%.o : %.cpp
 $(CXX) $(CXXFLAGS) -MD -o $@ $<
 @cp $*.d $*.P; \
 sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
 -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
 rm -f $*.d

clean:
 rm -f $(OBJ) $(OUT) $(DEPS) *~

-include $(DEPS)

Комментариев нет:

Отправить комментарий