Проблема в том что make сам не умеет строить зависимости файлов с исходными кодами от заголовочных файлов. То есть, например, строим бинарный файл из foo.cpp, в который, с помощью директивы include включен bar.h. Простейший makefile будет выглядить как-то так:
Включаемый файл bar.h нигде не упоминается, и если мы его изменим, цель пересобрана не будет. Чтобы этого не происходило, надо указать bar.h в зависимостях рядом с foo.cpp. Однако вручную перечислять в зависимостях все включаемые заголовочные файлы практически нереально.
К счастью, этого и не требуется. У семейства компиляторов GCC есть флаг -MD, благодаря которому в процессе компиляции файла с исходными кодами создается файл, содержащий как раз список необходимых нам зависимостей. И формат этого файла совпадает с форматом зависимостей, используемом в make. Получается, при первой компиляции файла с исходными кодами будет создан файл с зависимостями для него, а при последующих этот файл нужно просто включить в makefile - тогда каждый файл с исходными кодами будет представлять собой в makefile цель с зависимостями в виде списка заголовочных файлов.
Ниже идет пример makefile rкоторый я использую для всех своих небольших проектов.
Собственно, вначале я задаю список директорий, где лежат исходные коды, затем с помощью wildcard и других функций make (подробнее про них можно почитать, например, здесь и здесь) получаю список файлов с исходными кодами на Си и Си++, расположенных в указанных директориях. Далее отдельно компилируются исходники на Си и на Си++, объектники и файлы зависимостей кладутся в отдельный каталог, последние будут включены в makefile при следующем вызове make. Ну и затем все это линкуется в бинарник. Про автоматические переменные, типа $^ и $@ можно прочитать здесь.
all: test test: foo.cpp g++ foo.cpp -o test
К счастью, этого и не требуется. У семейства компиляторов 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
Комментариев нет :
Отправить комментарий