Яка мета .PHONY в makefile?


1736

Що .PHONYозначає Makefile? Я пережив це , але це занадто складно.

Хтось може мені це пояснити простими словами?

Відповіді:


1944

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

foo: bar
  create_one_from_the_other foo bar

Однак іноді потрібно, щоб ваш Makefile запускав команди, які не представляють фізичні файли у файловій системі. Хорошими прикладами для цього є загальні цілі "чисто" та "все". Швидше за все, це не так, але, можливо,clean у вашому головному каталозі може бути названий файл . У такому випадку Make буде заплутаний, оскільки за замовчуванням cleanціль буде пов’язана з цим файлом, і Make запустить її лише тоді, коли файл не буде оновлений в залежності від його залежностей.

Ці спеціальні цілі називаються фальшивими, і ви можете чітко сказати Зробити, що вони не пов'язані з файлами, наприклад:

.PHONY: clean
clean:
  rm -rf *.o

Тепер make cleanвін запуститься, як очікувалося, навіть якщо у вас є ім’я з файлом clean.

З точки зору Make, підроблена ціль - це просто ціль, яка завжди застаріла, тому щоразу, коли ви запитаєте make <phony_target>, вона буде працювати, незалежно від стану файлової системи. Деякі загальні makeцілі, які часто фальшиво є: all, install, clean, distclean, TAGS, info, check.


49
@eSKay: "чому його називають" фальшивим "?" - тому що це не реальна ціль. Тобто ім'я цілі - це не файл, який створюється командами цієї цілі.
Бернард

96
@Lazer: Я не знаю, чи ти є носієм англійської мови. Я не. слово фальшиве не означає, як воно звучить. en.wiktionary.org/wiki/phony говорить: Шахрайство; підробка; маючи оманливий вигляд.
Бахбар,

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

9
Зауважте, що вам не потрібно використовувати .PHONY, якщо у вас немає файлу з таким же ім'ям, як завдання. Завдання завжди буде виконуватися в будь-якому випадку, і Makefile буде більш читабельним.
Бернард

15
"фальшива ціль - це просто ціль, яка завжди застаріла" - чудове пояснення!
Даніель

730

Припустимо, у вас є installціль, що дуже часто зустрічається в makefiles. Якщо ви не використовуєте .PHONY, а названий файл installіснує в тому ж каталозі, що і Makefile, тоді make installнічого не буде робити . Це пояснюється тим, що Make інтерпретує правило таким чином, щоб означати "виконувати такий-і-такий рецепт для створення файлу з назвою install". Оскільки файл вже є, а його залежності не змінилися, нічого не буде зроблено.

Однак якщо ви зробите installцільовий PHONY, він скаже інструменту make, що ціль вигадана, і цей make не повинен очікувати, що він створить фактичний файл. Отже, він не перевірить, чи installіснує файл, тобто: а) його поведінку не буде змінено, якщо файл існує, і б) додаткові stat()не будуть викликатися.

Як правило, всі цілі у вашому Makefile, які не створюють вихідний файл з тим самим іменем, як ім'я цілі, повинні бути PHONY. Це , як правило , включає в себе all, install, clean, distclean, і так далі.


6
@PineappleUndertheSea Прийнята відповідь значно покращилася від початкового рівня нікчемності, і зараз так само хороша, як і ця. Мені довелося переглянути його історію редагування, щоб зрозуміти ваш коментар.
Марк Амері

2
Це здається безглуздим, оскільки я ніколи не матиму файлів з назвою «встановити» тощо. Більшість файлів мають розширення файлу, а файли без розширення файлів зазвичай у всіх кришках, як-от "README". Знову ж таки, якщо у вас є сценарій bash з назвою "install" замість "install.sh", вам буде погано провести час.
ядерний

6
@JasonTu Це не обов'язково правда. Конвенції Bash сценаріїв пропонують вам опустити .shабо .bashрозширення для "програм", які працюють так, як вони мають основну функцію, і резервуйте додавання розширення для бібліотек, які ви включаєте ( source mylib.sh). Насправді я потрапив до цього питання ТАК, тому що у мене був сценарій у тому самому каталозі, що і мій Makefile називавсяinstall
Кайл

10
@Kyle Так, я не впевнений, що означало моє минуле «я». Цими днями я .PHONYвесь час використовую ...
ядерний

2
@JasonTu Рішення тут просте: побудуйте машину часу і «замініть» своє минуле «я». Я рекомендую взяти з собою лопату, щоб ніхто не зрозумів, що ви .PHONYверсія.
Mateen Ulhaq

120

ПРИМІТКА : Інструмент make читає makefile і перевіряє часові позначки модифікації файлів з обох боків символу ':' у правилі.

Приклад

У каталозі 'test' є такі файли:

prerit@vvdn105:~/test$ ls
hello  hello.c  makefile

У makefile правило визначається так:

hello:hello.c
    cc hello.c -o hello

Тепер припустимо, що файл 'привіт' - це текстовий файл, що містить деякі дані, створений після файлу 'hello.c'. Отже модифікація (або створення) часової позначки "привіт" буде новішою, ніж "hello.c". Отже, коли ми будемо викликати "make hello" з командного рядка, він надрукує як:

make: `hello' is up to date.

Тепер перейдіть до файлу 'hello.c' та покладіть у нього білі пробіли, що не впливає на синтаксис чи логіку коду, тоді збережіть та закрийте. Тепер модифікація часу hello.c є новішою, ніж "hello". Тепер, якщо ви викликаєте "привіт", він виконує команди як:

cc hello.c -o hello

І файл 'привіт' (текстовий файл) буде перезаписаний новим бінарним файлом 'привіт' (результат вищевказаної команди компіляції).

Якщо ми використовуємо .PHONY у makefile так:

.PHONY:hello

hello:hello.c
    cc hello.c -o hello

а потім викликати "привіт", він ігнорує будь-який файл, присутній у "тесті" pwd, і виконуватиме команду щоразу.

Тепер припустимо, що цільовий привіт не має оголошених залежностей:

hello:
    cc hello.c -o hello

і файл 'привіт' вже присутній у тесті pwd ', тоді' make hello 'завжди відображатиметься як:

make: `hello' is up to date.

3
Мало того, що команди, які я запускаю, мають сенс, це, нарешті, makeмає сенс у цілому, це все про файли! Дякую за цю відповідь.
Kzqai

80
.PHONY: install
  • означає, що слово "встановити" не означає ім'я файлу в цьому Makefile;
  • означає, що Makefile не має нічого спільного з файлом під назвою "встановити" в одному каталозі.


33

Найкращим поясненням є сам посібник GNU: розділ 4.6 «Цільові цілі» .

.PHONYє одним із спеціальних вбудованих цільових імен марки . Є й інші цілі, які можуть вас зацікавити, тому варто переглядати ці посилання.

Коли настане час розглянути ціль .PHONY, make запустить її рецепт беззастережно, незалежно від того, існує файл з цим ім'ям або який його час останньої модифікації.

Можливо, вам також будуть цікаві стандартні цілі марки, такі як allі clean.


11

Існує також одна важлива хитра трактування ". FONY" - коли фізична ціль залежить від підробленої цілі, яка залежить від іншої фізичної цілі:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Ви просто очікуєте, що якщо ви оновили TARGET2, тоді TARGET1 слід вважати старим проти TARGET1, тому TARGET1 слід відновити. І це дійсно працює таким чином .

Найскладніша частина полягає в тому, що TARGET2 не є неспроможним проти TARGET1 - у такому випадку ви повинні очікувати, що TARGET1 не повинен бути відновлений.

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

Поміркуйте:

all: fileall

fileall: file2 filefwd
    echo file2 file1 >fileall


file2: file2.src
    echo file2.src >file2

file1: file1.src
    echo file1.src >file1
    echo file1.src >>file1

.PHONY: filefwd
.PHONY: filefwd2

filefwd: filefwd2

filefwd2: file1
    @echo "Produced target file1"


prepare:
    echo "Some text 1" >> file1.src
    echo "Some text 2" >> file2.src

Ви можете пограти з цим:

  • спочатку зробіть "підготовку", щоб підготувати "вихідні файли"
  • пограйте з цим, торкнувшись певних файлів, щоб побачити їх оновленими

Ви можете бачити, що файл файлів залежить від файлу1 опосередковано через хибну ціль - але він завжди перебудовується через цю залежність. Якщо змінити залежність в fileallвід filefwdдо file, тепер fileallне отримує перебудований кожен раз, але тільки тоді , коли який - або з залежних цілей несвіжий проти нього у вигляді файлу.


5

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

Ви можете помістити кілька .PHONY:у свої Makefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

Є ще один спосіб оголосити підроблені цілі: просто поставте "::"

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

«::» має особливе значення: цілі є фальшивими плюс вони можуть з'являтися кілька разів:

clean ::
    rm file1

...


clean ::
    rm file2

Командні блоки будуть називатися один за одним.


3

Я часто використовую їх, щоб сказати, що ціль за замовчуванням не стріляти.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Без фальшиво, make supercleanстрілятиме clean, andsomethingelseі catcher superclean; але з PHONY make supercleanне запустить catcher superclean.

Нам не потрібно турбуватися про те, щоб сказати зробити це clean ціль - ТЕЛЕФОН, тому що це не зовсім фальшиво. Хоча він ніколи не видає чистий файл, він має команди для запуску, тому make вважатиме, що це кінцева мета.

Однак supercleanціль справді є хибною, тому make make спробує скласти її з будь-яким іншим, що забезпечує деп-ціли для supercleanцілі - сюди входять інші supercleanцілі та %ціль.

Зверніть увагу , що ми взагалі нічого не говорить про те, andsomethingelseчи blah, так що вони явно йдуть на видовище.

Вихід виглядає приблизно так:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.