Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > GNU Make


Автор: SaDFromSpb 15.10.2006, 20:06
    Одна из основных фичей make в том, что она позволяет перекомпилировать (перетранслировать etc...) только те файлы, которые в этом нуждаются. Для этого необходимо составлять в мэйкфайле правила с зависимостями. Ну понятное дело, что составлять эти зависимости вручную не круто. Можно что-нибудь забыть или перепутать.
    Исходя из этих соображений, мне захотелось написать такой мэйкфайл, который автоматически генерирует зависимости и собирает проект по одной команде make. (Можно конечно сделать отдельную команду depends для этого дела, и вызывать ее перед сборкой, если добавился новый файл или произошли изменения в инклудах. Но так делать лень =) и периодически обязательно будешь про это забывать.)

   В нете я нашел одно решение, которое удовлетворяло моим требованиям за одним исключением: генерируемые зависимости всегда были на шаг позади сборки. То есть сначала по старым зависимостям собирался проект, затем эти зависимости обновлялись.

   Вобщем, решено было создать свой супер-пупер-мэйкфайл, потому-что заниматься основной работой (писать доку) решительно не хотелось, а сидеть в интернете - небезопасно для карьеры =).

   Прежде всего пришлось свыкнуться с мыслью, что одним мэйкфайлом не обойдешся, потому что зависимости должны присутствовать в мэйкфайле в явном виде уже при его первичном проходе. Следовательно, они должны быть либо прописанны вручную (чего мы хотим избежать), либо подцеплены include'ом из другого(их) файла(ов). Пришлось создавать один файл под именем "Makefile", генерирующий зависимости и вызывающий другой файл с загадочным именем ".compile".

Содержимое файла Makefile:
Код

MAKEFLAGS =--no-print-directory  # Это, чтобы не выводилась надпись entering/living directory ...
export EXECUTABLE = run            # Имя исполняемого файла. export нужна для того, 
                         # чтобы второй мэйкфайл тоже видел эту переменную

DELETE_DEPENDS       = FALSE       # Нужно ли удалять файлы с зависимостями после сборки 
export DEPEND_EXTEN  = depends  # Расширение для файлов с зависимостями, которое добавляется к именам файлов .cpp 

WARNFLAGS =  -Wall ... bla bla bla
export CXXFLAGS := $(WARNFLAGS) -ggdb еще bla bla bla bla   # Это встроенная переменная, которая используется неявным
                                             # правилом по сборке объектников (подставляется как ключ к gcc)

SRCS = main.cpp source1.cpp source2.cpp
HDRS = header1.hpp header2.hpp
export OBJS := $(SRCS:.cpp=.o)
export DEPENDS := $(SRCS:.cpp=.cpp.$(DEPEND_EXTEN))   # Вот это и будут файлы с зависимостями


DELETE_DEPENDS_COMMAND :=                             # команда для удаления файлов с зависимостями
ifeq ($(DELETE_DEPENDS), TRUE)
    DELETE_DEPENDS_COMMAND := $(RM) *.$(DEPEND_EXTEN)
endif


# Здесь создаем команду по генерации файлов с зависмостями средствами gcc.
# Для каждого файла команда имеет вид " g++ -M -MF  файл_зависмостей   cpp-шник "
ds := $(foreach depend,$(DEPENDS), && $(CCC) -M -MF $(depend) $(basename $(depend)))
CREATE_DEPENDS_COMMAND := $(wordlist 2,$(words $(ds)), $(ds))

# Main target
$(DEPENDS): $(SRCS) $(HDRS)
    @echo Generating dependencies...
    $(CREATE_DEPENDS_COMMAND)   # Создаем зависимости
    $(MAKE) -f .compile              # Вызываем второй мэйкфайл
    $(DELETE_DEPENDS_COMMAND)   # Удаляем файлы с зависимостями 

# Ну и так, по мелочи:

.PHONY: clean clear
clean: ; $(RM) *.o *.$(DEPEND_EXTEN)
clear: ; $(RM) *.o *.$(DEPEND_EXTEN) $(EXECUTABLE)


Содержимое файла ".compile"
Код

# Main target
$(EXECUTABLE) : $(OBJS)
    @echo Linking $(PROGRAM) binary
    $(CCC) -o $@ $(OBJS)
    @echo done

# Including files with dependencies
include *.$(DEPEND_EXTEN)     # Вот здесь и подключаем заветные зависимости


Собствено вот.
В данном примере в файлы зависимостей включаются и все библиотечные хедеры (это полезно, если параллельно редактируешь свою библиотеку). Если библиотечные хедеры не меняются, то флаг -M можно заменить на -MM. Тогда в зависимостях пропишутся только хедеры, включенные с помощью кавычек.

Наверное, на больших проектах эта фигня будет добавлять лишние пару секунд при компиляции, да и наличие двух мэйкфайлов вместо одного - это как-то не круто. Но все-таки удобно, мне кажется.
Если я тут понаписал полную фигню, и на самом деле все это - ламерство, и можно было сделать гораздо лучше по-другому, то просьба попинать.
Так же приветствуются любые цензурные пожелания и замечания по доработке.

Автор: GrayCardinal 16.10.2006, 05:12
Интересное чтиво  smile 

www.a-a-p.org
И cons (но домашней не помню)

Автор: SaDFromSpb 16.10.2006, 15:20
GrayCardinal, 
Цитата(GrayCardinal @  16.10.2006,  05:12 Найти цитируемый пост)
www.a-a-p.org
И cons (но домашней не помню) 
Я про них не знал, но догадывался  smile
Я все-таки именно про Make. Потому что многие все-равно его используют. (Вот ты, к примеру, чем пользуешся?).  И у нас в конторе его юзают в частности.
Хотя за ссылочки спасибо. Попробую дома поковырять.


Автор: bsa 16.10.2006, 19:38
Еще:
http://www.scons.org/
http://sourceware.org/automake

Автор: bilbobagginz 16.10.2006, 21:04
aap, scons - намного более продвинуты чем make.
то, что ты пытаешься сваять - придумывать autoconf + automake сызнова для make.
дело гиблое.

все стрелки идут от make вперёд а не на make.


Автор: GrayCardinal 17.10.2006, 05:26
SaDFromSpb, 
Я - то ? У меня скрипт свой Perl'овский  smile 

Автор: SaDFromSpb 17.10.2006, 13:25
Короче, понятно. Опять я позади планеты всей.  smile
Ладно. Будем более продвинутые темы осваивать.

Цитата(GrayCardinal @  17.10.2006,  05:26 Найти цитируемый пост)
У меня скрипт свой Perl'овский

Отец!  smile 

Но у меня есть оправдание - я на линухе сравнительно недавно программлю. Всем спасибо за инфу.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)