англійськафранцузькаіспанська

Ad


Значок OnWorks

makepp_cookbook - онлайн у хмарі

Запустіть makepp_cookbook у постачальника безкоштовного хостингу OnWorks через Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

Це команда makepp_cookbook, яку можна запустити в постачальнику безкоштовного хостингу OnWorks за допомогою однієї з наших численних безкоштовних робочих станцій, таких як Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

ПРОГРАМА:

ІМ'Я


makepp_cookbook -- найкращий спосіб налаштувати make-файли для різних ситуацій

ОПИС


Я виявив, що практично ніхто ніколи не читає інструкцію для виготовлення інструменту, тому що чесно кажучи
нікого насправді не цікавить сам процес виготовлення - нас цікавлять лише результати.
Тому цю кулінарну книгу було складено в надії, що люди зможуть отримати те, що їм потрібно
швидко з прикладів, не перебираючи посібник. Це показує, як вводити
питання, тоді як інструкції з встановлення та камені спотикання можна знайти в
Питання що часто задаються.

Створюємо libraries
Do ви насправді необхідність a бібліотека?

Я бачив ряд великих програм, які складаються з великої кількості модулів, кожен з яких
який живе у власному каталозі. Зазвичай кожен каталог поміщається в свою власну бібліотеку,
а потім остаточна програма зв’язується з усіма бібліотеками.

У багатьох випадках, я думаю, є кращий підхід, ніж використовувати бібліотеку. Бібліотеки
насправді не є правильним рішенням, якщо кожен модуль не може або не буде повторно використаний в будь-якому іншому
програму, тому що тоді ви отримаєте всі недоліки бібліотек і жодного з них
переваги. Бібліотеки корисні в таких випадках:

1. Коли у вас є купа підпрограм, які повинні бути пов'язані з кількома різними
програм, і жодна програма фактично не використовує 100% підпрограм - кожна програма використовує
різна підмножина. У цьому випадку, ймовірно, було б гарною ідеєю використовувати статичну бібліотеку (a
.a файл або архівний файл).

2. Коли у вас є модуль, який має бути пов'язаний з кількома різними програмами, і ви
Ви хочете завантажити його динамічно, щоб кожній програмі не потрібно було мати окрему копію
бібліотека. Динамічні бібліотеки можуть заощадити простір виконуваного файлу, а іноді й розширити
продуктивність системи, оскільки для всіх файлів завантажено лише одну копію бібліотеки
різні програми, які його використовують.

3. Коли ваше посилання занадто довго, використовуйте спільні бібліотеки для великих фрагментів
програма може значно прискорити посилання.

Використання статичних бібліотек має один головний недолік: у деяких системах (наприклад, Linux) порядок
у якому ви пов’язуєте бібліотеки, є критично важливим. Компонувальник обробляє бібліотеки
у порядку, зазначеному в його командному рядку. Він бере все, від чого думає, що йому потрібно
кожної бібліотеки, потім переходить до наступної бібліотеки. Якщо якась наступна бібліотека посилається на a
символ, який ще не був включений з попередньої бібліотеки, компонувальник ні
знати, щоб повернутися назад і отримати його з попередньої бібліотеки. В результаті це може знадобитися
щоб перерахувати бібліотеку кілька разів у командному рядку компонувальника. (Я працював над проектом
де довелося тричі повторити весь список бібліотек. Цей проект створив
Я віддаю перевагу альтернативному підходу, запропонованому нижче, — інкрементному посиланню.)

Використання динамічних бібліотек має кілька недоліків. По-перше, ваша програма може бути трохи
повільніше запускається, якщо бібліотека ще не використовується іншою програмою, тому що
його потрібно знайти і завантажити. По-друге, отримати всю динаміку може бути непросто
бібліотеки, встановлені в правильних місцях; Ви не можете просто скопіювати виконуваний файл програми,
ви також повинні переконатися, що ви скопіювали всі його бібліотеки. По-третє, на деяких системах це
важко налагодити код у спільних бібліотеках, оскільки налагоджувачі не підтримують
їм добре.

Якщо ваш модуль ніколи не використовуватиметься в будь-якій іншій програмі, то немає причин використовувати
бібліотека: ви отримуєте всі недоліки використання бібліотек і жодної з переваг.
Техніка, яку я віддаю перевагу, полягає у використанні інкрементного зв’язування, якщо воно доступне.

Ось як це можна зробити в Linux:

my_module.o : $(filter_out my_module.o, $(підстановка *.o))
ld -r -o $(вихід) $(входи)

Це призведе до створення іншого .o файл називається my_module.o, який складатиметься з
всі .o файли в цьому підкаталозі. Компонувальник вирішить якомога більше
посилань, наскільки це можливо, і залишить решту посилань для вирішення в a
наступний етап зв'язування. На верхньому рівні, коли ви нарешті створите свою програму,
замість зв'язування з libmy_module.a or libmy_module.so, ви б просто зв’язалися з
my_module.o. Коли ви посилаєте .o файлів, у вас немає проблем із залежністю від порядку в
командний рядок компонувальника.

Здавати в оренду makepp зрозуміти з який бібліотека Модулі він має необхідний

Навіть якщо у вас є справжня бібліотека, де даній програмі потрібно лише кілька файлів із неї
(а не кожен окремий модуль), makepp може з’ясувати, які саме модулі
потрібні з бібліотеки та включайте лише ті, що містяться в збірці. Це може зберегти компіляцію
час, якщо ви розробляєте бібліотеку разом із програмою, тому що ви не турбуєтеся про це
скомпілювати бібліотечні модулі, які не потрібні для конкретної програми, над якою ви працюєте.

Якщо ваша бібліотека суворо дотримується конвенції, в якій оголошені всі функції або класи
файл xyz.h повністю реалізовані у вихідному файлі, який компілюється до xyz.o (тобто ти
не розбивайте реалізацію на xyz1.o та xyz2.o), то ви можете використовувати
Функція "$(infer_objects)", щоб сказати makepp витягувати лише відповідні модулі з файлу
бібліотека. Це може напрочуд добре працювати для бібліотек навіть із десятками включених файлів.
В основному, "$(infer_objects)" перевіряє список .h файли, які включені, і вигляд
для відповідних .o файли. Якщо ви швидко розвиваєте бібліотеку та програму
разом це може заощадити час компіляції, оскільки ви ніколи не збираєтеся скомпілювати модулі
бібліотека, яку програма не використовує.

Ось приклад того, як я це використовую:

my_program: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(входи) -o $(вихід) $(SYSTEM_LIBRARIES)

Функція "$(infer_objects)" повертає свій перший аргумент (після виконання підстановки
розширення на ньому), а також переглядає список файлів у своєму другому аргументі for
файли, ім'я яких збігається з назвою будь-якого .h файли, включені будь-яким файлом у перший
аргумент. Якщо такі файли знайдено, вони додаються до списку.

Створюємо a статичний бібліотека

Якщо ви впевнені, що вам дійсно потрібна бібліотека, а додаткове посилання недоступне або
це не те, що ви хочете зробити, є кілька способів зробити це. По-перше, ось приклад
де всі файли явно перераховані:

LIBRARY_FILES = abcde

libmine.a: $(ФАЙЛИ_БІБЛІОТЕКИ).o
&rm -f $(вихід)
$(AR) cr $(вихід) $(входи)
ranlib $(output) # Можливо, не потрібно, залежно від вашої ОС.

&rm - це вбудована команда makepp "rm". Якщо ви звикли писати make-файли, можливо
трохи здивований цією командою; ви, можливо, звикли до чогось подібного:

libmine.a: $(ФАЙЛИ_БІБЛІОТЕКИ).o
$(AR) ru $@ $? # Не рекомендовано!!!!!!!
ranlib $(вихід)

де $? (також відома як "$(changed_inputs)") - це автоматична змінна, яка означає будь-які файли
які змінилися з моменту останнього створення бібліотеки, і $@ приблизно той самий
як "$(вихід)".

Цей підхід не рекомендується з кількох причин:

· Припустимо, ви видаляєте вихідний файл із поточного каталогу. Це все ще в
бібліотеку, тому що ви не відновили бібліотеку з нуля. В результаті будь-що
що посилання з цією бібліотекою будуть застарілими .o файл, і це може зіпсувати ваш
будує. (Колись я був повністю збитий з цього приводу, коли намагався видалити мертвий код
з проекту: я продовжував видаляти файли, але він все ще зв’язувався, тому я думав, що код був
мертвий. Однак, коли хтось інший відновив проект з нуля, він не пов’язував жодного
більше! Проблема полягала в тому, що старий .o файли все ще були в архіві.)

Крім того, залежно від ваших варіантів "ar" і вашої реалізації "ar" (наприклад, якщо ви
використовуйте параметр "q" замість "r"), ви можете отримати декілька версій
то ж .o всередині .a файл. Якщо різні версії визначають різні глобали, то
компонувальник може спробувати залучити їх обидва. Це, мабуть, погана річ.

Ось чому ми спочатку видаляємо файл бібліотеки та створюємо його з нуля. Це буде
займати трохи більше часу, ніж просто оновлення модулів у бібліотеці, але не набагато більше; на
сучасний комп'ютер, кількість часу, що витрачається на ar Програма незначна в порівнянні
до того, що компілятор C використовує в типовій збірці, тому хвилюватися не варто
о.

· Одним із способів, яким makepp намагається гарантувати правильні збірки, є те, що так і буде
автоматично перебудувати, якщо змінено командний рядок для створення заданої цілі. Але
використовуючи $? змінна може викликати проблеми, оскільки щоразу, коли бібліотека оновлюється,
команда build відрізняється. (Ви можете придушити це за допомогою
":build_check ignore_action"; дивіться makepp_build_check для деталей.)

· Оновлення архіву, а не перебудова, унеможливить makepp
правильно помістити файл у кеш збірки (докладніше див. у makepp_build_cache).

Іноді ви можете помітити, що перерахування всіх файлів є трохи болючим, особливо якщо a
проект швидко розвивається, а список файлів постійно змінюється. Це
може бути простіше побудувати бібліотеку за допомогою символів підстановки, наприклад:

libmine.a: $(only_targets *.o)
&rm $(вихід)
$(AR) cr $(вихід) $(входи)

Це ставить все .o файли в поточному каталозі в бібліотеку. Підстановка
відповідає будь -якому .o файл, який існує або може бути створений, тому він працюватиме, навіть якщо файлів немає
ще існують.

Для виключення використовується функція "only_targets". .o файли, які не мають відповідних
вихідні файли більше. Припустимо, у вас є файл під назвою xyz.c що ти раніше вкладав у свій
бібліотека. Це означає, що є xyz.o файл валяється. Тепер ви видаляєте xyz.c
тому що він застарів, але ви забуваєте видалити xyz.o. Без "only_targets"
функція xyz.o все одно буде включено до списку .o файли, що входять до бібліотеки.

Створюємо a динамічний бібліотека

Процес створення динамічних бібліотек повністю залежить від системи. Я б дуже
рекомендуємо використовувати libtool для створення динамічної бібліотеки (див
<http://www.gnu.org/software/libtool/>), тож вам не потрібно придумувати, як це зробити
вашої платформи, і щоб ваш make-файл продовжував працювати, навіть коли ви перейдете на a
різні ОС. Додаткову інформацію дивіться в документації libtool. Ось зразок Makefile:

LIBTOOL := libtool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(входи) -o $(вихід)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(ВКЛЮЧИТЬ) -c $(вхід) -o $(вихід)

Створюємо on кілька різний машини or мереж
Однією з найбільш дратівливих проблем з make-файлами є те, що вони майже ніколи не працюють, коли ви
переключитися на іншу машину або іншу мережу. Якщо ваші make-файли повинні працювати
будь-яку можливу машину на планеті, то вам, ймовірно, знадобиться якась конфігурація
сценарій. Але якщо вам потрібно працювати лише на кількох різних машинах, є кілька способів
Ви можете підійти до цієї проблеми:

Скористайтесь a різний включати файл in всі середовищах

На початку кожного make-файлу можна включити такий рядок:

включити system_defs.mk

Файл system_defs.mk зазвичай розташовується в іншому місці для кожного
середовище. Якщо ви хочете, щоб ваші каталоги збірки були однаковими на всіх машинах, то поставте
system_defs.mk у каталозі над каталогами збірки, або введіть шлях для включення
makepp за допомогою параметра командного рядка "-I".

Зазвичай це досить боляче робити, але це добре працює, якщо їх величезна кількість
відмінності.

Скористайтесь if заяви

Це найпотворніший спосіб зробити це, але зазвичай він спрацьовує.

ifsys i386
CC := gcc
інакше ifsys sun4u
CC := cc
інакше ifsys hpux11
CC = c89
ENDIF

Якщо все, що вам потрібно зробити, це знайти кілька програм або бібліотек або включити файли в різні
місцях, можуть бути кращі способи (див. нижче).

програма пошуку, перший_доступний, файл пошуку

Ці функції можуть здійснювати пошук у різних каталогах у вашій системі, щоб знайти
відповідні файли. Це, звичайно, не настільки потужний, як сценарій налаштування, але я вважаю його
корисний. Наприклад, я роблю наступне:

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# Виберіть перший компілятор C++, доступний у PATH.
# (До речі, якщо ви взагалі не визначаєте CXX, це
# – це те, як це визначено.)
TCL_INCLUDE ;= -I$(dir_noslash $(знайти файл tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) шукає tcl.h у кожному з вказаних
# каталогів і повертає повний шлях. Це тоді
# перетворено на параметр компіляції шляхом видалення
# ім'я файлу (виходячи з каталогу) з префіксом -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(вхід) -o $(вихід)

TCL_LIB ;= $((перший_доступний
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Знайдіть, де знаходиться бібліотека Tcl. Тоді це явно
# зазначено в команді link:
моя_програма : *.o
$(CXX) $(CXXFLAGS) $(входи) -o $(вихід) $(TCL_LIB)

Приймати перевагу of Перл конфиг інформація

Наведених вище методів може бути недостатньо, якщо вам потрібна додаткова інформація про
вашої системи, наприклад, чи існує довгий двійник або який порядок байтів. однак,
perl вже обчислив ці речі, тому ви можете просто використовувати його відповіді.

Сценарій автоналаштування Perl робить всю інформацію про конфігурацію доступною через
хеш % Config. Немає синтаксису для доступу до хешу Perl безпосередньо в makepp, але ви можете
перейдіть до Perl і встановіть скалярні змінні, які безпосередньо доступні з makepp:

perl_begin
# Отримати значення з хешу конфігурації.
використовувати Config;
$CC = $Config{'cc'}; # Компілятор C, який використовував Perl;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'визначити';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

Крім того, після того, як ви виконаєте 'use Config', ви можете використовувати оператор "$(perl )", наприклад
це:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

Введіть "perldoc Config", щоб побачити, яка інформація доступна через хеш %Config.

Конфігурація Perl є хорошим місцем для отримання таких речей, як інформація про цілі типи, байти
порядок та інші речі, які зазвичай потребують окремого конфігураційного сценарію для пошуку. Деякі з
його інформації, що стосується наявності речей у файловій системі, може не бути
дійсний. Наприклад, $Config{'cc'} відноситься до компілятора C, на якому створено perl,
який може бути не тим компілятором C, який ви хочете використовувати. Насправді його може навіть не існувати
у вашій системі, оскільки, ймовірно, ви встановили Perl за допомогою бінарного пакету.

Tips та цінності використання макетів
Узгодження всі файли крім a певний підмножина

Підстановки Makepp на даний момент не мають жодного способу збігу всіх файлів крім певний
встановити, але це можна зробити за допомогою комбінації функцій.

Наприклад, припустимо, що у вас є тестова програма для кожного модуля в бібліотеці, але у вас її немає
хочуть включити тестові програми до бібліотеки. Якщо всі тестові програми починаються з
тест, то ви можете виключити їх таким чином:

libproduction.a: $(filter_out test*, $(підстановка *.o))

Функції "$(filter)" і "$(filter_out)" - це дуже потужний набір фільтрів.
всі види операцій перетину множин і різниць. Наприклад,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# Повертає всі підкаталоги, яких немає
# "test" або $(ARCH) у них.

$(фільтр $(patsubst test_dir/test_%.o, %.o, $(підстановка test_dir/*.o)), \
$(підстановка *.o))
# Повертає список файлів .o в поточному
# каталог, для якого є відповідний
# файл test_*.o у підкаталозі test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard man/man3/*.3)), \
$(підстановка *.o))
# Повертає список файлів .o в поточному
# каталог, для якого немає сторінки посібника
# з такою ж назвою файлу в підкаталозі man/man3.

використання "$(only_targets )" функція до усунутий застарілий .o файли

Припустимо, ви створюєте програму або бібліотеку за допомогою такої команди збірки:

програма: *.o
$(CC) $(входи) -o $(вихід)

Припустимо, тепер ви видаляєте вихідний файл. Якщо ви забули видалити відповідні .o файл,
він все одно буде пов’язаний, навіть якщо його більше немає можливості створити. В
У майбутньому makepp, ймовірно, автоматично розпізнає цю ситуацію та виключить її
список підстановочних знаків, але наразі ви повинні вказати йому виключити його вручну:

програма: $(only_targets *.o)
$(CC) $(входи) -o $(виходи)

Makepp не знає жодного способу створення застарілого .o файл більше, оскільки його вихідний файл є
зникло, тому функція "$(only_targets)" виключить його зі списку залежностей.

Tips та цінності множинний каталоги
Однією з основних причин написання makepp було спрощення обробки кількох
каталогів. Makepp може комбінувати команди збірки з кількох make-файлів, тож він може
правильно працювати з правилом в одному make-файлі, що залежить від файлу, створеного a
інший make-файл.

Що до do in місце of рекурсивний зробити

Makepp підтримує рекурсивний make для зворотної сумісності, але настійно рекомендується
Що Ви НЕ використай це. Якщо ви не знаєте, що це таке, добре.

Перегляньте «Кращу систему для ієрархічних побудов» у makepp, щоб дізнатися більше про те, чому ви цього не хочете
використовуйте рекурсивний make, або шукайте в Інтернеті "рекурсивний make вважається шкідливим".

Замість того, щоб робити рекурсивний make, щоб зробити "всі" ціль у кожному make-файлі, це так
зазвичай легше дозволити makepp визначити, які цілі насправді потрібно створити.
Крім того, якщо ви покладете всі свої .o та файли бібліотеки в тому самому каталозі, що й файл
makefiles, тоді makepp автоматично визначить, які файли make-файлу також потрібні -
Єдине, що потрібно, це мати на верхньому рівні список файлів, які потрібні
для останнього кроку підключення. Дивіться приклади нижче.

Один makefile та цінності кожен каталог: з неявний погрузка

Найпоширенішим способом роботи з кількома каталогами є розміщення make-файлу в кожному каталозі
який описує, як побудувати все в цьому каталозі або з нього. Якщо поставити .o файли в
той самий каталог, що й вихідні файли, потім неявне завантаження (див. «Неявне завантаження» в
makepp_build_algorithm) автоматично знайде всі make-файли. Якщо ви поставите свій .o
файли в іншому каталозі (наприклад, у підкаталозі, що залежить від архітектури), то ви
ймовірно, доведеться завантажити всі відповідні make-файли за допомогою оператора load_makefile.

Ось зразок make-файлу верхнього рівня для ієрархії каталогів, яка використовує неявне завантаження
щоб створити програму, яка складається з багатьох спільних бібліотек (але дивіться «Чи дійсно вам потрібен a
бібліотека?" у makepp_cookbook, тому що створення програми з купи спільних бібліотек
це не обов'язково гарна ідея):

# Makefile верхнього рівня:
program : main.o **/*.la # Посилання на спільні бібліотеки з усіх підкаталогів.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(входи) -o $(вихід) $(LIBS)

Це майже все, що вам потрібно в make-файлі верхнього рівня. У кожному підкаталозі ви
ймовірно, зробив би щось подібне:

# Makefile в кожному підкаталозі:
включати standard_defs.mk # Пошуки ., .., ../ .., і т. д., поки не
# знаходить вказаний файл включення.
# замінити деякі визначення змінних тут
SPECIAL_FLAGS := -зробити_щось_різне

Кожен make-файл, ймовірно, може бути майже однаковим, якщо команди для створення цілей
досить схожі.

Нарешті, ви б помістили наступне в standard_defs.mk файл (який, ймовірно, повинен
знаходитися в каталозі верхнього рівня):

# Загальні налаштування змінних і правила побудови для всіх каталогів.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards включає)
# Пошуки ., .., ../ .., тощо для файлу або
# каталог називається включає, тому якщо ви поставте
# всі ваші включені файли, це буде
# знайди їх.
ВКЛЮЧАЄ := -I$(INCLUDE_DIR)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(ВКЛЮЧИТЬ) -c $(вхід) -o $(вихід)

lib$(відносно ., ..).la: $(тільки_цілі *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(вихід) $(входи)
# $(relative_to ., ..) повертає назву поточного
# підкаталог відносно верхнього рівня
# підкаталог. Отже, якщо цей make-файл xyz/Makefile,
# це правило створить xyz/libxyz.la.

# Публікуйте загальнодоступні файли включення в каталозі включення верхнього рівня:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(вхід) $(вихід)

Один makefile та цінності кожен каталог: явний погрузка

Якщо ви хочете покласти все своє .o потім файли в підкаталог, що залежить від архітектури
наведений вище приклад слід змінити таким чином:

# Makefile верхнього рівня:
MAKEFILES := $(підстановка **/Makeppfile) # Список усіх підкаталогів для
# отримати make-файли з.

load_makefile $(MAKEFILES) # Завантажте їх усі.

include standard_defs.mk # Отримати команду компіляції для main.o.

програма: $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(входи) -o $(вихід) $(LIBS)
# */**/$(ARCH) виключає підкаталог
# $(ARCH), де ми не хочемо будувати
# спільна бібліотека.

Кожен make-файл буде точно таким же, як і раніше:

# Makefile в кожному підкаталозі:
включити standard_defs.mk
# ... змінна тут замінює

І, нарешті, standard_defs.mk міститиме щось на кшталт наступного:

# Загальні налаштування змінних і правила побудови для всіх каталогів.
ARCH ;= $(назва оболонки -s)-$(назва оболонки -m)-$(назва оболонки -r)
# Іноді люди використовують лише $(shell uname -m), але
# це буде однаково для FreeBSD і Linux
# x86. -r не дуже корисний в Linux,
# але це важливо для інших ОС: двійкові файли для
# SunOS 5.8 зазвичай не працює на SunOS 5.7.
&mkdir -p $(ARCH) # Переконайтеся, що вихідний каталог існує.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards включає)
# Пошуки ., .., ../ .., тощо для файлу або
# каталог називається включає, тому якщо ви поставте
# всі ваші включені файли, це буде
# знайди їх.
ВКЛЮЧАЄ := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(ВКЛЮЧИТЬ) -c $(вхід) -o $(вихід)

$(ARCH)/ lib$(відносно ., ..).la: $(тільки_цілі *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(вихід) $(входи)
# $(relative_to ., ..) повертає назву поточного
# підкаталог відносно верхнього рівня
# підкаталог. Отже, якщо цей make-файл xyz/Makefile,
# це правило створить xyz/$(ARCH)/libxyz.la.

# Скопіюйте загальнодоступні файли включення в каталог включення верхнього рівня:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(вхід) $(вихід)

Автоматично створення make-файли

Якщо всі ваші make-файли дуже схожі (як у наведеному вище прикладі), ви можете сказати Makepp
щоб створити їх автоматично, якщо вони не існують. Просто додайте наступне до свого верхнього рівня
make-файл:

SUBDIRS := $(filter_out unwanted_dir1 unwanted_dir2, $(widcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "include standard_defs.mk" -o $(вихід)
&echo "_include Additional_defs.mk" -o >>$(вихід)
# Якщо файл Additional_defs.mk існує, то
# він буде включено, але якщо він не існує,
# оператор _include буде проігноровано.

Тепер самі make-файли будуть автоматично створені.

Один makefile тільки at топ рівень

Якщо всі ваші make-файли ідентичні, ви можете запитати: навіщо мені мати make-файл у кожному
рівень? Чому б не помістити це все в make-файл верхнього рівня?

Так, це можна зробити. Основним недоліком є ​​те, що стає важче вказати
різні варіанти збірки для кожного підкаталогу. Другим недоліком є ​​те, що ваш
makefile, ймовірно, стане трохи важче читати.

Ось приклад, як це зробити:

# Макет-файл верхнього рівня для ієрархії каталогів. Будує програму
# із набору спільних бібліотек як приклад. (Див. застереження вище
# пояснюючи, чому ви можете використовувати інкрементальне зв’язування чи інше
# підхід, а не спільні бібліотеки.)
makepp_percent_subdirs := 1 # Дозволити % відповідати кільком каталогам.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(widcard **))
CFLAGS := -g -O2
ВКЛЮЧАЄ := -Включає

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(ВКЛЮЧИТЬ) $(CFLAGS) -c $(вхід) -o $(вихід)

$(за кожний)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo: foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(вихід) $(входи)
# Правило створення всіх бібліотек.

програма : main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(вихід) $(входи)

включає/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(вхід) $(вихід)
# Зразок правила для загальнодоступного копіювання
# доступний файл .h у потрібне місце.

A очистити мета

Традиційні make-файли містять чисту мету, яка дозволяє видалити все, що було
побудований. Є три причини, чому ви не повинні робити цього з makepp:

1. Makepp докладає всіх зусиль, щоб забезпечити правильну збірку. Тож відчайдушне «Я ні
знайте, що не так», змушувати вас хотіти почати з нуля залишилося в минулому.

2. Люди іноді намагаються заощадити час, роблячи дві суперечливі речі одночасно:
«очистити все». Це може збити з пантелику розумну систему підстановки makepp, тому що так
спочатку дізнайтеся факти, перш ніж щось робити. Потім настає чиста дія, яка діє
не розповідати makepp, що він робить (насправді він не може, тому що він щось скасовує --
на відміну від того, для чого призначений інструмент побудови). Потім йде "всі", але оновлені файли,
які там, де є, таємничим чином зникли.

3. Є команда "makeppclean", яка робить те ж саме, але більш ефективно.

Проте ми зберігаємо цей історичний розділ, оскільки він дещо розповідає про
спосіб роботи makepp: фальшива ціль під назвою "clean" - це просто назва для набору команд
видалити всі файли, які є результатом процесу make. Зазвичай виглядає чиста мішень
щось на зразок цього:

$(фальшивий чистий):
&rm -fm $(підстановка *.o .makepp_log)
# -m і .makepp_log позбавляються від усього сміття makepp.

Замість того, щоб явно вказувати файли, які ви хочете видалити, ви також можете вказати makepp
видалити все, що він вміє будувати, наприклад:

$(фальшивий чистий):
&rm -fm .makepp_log $(only_targets *)

Це має перевагу в тому, що якщо будь-який із ваших вихідних файлів можна створити з інших файлів,
вони також будуть видалені; з іншого боку, несвіжий .o файли (файли, які раніше були
можна зібрати, але вихідний файл якого було видалено) не буде видалено.

Якщо у вас є збірка, яка включає файли make-файлів у кількох різних каталогах, ваш топ-
makefile рівня може посилатися на «чисту» ціль (або будь-яку іншу фальшиву мету) в іншому
make-файл:

# Makefile верхнього рівня
SUBDIRS := sub1 sub2

# правила побудови тут

# Очистіть після збірки:
$(фальшиве очищення): $(SUBDIRS)/чисте
&rm -fm .makepp_log $(only_targets *)

Крім того, ви можете помістити свою «чисту» ціль лише у make-файл верхнього рівня і мати його
обробити всі каталоги, наприклад:

$(фальшивий чистий):
&rm -fm $(only_targets **/*)

використання Qt потужність препроцесор
У цьому прикладі показано make-файл для утиліти, яка використовує бібліотеку Qt GUI від Nokia (див
<http://qt.nokia.com>). Єдине, що трохи незвичайне в цьому, це те, що ви
повинен запускати препроцесор під назвою "moc" у більшості файлів ".h", які містять визначення віджетів,
але ви не хочете запускати "moc" для будь-яких файлів ".h", які не використовують макрос "Q_OBJECT".

Автоматично визначення який файли необхідність потужність файли

Ви можете, звичайно, просто перерахувати всі файли ".h", для яких потрібно запустити "moc".
Однак, якщо ви швидко розробляєте нові віджети, це може бути чимось неприємним
продовжуйте оновлювати список у make-файлі. Ви можете обійти необхідність перерахування moc
модулі явно з чимось на кшталт цього:

MOC := $(QTDIR)/bin/moc
МОДУЛИ := будь-які модулі, які є у вашій програмі
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Сканує всі файли .h на наявність макросу Q_OBJECT.

my_program: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(входи) -o $(вихід)

moc_%.cxx: %.h # Створює файли moc з файлів .h.
$(MOC) $(вхід) -o $(вихід)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(вхід) -o $(вихід)

Цей підхід сканує кожну з ваших .h файлів щоразу, коли makepp запускається, шукаючи файл
Макрос "Q_OBJECT". Це звучить дорого, але, ймовірно, це не займе багато часу. (В .h
Всі файли все одно доведеться завантажувати з диска в процесі компіляції, тому вони будуть
кешуватися.)

#включати .moc файл

Інший підхід полягає в тому, щоб "#include" виведення з препроцесора "moc" у вашому віджеті
файл реалізації. Це означає, що ви повинні не забути написати «#include», але він має
перевага в тому, що існує менше модулів для компіляції, і тому компіляція відбувається швидше.
(Для більшості компіляцій C++ більшість часу витрачається на читання заголовних файлів, і
вихідні дані препроцесора повинні включати майже стільки файлів, скільки ваш віджет
все одно.) Наприклад:

// my_widget.h
клас MyWidget : публічний QWidget {
Q_OBJECT
// ...
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc є результатом
// препроцесор moc.
// Інші речі щодо реалізації тут.
MyWidget::MyWidget(QWidget * батьківський, const char * ім'я) :
QWidget (батько, ім'я)
{
// ...
}

Тепер вам потрібно мати правило у вашому make-файлі для створення всіх файлів ".moc", наприклад:

MOC := $(QTDIR)/bin/moc
# Правило створення файлів .moc:
%.moc: %.h
$(MOC) $(вхід) -o $(вихід)

Makepp достатньо розумний, щоб усвідомити, що йому потрібно створити "my_widget.moc", якщо він цього не зробить
вже існує, або якщо вона застаріла.

Цей другий підхід я зазвичай використовую, оскільки він прискорює компіляцію.

Заміни та цінності не підтримується зробити ідіоми
ПОСТАНОВИТЬ ЦІЛІ

Іноді люди мають правила у своєму make-файлі залежно від того, яку ціль вони створюють,
за допомогою спеціальної змінної "MAKECMDGOALS". Наприклад, іноді можна побачити такі речі
це:

ifneq ($(виробництво фільтра, $(MAKECMDGOALS)),)
CFLAGS := -O2
ще
CFLAGS := -g
ENDIF

Це буде добре працювати з makepp. Однак я рекомендую не використовувати «MAKECMDGOALS» для таких
випадків (так само GNU робить посібник). Вам краще поставити свій оптимізований і
налагоджено скомпільований .o файли в окремих каталогах, або надання їм різних префіксів або
суфікси або використання репозиторіїв, щоб тримати їх окремо.

Мабуть, єдиний випадок, коли ви дійсно захочете посилатися на "MAKECMDGOALS", це якщо це
Завантаження ваших make-файлів займає багато часу, і це не потрібно для вашої «чистої» цілі
(але вам не потрібна чиста ціль). Наприклад,

ifneq ($(MAKECMDGOALS),чистий)
load_makefile $(підстановка **/Makeppfile)
ще
no_implicit_load . # Заборонити автоматичне завантаження будь-яких інших make-файлів.
ENDIF

$(фальшивий чистий):
&rm -f $(підстановка **/*.o)

Рекурсивний зробити до будувати in різний каталоги

Дивіться «Поради для кількох каталогів» у makepp_cookbook.

Рекурсивний зробити до зміна значення of a змінна

Деякі make-файли повторно викликають себе з іншим значенням змінної, наприклад, debug
target у наступному фрагменті make-файлу

.PHONY: усі налагодження

оптимізовано:
$(MAKE) програма CFLAGS=-O2

відлагоджувати:
$(MAKE) програма CFLAGS=-g

програма: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

Якщо користувач вводить "make debug", він створює програму в режимі за замовчуванням з увімкненим налагодженням
замість оптимізації.

Кращий спосіб зробити це - створити дві різні програми з двома різними наборами
об'єктні файли, наприклад:

CFLAGS := -O2
ПРАПОРЦІ_НАЛАШЕННЯ := -g
МОДУЛИ := аб

програма: $(MODULES).o
$(CC) $(CFLAGS) $(входи) -o $(вихід)

налагодження/програма: debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(входи) -o $(вихід)

%.o : %.c
$(CC) $(CFLAGS) -c $(вхід) -o $(вихід)

debug/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(вхід) -o $(вихід)

$(фальшиве налагодження): налагодження/програма

Перевага такого способу полягає в тому, що (а) вам не потрібно все перебудовувати
перейти з налагодження до оптимізованого і назад; (б)

Вище можна написати дещо стисло, використовуючи репозиторії. Наступні
makefile точно еквівалентний:

налагодження репозиторію=. # Робить підкаталог debug схожим на копію
# поточний підкаталог.
load_makefile налагодження CFLAGS=-g
# Замінювати CFLAGS при виклику в підкаталозі debug
CFLAGS := -O2 # Значення CFLAGS при виклику в цьому підкаталозі

програма: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

$(фальшиве налагодження): налагодження/програма
# Якщо користувач вводить "makepp debug", збирає
# налагодження/програма замість програми.

Різне Поради
Як do I будувати один частина інакше просто раз?

Makepp робить це важко, оскільки результат не відповідає правилам.
Але є ситуації, коли це може знадобитися, наприклад, для компіляції лише одного модуля
важка інформація про налагодження. Ви можете досягти цього за два кроки, спочатку створивши
залежність окремо, а потім виключивши її з фази підключення:

makepp DEBUG=3 buggy.o # Створіть його за допомогою іншого параметра.
makepp --dont-build=buggy.o buggy # Використовуйте його, незважаючи на "неправильний" варіант збірки.

Як do I зробити Переконайтеся my вихід каталоги існує?

Ви можете вказати правило для створення вихідного каталогу, а потім переконатися, що кожен файл
входить у вихідний каталог залежить від цього. Але зазвичай простіше зробити щось подібне
це:

# Класичний спосіб
манекен := $(тест оболонки -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Зазвичай це простіше, ніж робити всі файли залежними
# $(OUTPUT_DIRECTORY) і має правило для його створення.
# Зверніть увагу, що ви повинні використовувати := замість =, щоб змусити це зробити
# виконати негайно.
# Альтернативний підхід: використання коду Perl, локальна вар. OUTPUT_DIRECTORY
perl_begin
-d $OUTPUT_DIRECTORY або mkdir $OUTPUT_DIRECTORY;
perl_end
# Сучасний спосіб нічого не робить для існуючих каталогів
&mkdir -p $(OUTPUT_DIRECTORY)

Один із цих операторів має бути у верхній частині вашого make-файлу, щоб вони виконувались
перед тим, що може знадобитися каталог.

Як do I змусити a команда до виконувати on кожен будувати?

Найпростіший спосіб - це взагалі не використовувати механізм правила, а просто виконати його, наприклад
це:

манекен := $(дата оболонки > мітка часу_останньої_складання)

Або помістіть його в блок perl, наприклад:

perl_begin
system("команда для виконання");
perl_end

Недоліком цього підходу є те, що він буде виконаний, навіть якщо це не пов’язана ціль
запускається.

Другий підхід — оголосити файл фальшивою метою, навіть якщо це справжній файл.
Це змусить makepp щоразу повторно виконувати команду для його побудови, але лише за умови
з’являється у списку залежностей деякого правила.

Як do I скорочувати displayed будувати команди?

Часто існує так багато варіантів для команд компіляції, що те, що відображається на
екран не читається. Ви можете змінити те, що відображається, придушивши відображення
всю команду, а потім явно роздрукуйте цікаву частину команди. Його
легко роздрукувати лише відповідну частину команди, використовуючи "$(filter_out)", наприклад
це:

ALL_CFLAGS = $(CFLAGS) $(ВКЛЮЧИТЬ) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(вхід)
@$(CC) $(ALL_CFLAGS) -c $(вхід) -o $(вихід)

("@" перед командою блокує друк команди.)

Це дозволить вам побачити більшість цікавих опцій, але не відобразить усі
включають каталоги (яких часто дуже багато!). Якщо частина вас цікавить
in є суміжним у вашій команді, ви також можете використовувати функцію "друк" (яка додає a
новий рядок, тому вам не потрібно кілька з них):

ціль:
@... $(роздрукувати цікаву частину) ...

Як do I конвертувати a файл в залежності?

Для деяких незрозумілих форматів файлів не варто впроваджувати сканер. В одному проекті
у нас є файли xml, скажімо foobar.xml який містить залежності для foobar.out:


а
б
c


Ми вирішили дотримуватися цього простого макета, тому нам не потрібно аналізувати xml. З
Вбудований &sed, ось що ми робимо з трьома простими замінами для трьох видів
рядки:

%.d: %.xml
&sed 's! !$(stem).out: \\! || s! (.+) !$$1 \\! || s! !# Порожній!' \
$(вхід) -o $(вихід)

включити foobar.d

Спроба включити це, спочатку створює "foobar.d":

foobar.out: \
а \
б \
c \
# Порожній

Порожній (просто коментар або дійсно порожній) рядок дозволяє уникнути турботи про закінчення
зворотний скіс. Альтернативою створення багаторядкового списку є:

%.d: %.xml
&sed 's! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(вхід) -o $(вихід)

включити foobar.d

Це створює еквівалент:

foobar.out: $((
a
b
c
))

Якщо вам потрібно зробити більш складне перезапис, визначте функцію в файлі make-файлу або в a
модуль, який ви включаєте. Наприклад, undefining $_ пропустить рядки введення:

sub myfilter {
повернути undef $_ якщо /
мій $stem = f_stem;
s! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed 's! !$(stem).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(вхід) -o $(вихід)

включити foobar.d

Використовуйте makepp_cookbook онлайн за допомогою служб onworks.net


Безкоштовні сервери та робочі станції

Завантажте програми для Windows і Linux

Команди Linux

Ad