"Разнесение" разных версий программы по отдельным директориям
В том случае если я собираю несколько вариантов одной и той же программы (например, отладочную и рабочую версию), становится неудобным помещать результаты компиляции в один и тот же каталог. При переходе от одного варианта к другому приходится полностью перекомпилировать программу во избежание нежелательного "смешивания" объектных файлов разных версий.
Для решения этой проблемы я помещаю результаты компиляции каждой версии программы в свой отдельный каталог. Так, например, отладочная версия программы (включая все объектные файлы) помещается в каталог debug, а рабочая версия программы - в каталог release:
- example_6-multiconfig-multidir /
- debug /
- release /
- main.cpp
- main.h
- Editor /
- Editor.cpp
- Editor.h
- TextLine /
- TextLine.cpp
- TextLine.h
- Makefile
- make_debug
- make_release
Главная сложность заключалась в том, чтобы заставить программу make помещать результаты работы в разные директории. Попробовав разные варианты, я пришел к выводу, что самый легкий путь - использование флажка --directory при вызове make. Этот флажок заставляет утилиту перед началом обработки make-файла, сделать каталог, указанный в командной строке, "текущим".
Вот, например, как выглядит командный файл make_release, собирающий рабочую версию программы (результаты компиляции помещается в каталог release):
mkdir release make compile_flags="-O3 -funroll-loops -fomit-frame-pointer" \ --directory=release \ --makefile=../Makefile
Команда mkdir введена для удобства - если удалить каталог release, то при следующей сборке он будет создан заново. В случае "составного" имени каталога (например, bin/release) можно дополнительно использовать флажок -p. Флажок --directory заставляет make перед началом работы сделать указанную директорию release текущей. Флажок --makefile укажет программе make, где находится make-файл проекта. По отношению к "текущей" директории release, он будет располагаться в "родительском" каталоге.
Командный файл для сборки отладочного варианта программы (make_debug) выглядит аналогично.
Различие только в имени директории, куда помещаются результаты компиляции (debug) и другом наборе флагов компиляции:
mkdir debug make compile_flags="-O0 -g" \ --directory=debug \ --makefile=../Makefile
Вот окончательная версия make-файла для сборки "гипотического" проекта текстового редактора:
# # example_6-multiconfig-multidir/Makefile # # Пример "разнесения" разных версий программы по отдельным директориям #
program_name := iEdit source_dirs := . Editor TextLine
source_dirs := $(addprefix ../,$(source_dirs)) search_wildcards := $(addsuffix /*.cpp,$(source_dirs))
$(program_name): $(notdir $(patsubst %.cpp,%.o, $(wildcard $(search_wildcards) ) ) ) gcc $^ -o $@
VPATH := $(source_dirs)
%.o: %.cpp gcc -c -MD $(compile_flags) $(addprefix -I,$(source_dirs)) $<
include $(wildcard *.d)
В этом окончательном варианте я "вынес" имя исполняемого файла программы в отдельную переменную program_name. Теперь для того чтобы адаптировать этот make-файл для сборки другой программы, в нем достаточно изменить всего лишь несколько первых строк.
После запуска командных файлов make_debug и make_release директория с последним примером выглядит так:
- example_6-multiconfig-multidir /
- debug /
- iEdit
- main.o
- main.d
- Editor.o
- Editor.d
- TextLine.o
- TextLine.d
- release /
- iEdit
- main.o
- main.d
- Editor.o
- Editor.d
- TextLine.o
- TextLine.d
- main.cpp
- main.h
- Editor /
- Editor.cpp
- Editor.h
- TextLine /
- TextLine.cpp
- TextLine.h
- makefile
- make_debug
- make_release
- debug /
- В Приложении A я описываю проблемы, которые могут возникнуть при редактировании make-файлов в разных операционных системах
- В Приложении B я описываю свой личный способ организации дерева каталогов для сложных проектов.
- В Приложении C я делюсь некоторыми мыслями по поводу использования компилятора GCC