html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Пример Makefile

Написание makefile иногда становится головной болью. Однако, если разобраться, все становится на свои места, и написать мощнейший makefile длиной в 40 строк для сколь угодно большого проекта получается быстро и элегантно.

Внимание! Предполагаются базовые знания утилиты GNU make.


Имеем некий типичный абстрактный проект со следующей структурой каталогов:



Пусть для включения заголовочных файлов в исходниках используется что-то типа #include <dir1/file1.h>, то есть каталог project/include делается стандартным при компиляции.

После сборки надо, чтобы получилось так:



То есть, в каталоге bin лежат рабочая (application) и отладочная (application_debug) версии, в подкаталогах Release и Debug каталога project/obj повторяется структура каталога project/src с соответствующими исходниками объектных файлов, из которых и компонуется содержимое каталога bin.

Чтобы достичь данного эффекта, создаем в каталоге project файл Makefile следующего содержания:
  1. root_include_dir    := include
  2. root_source_dir    := src
  3. source_subdirs    := . dir1 dir2
  4. compile_flags      := -Wall -MD -pipe
  5. link_flags            := -s -pipe
  6. libraries               := -ldl
  7.  
  8. relative_include_dirs   := $(addprefix ../../, $(root_include_dir))
  9. relative_source_dirs   := $(addprefix ../../$(root_source_dir)/, $(source_subdirs))
  10. objects_dirs               := $(addprefix $(root_source_dir)/, $(source_subdirs))
  11. objects                      := $(patsubst ../../%%, $(wildcard $(addsuffix /*.c*, $(relative_source_dirs))))
  12. objects                      := $(objects:.cpp=.o)
  13. objects                      := $(objects:.c=.o)
  14.  
  15. all : $(program_name)
  16.  
  17. $(program_name) : obj_dirs $(objects)
  18.         g++ -o $@ $(objects) $(link_flags) $(libraries)
  19.  
  20. obj_dirs :
  21.         mkdir -p $(objects_dirs)
  22.  
  23. VPATH := ../../
  24.  
  25. %.o : %.cpp
  26.         g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs))
  27.  
  28. %.o : %.c
  29.         g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs))
  30.  
  31. .PHONY : clean
  32.  
  33. clean :
  34.         rm -rf bin obj
  35.  
  36. include $(wildcard $(addsuffix /*.d, $(objects_dirs)))

В чистом виде такой makefile полезен только для достижения цели clean, что приведет к удалению каталогов bin и obj.
Добавим еще один сценарий с именем Release для сборки рабочей версии:

mkdir -p bin
mkdir -p obj
mkdir -p obj/Release
make --directory=./obj/Release --makefile=../../Makefile build_flags="-O2 -fomit-frame-pointer" program_name=../../bin/application


И еще один сценарий Debug для сборки отладочной версии:

mkdir -p bin
mkdir -p obj
mkdir -p obj/Debug
make --directory=./obj/Debug --makefile=../../Makefile build_flags="-O0 -g3 -D_DEBUG" program_name=../../bin/application_debug


Именно вызов одного из них соберет наш проект в рабочем, либо отладочном варианте. А теперь, обо всем по-порядку.

Допустим, надо собрать отладочную версию. Переходим в каталог project и вызываем ./Debug. В первых трех строках создаются каталоги. В четвертой строке утилите make сообщается, что текущим каталогом при запуске надо сделать project/obj/Debug, относительно этого далее передается путь к makefile и задаются две константы: build_flags (тут перечисляются важные для отладочной версии флаги компиляции) и program_name (для отладочной версии – это application_debug).

Далее, в игру вступает GNU make. Прокомментируем каждую строку makefile:

1: Объявляется переменная с именем корневого каталога заголовочных файлов.

2: Объявляется переменная с именем корневого каталога исходников.

3: Объявляются переменная с именами подкаталогов корневого каталога исходников.

4: Объявляется переменная с общими флагами компиляции. -MD заставляет компилятор сгенерировать к каждому исходнику одноименный файл зависимостей с расширением .d. Каждый такой файл выглядит как правило, где целью является имя исходника, а зависимостями – все исходники и заголовочные файлы, которые он включает директивой #include. Флаг -pipe заставляет компилятор пользоваться IPC вместо файловой системы, что несколько ускоряет компиляцию.

5: Объявляется переменная с общими флагами компоновки. -s заставляет компоновщик удалить из результирующего ELF файла секции .symtab, .strtab и еще кучу секций с именами типа .debug*, что значительно уменшает его размер. В целях более качественно отладки этот ключ можно убрать.

6: Объявляется переменная с именами используемых библиотек в виде ключей компоновки.

8: Объявляется переменная, содержащая относительные имена каталогов со стандартными заголовочными файлами. Потом такие имена напрямую передаются компилятору, предваряемые ключем -I. Для нашего случая получится ../../include, потому что такой каталог у нас один. Функция addprefix добавляет свой первый аргумент ко всем целям, которые задает второй аргумент.

9: Объявляется переменная, содержащая относительные имена всех подкаталогов корневого каталога исходников. В итоге получим: ../../src/. ../../src/dir1 ../../src/dir1.

10: Объявляется переменная, содержащая имена подкаталогов каталога project/obj/Debug/src относительно текущего project/obj/Debug. То есть, этим мы перечисляем копию структуры каталога project/src. В итоге получим: /src/dir1 src/dir2.

11: Объявляется переменная, содержащая имена исходников, найденных на основе одноименных файлов *.c* (.cpp\.c), безотносительно текущего каталога. Смотрим поэтапно: результатом addsuffix будет ../../src/./*.с* ../../src/dir1/*.с* ../../src/dir2/*.с*. Функция wildcard развернет шаблоны со звездочками до реальных имен файлов: ../../src/./main.сpp ../../src/dir1/file1.с ../../src/dir1/file2.сpp ../../src/dir2/file3.с ../../src/dir2/file4.с. Функция patsubsb уберет префикс ../../ у имен файлов (она заменяет шаблон, заданный первым аргументом на шаблон во втором аргументе, а % обозначает любое количество символов). В итоге получим: src/./main.сpp src/dir1/file1.с src/dir1/file2.сpp src/dir2/file3.с src/dir2/file4.с.

12: В переменной с именами исходников расширения .cpp заменяется на .o.

13: В переменной с именами исходников расширения .c заменяется на .o.

15: Первое объявленное правило – его цель становится целью всего проекта. Зависимостью является константа, содержащая имя программы (../../bin/application_debug мы ее передали при запуске make из сценария).

17: Описание ключевой цели. Зависимоcти тоже очевидны: наличие созданных подкаталого в project/obj/Debug, повторяющих структуру каталога project/src и множество объектных файлов в них.

18: Описано действие по компоновке объектных файлов в целевой.

20: Правило, в котором цель – каталог project/obj/Debug/src и его подкаталоги.

21: Действие по достижению цели – создать соответствующие каталоги src/., src/dir1 и src/dir2. Ключ -p утилиты mkdir игнорирует ошибку, если при создании какого-либо каталога, таковой уже существуют.

23: Переменная VPATH принимает значение ../../. Это необходимо для шаблонов нижеследующих правил.

25: Описывается множество правил, для которых целями являются любые цели, соответствующие шаблону %.o (то есть имена которых оканчиваются на .o), а зависимостями для этих целей являются одноименные цели, соответствующие шаблону %.cpp (то есть имена которых оканчиваются на .cpp). При этом под одноименностью понимается не только точное совпадение, но также если имя зависимости предварено содержимым переменной VPATH. Например, имена src/dir1/file2 и ../../src/dir1/file2 совпадут, так как VPATH содержит ../../.

26: Вызов компилятора для превращения исходника на языке С++ в объектный файл.

28: Описывается множество правил, для которых целями являются любые цели, соответствующие шаблону %.o (то есть имена которых оканчиваются на .o), а зависимостями для этих целей являются одноименные цели, соответствующие шаблону %.c (то есть имена которых оканчиваются на .c). Одноименность как в строке 23.

29: Вызов компилятора для превращения исходника на языке С в объектный файл.

31: Некоторая цель clean объявлена абстрактной. Достижение абстрактной цели происходит всегда и не зависит от существования одноименного файла.

32: Объявление абстрактной цели clean.

33: Действие по ее достижению заключается в уничтожении каталогов project/bin и project/obj со всем их содержимым.

36: Включение содержимого всех файлов зависимостей (с расширением .d), находящихся в подкаталогах текущего каталога. Данное действие утилита make делает в начале разбора makefile. Однако, файлы зависимостей создаются только послекомпиляции. Значит, при первой сборке ни один такой файл включен не будет. Но это не страшно. Цель включения этих файлов – вызвать перекомпиляцию исходников, зависящих от модифицированного заголовочного файла. При второй и последующих сборках утилита make будет включать правила, описанные во всех файлах зависимостей, и, при необходимости, достигать все цели, зависимые от модифицированного заголовочного файла.

Удачи!
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

2

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • shoumikhin
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции