Автоматическое построение зависимостей в make

Проблема в том что make сам не умеет строить зависимости файлов с исходными кодами от заголовочных файлов. То есть, например, строим бинарный файл из foo.cpp, в который, с помощью директивы include включен bar.h. Простейший makefile будет выглядить как-то так:
all: test

test: foo.cpp
    g++ foo.cpp -o test
Включаемый файл bar.h нигде не упоминается, и если мы его изменим, цель пересобрана не будет. Чтобы этого не происходило, надо указать bar.h в зависимостях рядом с foo.cpp. Однако вручную перечислять в зависимостях все включаемые заголовочные файлы практически нереально.

К счастью, этого и не требуется. У семейства компиляторов GCC есть флаг -MD, благодаря которому в процессе компиляции файла с исходными кодами создается файл, содержащий как раз список необходимых нам зависимостей. И формат этого файла совпадает с форматом зависимостей, используемом в make. Получается, при первой компиляции файла с исходными кодами будет создан файл с зависимостями для него, а при последующих этот файл нужно просто включить в makefile - тогда каждый файл с исходными кодами будет представлять собой в makefile цель с зависимостями в виде списка заголовочных файлов.
Ниже идет пример makefile rкоторый я использую для всех своих небольших проектов.
obj_dir = ./obj
lib_dir = ./lib
source_dirs = ./ sources
search_cpp_wildcards = $(addsuffix /*.cpp, $(source_dirs)) 
search_c_wildcards = $(addsuffix /*.c, $(source_dirs)) 
c_obj = $(addprefix $(obj_dir)/, $(notdir $(patsubst %.c, $(obj_dir)/%.o, $(wildcard $(search_c_wildcards)))))
cpp_obj = $(addprefix $(obj_dir)/, $(notdir $(patsubst %.cpp, $(obj_dir)/%.o, $(wildcard $(search_cpp_wildcards)))))
cflags = -o3 -Wall
lflags = -lsomething 

VPATH := $(source_dirs)  
 
all: target

target: $(c_obj) $(cpp_obj)
    g++ $^ -o $@ -L$(lib_dir)

$(obj_dir)/%.o: %.cpp
    gcc -c -MD $(addprefix -I, $(source_dirs)) $(cflags) -o $@ $<


$(obj_dir)/%.o: %.c
    gcc -c -MD $(addprefix -I,$(source_dirs)) $(cflags) -o $@ $<

include $(wildcard $(obj_dir)/*.d) 

clean: 
    rm -f $(obj_dir)/*.o $(obj_dir)/*.d ./target
Собственно, вначале я задаю список директорий, где лежат исходные коды, затем с помощью wildcard и других функций make (подробнее про них можно почитать, например, здесь и здесь) получаю список файлов с исходными кодами на Си и Си++, расположенных в указанных директориях. Далее отдельно компилируются исходники на Си и на Си++, объектники и файлы зависимостей кладутся в отдельный каталог, последние будут включены в makefile при следующем вызове make. Ну и затем все это линкуется в бинарник. Про автоматические переменные, типа $^ и $@ можно прочитать здесь.

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

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