Що означають символи makefile $ @ і $ <?


416
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
    $(CC) $(CFLAGS) $< -o $@

Що робити $@і $<робити саме?


5
Посилання вище перервано, ось ще одне: gnu.org/software/make/manual/html_node/Automatic-Variables.html
asciz

1
Привіт, що означає це ".cpp.o:" як ціль? (попередній рядок?).
псевдонім_127

3
".Cpp.o:" означає будівництво ".o" (об'єктні файли) з ".cpp" (вихідні файли)
jaguzu

1
Я відчуваю, що слід зазначити, що на наступному посиланні є підручник із створення, з якого я вважаю, що Мохіт отримав макіяж у своєму посту. mrbook.org/blog/tutorials/make
DeepDeadpool

Microsoft називає це макросом імені файлу (для NMAKE), який зрозуміліше, ніж автоматичні змінні (для MAKE). Корисно бачити обидві сторони в освітніх цілях.
Іванзіньо

Відповіді:


502

$@- ім'я генерується файла та $<перша умова (зазвичай це вихідний файл). Перелік усіх цих спеціальних змінних ви можете знайти в посібнику GNU Make .

Наприклад, розглянемо таку заяву:

all: library.cpp main.cpp

В цьому випадку:

  • $@ оцінює до all
  • $< оцінює до library.cpp
  • $^ оцінює до library.cpp main.cpp

16
Варто зазначити, що $@не обов'язково в кінцевому підсумку бути файлом, це також може бути ім'ям .PHONYцілі.
Ефемера

Чи можу я додати до параметрів командного рядка це: $@sдля генерації-виводу, наприклад name.os?
huseyin tugrul buyukisik

4
Остерігайтеся, коли перша залежність є змінною, що представляє список, $ <оцінюється після її розширення. Отже, коли LIST = lib1.cpp lib2.cpp, і все: $ {LIST} main.cpp, $ <оцінюється просто lib1.cpp. Кілька років тому я провів деякий час, з'ясовуючи, що відбувається в результаті, викликаному такою поведінкою.
Чан Кім

Загалом $ @ посилається на ім'я цілі, яке знаходиться зліва від:
Діпак Кіран

78

$@І $<називаються автоматичними змінними . Змінна $@являє собою ім'я створеного файла (тобто цілі) і $<являє собою першу необхідну умову, необхідну для створення вихідного файлу.
Наприклад:

hello.o: hello.c hello.h
         gcc -c $< -o $@

Тут hello.oзнаходиться вихідний файл. Це те, на що $@розширюється. Перша залежність є hello.c. Ось що і $<розширюється.

-cПрапор генерує .oфайл; див. man gccдля більш детального пояснення. -oВизначає вихідний файл , щоб створити.

Для отримання додаткової інформації ви можете прочитати цю статтю про Linux Makefiles .

Також ви можете перевірити посібники GNU make . Це полегшить створення Makefiles та їх налагодження.

Якщо запустити цю команду, вона виведе базу даних makefile:

make -p 

1
Ваша відповідь звучить як би $<розшириться на hello.c hello.h(обидва). Будь ласка, поясніть.
Д-р Беко

Так, він буде включати в себе як hello.c і hello.h
спритний

19
$<це лише перший пункт. Щоб включити всіх, використовуйте $^.
Д-р Беко

1
Д-р Беко має рацію. Автор повинен змінити свою відповідь.
PT Huynh

67

З управління проектами за допомогою GNU Make, 3-е видання, стор. 16 (це під ліцензією GNU Free Documentation ):

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

Існує сім "основних" автоматичних змінних:

  • $@: Ім'я файлу, що представляє ціль.

  • $%: Елемент імені файла специфікації члена архіву.

  • $<: Ім'я файлу першої необхідної умови.

  • $?: Назви всіх необхідних умов, ніж ціль, розділені пробілами.

  • $^: Імена файлів усіх передумов, розділених пробілами. У цьому списку видалено повторювані імена файлів, оскільки для більшості застосувань, таких як компіляція, копіювання тощо, дублікати не потрібні.

  • $+: Подібно до $^цього, це назви всіх передумов, розділених пробілами, крім тих, що $+містять дублікати. Ця змінна була створена для конкретних ситуацій, таких як аргументи для лінкерів, де повторювані значення мають значення.

  • $*: Стебло імені цільового файлу. Стебло - це найменування файлу без суфікса. Її використання поза правилами зразків не рекомендується.

Крім того, кожна з перелічених вище змінних має два варіанти сумісності з іншими марками. Один варіант повертає лише частину значення значення. Це зазначено з допомогою додавання «D» на символ, $(@D), $(<D)і т.д. Інший варіант повертає тільки файл частину вартості. Це позначено приєднання «F» на символ, $(@F), $(<F)і т.д. Зверніть увагу , що ці імена варіантів більш ніж один персонаж довго і повинні бути укладені в дужках. GNU make пропонує більш читабельну альтернативу з функціями dir та notdir.


37

$@І $<спеціальні макроси.

Де:

$@ - ім'я файлу цілі.

$< - назва першої залежності.


19

Makefile створює helloвиконуваний файл , якщо якийсь - або один з main.cpp, hello.cpp, factorial.cppзмінилося. Найменшим можливим Makefile для досягнення цієї специфікації могло бути:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • pro: дуже легко читати
  • con: підтримка кошмару, дублювання залежності C ++
  • con: проблема ефективності, ми перекомпілюємо всі C ++, навіть якщо було змінено лише один

Щоб покращити вищесказане, ми компілюємо лише ті файли C ++, які були відредаговані. Потім ми просто зв'язуємо отримані об'єктні файли разом.

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

main.o: main.cpp
    g++ -c main.cpp

hello.o: hello.cpp
    g++ -c hello.cpp

factorial.o: factorial.cpp
    g++ -c factorial.cpp
  • pro: виправляє проблему ефективності
  • con: новий кошмар з технічного обслуговування, потенційний друк на правилах файлів об'єктів

Щоб покращити це, ми можемо замінити всі правила об’єктного файлу одним .cpp.oправилом:

OBJECTS=main.o hello.o factorial.o

hello: $(OBJECTS)
    g++ -o hello $(OBJECTS)

.cpp.o:
    g++ -c $< -o $@
  • Pro: повернутися до короткого файлу, який легко читається

Тут .cpp.oправило визначає , як будувати anyfile.oз anyfile.cpp.

  • $< відповідає першій залежності, в цьому випадку, anyfile.cpp
  • $@відповідає меті, в даному випадку, anyfile.o.

Інші зміни, присутні в Makefile:

  • Полегшення зміни компіляторів з g ++ на будь-який компілятор C ++.
  • Полегшення зміни параметрів компілятора.
  • Полегшення зміни параметрів лінкера.
  • Полегшаючи зміну вихідних файлів C ++ та вихід.
  • Додано правило "all" за замовчуванням, яке виконує функцію швидкої перевірки, щоб забезпечити наявність усіх вихідних файлів до того, як буде зроблена спроба побудови програми.

1

у прикладі, якщо ви хочете збирати джерела, але маєте об’єкти в іншому каталозі:

Вам потрібно зробити:

gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...

але при більшості макросів результатом будуть усі об'єкти, за якими слідують усі джерела, наприклад:

gcc -c -o <all OBJ path> <all SRC path>

так що це нічого не складе ^^, і ви не зможете помістити файли об’єктів в інший dir :(

рішення - використовувати ці спеціальні макроси

$@ $<

це створить .o файл (obj / file.o) для кожного .c-файлу в SRC (src / file.c)

$(OBJ):$(SRC)
   gcc -c -o $@ $< $(HEADERS) $(FLAGS)

це означає :

    $@ = $(OBJ)
    $< = $(SRC)

але рядки за рядками ВСТАНОВИТИ всі рядки OBJ, а потім всі лінії SRC


Цікаво, що ви робите зі всією цією кількістю часу, яку ви економите, набравши "u" замість "you"?
Іванзіньо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.