614
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 $@

What do the $@ and $< do exactly?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mohit Deshpande
  • 53,877
  • 76
  • 193
  • 251
  • 9
    The link above is broken, here is the another one: http://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html – asciz Jan 26 '13 at 01:12
  • 3
    The ".cpp.o:" means building ".o" (object files) from ".cpp" (source files) – jaguzu Sep 13 '13 at 06:30
  • 1
    I feel it should be noted there is a make tutorial at the following link from which I believe Mohit obtained the makefile in his post. http://mrbook.org/blog/tutorials/make/ – DeepDeadpool Oct 29 '15 at 17:14
  • Microsoft calls it [Filename Macros](https://learn.microsoft.com/en-us/cpp/build/reference/filename-macros?view=vs-2019)(for NMAKE) which is clearer than [Automatic Variables](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html)(for MAKE). It's useful to see both sides for educational purposes. –  May 14 '20 at 18:34
  • @user2188550, both sides of what? – Jason Hemann May 15 '22 at 13:29

6 Answers6

788

$@ is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.

For example, consider the following declaration:

all: library.cpp main.cpp

In this case:

  • $@ evaluates to all
  • $< evaluates to library.cpp
  • $^ evaluates to library.cpp main.cpp
Lucas Derraugh
  • 6,929
  • 3
  • 27
  • 43
bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • 42
    It's worth noting that `$@` does not necessarily have to end up being a file, it could also be the name of a `.PHONY` target. – Ephemera Apr 11 '15 at 08:04
  • Can I add to commandline options this: `$@s` to generate assembly-output such as name.os? – huseyin tugrul buyukisik Jul 30 '17 at 16:25
  • 10
    Beware when the first dependency is a variable representing a list, $< is evaluated after it is expanded. So when LIST = lib1.cpp lib2.cpp, and all: ${LIST} main.cpp, $< is evaluated to just lib1.cpp. A few years ago, I had spend some time figuring out what's happend in the result caused by this behaviour. – Chan Kim Jul 11 '18 at 05:48
  • 2
    In general $@ refers to the target name which is to the left side of the : – Deepak Kiran May 07 '20 at 15:32
  • If anyone has enough rep to make a 1-character change, the http:// link in the above post now redirects to an https:// link and should be updated. – AJM Feb 11 '22 at 15:05
  • These are only true for GNU Make. On BSD Make `$<` refers to the implied source in a suffix transformation rule, and is not defined at all for explicit rules. `$^` isn't defined at all, that functionality is given by either `${.ALLSRC}` or `$>`. – Roflcopter4 Apr 05 '22 at 01:19
  • 1
    instead of `$<` and `$^`, wouldn't this just be a lot more readable if these were treated the same way bash arguments are treated (`$1` `$2`, ...)? – Snowball_ May 02 '22 at 20:52
  • Any clue what double `$$` differ? E.g. `$$@` or `$$<` – vmemmap Aug 05 '23 at 09:08
141

From Managing Projects with GNU Make, 3rd Edition, p. 16 (it's under GNU Free Documentation License):

Automatic variables are set by make after a rule is matched. They provide access to elements from the target and prerequisite lists so you don’t have to explicitly specify any filenames. They are very useful for avoiding code duplication, but are critical when defining more general pattern rules.

There are seven “core” automatic variables:

  • $@: The filename representing the target.

  • $%: The filename element of an archive member specification.

  • $<: The filename of the first prerequisite.

  • $?: The names of all prerequisites that are newer than the target, separated by spaces.

  • $^: The filenames of all the prerequisites, separated by spaces. This list has duplicate filenames removed since for most uses, such as compiling, copying, etc., duplicates are not wanted.

  • $+: Similar to $^, this is the names of all the prerequisites separated by spaces, except that $+ includes duplicates. This variable was created for specific situations such as arguments to linkers where duplicate values have meaning.

  • $*: The stem of the target filename. A stem is typically a filename without its suffix. Its use outside of pattern rules is discouraged.

In addition, each of the above variables has two variants for compatibility with other makes. One variant returns only the directory portion of the value. This is indicated by appending a “D” to the symbol, $(@D), $(<D), etc. The other variant returns only the file portion of the value. This is indicated by appending an “F” to the symbol, $(@F), $(<F), etc. Note that these variant names are more than one character long and so must be enclosed in parentheses. GNU make provides a more readable alternative with the dir and notdir functions.

alex
  • 10,900
  • 15
  • 70
  • 100
103

The $@ and $< are called automatic variables. The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.
For example:

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

Here, hello.o is the output file. This is what $@ expands to. The first dependency is hello.c. That's what $< expands to.

The -c flag generates the .o file; see man gcc for a more detailed explanation. The -o specifies the output file to create.

For further details, you can read this article on linoxide about Linux Makefiles.

Also, you can check the GNU make manuals. It will make it easier to make Makefiles and to debug them.

If you run this command, it will output the makefile database:

make -p 
dexterous
  • 6,422
  • 12
  • 51
  • 99
44

The $@ and $< are special macros.

Where:

$@ is the file name of the target.

$< is the name of the first dependency.

Eric
  • 2,202
  • 2
  • 26
  • 30
28

The Makefile builds the hello executable if any one of main.cpp, hello.cpp, factorial.cpp changed. The smallest possible Makefile to achieve that specification could have been:

hello: main.cpp hello.cpp factorial.cpp
    g++ -o hello main.cpp hello.cpp factorial.cpp
  • pro: very easy to read
  • con: maintenance nightmare, duplication of the C++ dependencies
  • con: efficiency problem, we recompile all C++ even if only one was changed

To improve on the above, we only compile those C++ files that were edited. Then, we just link the resultant object files together.

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: fixes efficiency issue
  • con: new maintenance nightmare, potential typo on object files rules

To improve on this, we can replace all object file rules with a single .cpp.o rule:

OBJECTS=main.o hello.o factorial.o

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

.cpp.o:
    g++ -c $< -o $@
  • pro: back to having a short makefile, somewhat easy to read

Here the .cpp.o rule defines how to build anyfile.o from anyfile.cpp.

  • $< matches to first dependency, in this case, anyfile.cpp
  • $@ matches the target, in this case, anyfile.o.

The other changes present in the Makefile are:

  • Making it easier to changes compilers from g++ to any C++ compiler.
  • Making it easier to change the compiler options.
  • Making it easier to change the linker options.
  • Making it easier to change the C++ source files and output.
  • Added a default rule 'all' which acts as a quick check to ensure all your source files are present before an attempt to build your application is made.
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
2

in exemple if you want to compile sources but have objects in an different directory :

You need to do :

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

but with most of macros the result will be all objects followed by all sources, like :

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

so this will not compile anything ^^ and you will not be able to put your objects files in a different dir :(

the solution is to use these special macros

$@ $<

this will generate a .o file (obj/file.o) for each .c file in SRC (src/file.c)

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

it means :

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

but lines by lines INSTEAD of all lines of OBJ followed by all lines of SRC

Aominé
  • 472
  • 3
  • 11