Что означают символы make-файла $ @ и $ <? - PullRequest
345 голосов
/ 10 июля 2010
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 ]

419 голосов
/ 10 июля 2010

$@ - это имя создаваемого файла, а $< - первое условие (обычно исходный файл). Вы можете найти список всех этих специальных переменных в GNU Make manual .

Например, рассмотрим следующую декларацию:

all: library.cpp main.cpp

В этом случае:

  • $@ оценивается как all
  • $< оценивается как library.cpp
  • $^ оценивается как library.cpp main.cpp
67 голосов
/ 31 августа 2013

$@ и $< называются автоматическими переменными .Переменная $@ представляет имя файла, который был создан (т. Е. Цель), а $< представляет первую предпосылку, необходимую для создания выходного файла.
Например:

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

Здесь,hello.o - выходной файл.Это то, что $@ расширяется до.Первая зависимость - hello.c.Это то, что $< расширяется до.

Флаг -c генерирует файл .o;см. man gcc для более подробного объяснения.-o определяет выходной файл для создания.

Для получения дополнительной информации вы можете прочитать эту статью о Linux Makefiles .

Также вы можете проверить GNU make руководства .Это облегчит создание Make-файлов и их отладку.

Если вы запустите эту команду, она выведет базу данных make-файла:

make -p 
48 голосов
/ 08 июня 2016

С Управление проектами с помощью GNU Make, 3-е издание (под Лицензия на бесплатную документацию GNU ):

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

Существует семь «основных» автоматических переменных:

  • $@: имя файла, представляющее цель.

  • $%: элемент имени файла спецификации элемента архива.

  • $<: имя файла первой предпосылки.

  • $?: имена всех предпосылок, которые новее, чем цель, разделенные пробелами.

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

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

  • $*: основа целевого имени файла. Стебель обычно является именем файла без суффикса. Его использование вне шаблонных правил не рекомендуется.

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

34 голосов
/ 10 июля 2010

$@ и $< являются специальными макросами.

Где:

$@ - имя файла цели.

$< - имя первой зависимости.

18 голосов
/ 12 апреля 2017

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: вернемся к короткому make-файлу, довольно легко читаемому

Здесь правило .cpp.o определяет, как построить anyfile.o из anyfile.cpp.

  • $< соответствует первой зависимости, в данном случае anyfile.cpp
  • $@ соответствует цели, в данном случае anyfile.o.

Другие изменения, присутствующие в Makefile:

  • Созданиепроще изменить компиляторы с g ++ на любой компилятор C ++.
  • Упрощение изменения параметров компилятора.
  • Упрощение изменения параметров компоновщика.
  • Создание егопроще изменять исходные файлы C ++ и вывод.
  • Добавлено правило по умолчанию 'all', которое действует как quick проверьте, чтобы убедиться, что все ваши исходные файлы присутствуют до того, как будет предпринята попытка построить ваше приложение.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...