In a GNU make rule, what's the difference between $< and $^, and how do I refer to just the order-only prerequisites?

Programming granfalloon · reference 1 day ago answered reference

In a GNU make rule, what's the difference between $< and $^, and how do I refer to just the order-only prerequisites?

1 answer

✓ Accepted answer

$< vs $^ vs $| in GNU make

$< = the first prerequisite only. If the recipe came from an implicit rule, it's the first prerequisite that rule added.

$^ = the names of all the (normal) prerequisites, space-separated, with duplicates removed. If a file is listed as a prerequisite more than once, $^ includes it only once.

So in foo.o: foo.c util.h common.h, $< is foo.c while $^ is foo.c util.h common.h. That's exactly the common split for a compile rule: $< is the source file you feed to the compiler, $^ is everything the target depends on.

Order-only prerequisites: use $|

Order-only prerequisites are the ones listed after a pipe (|) in the prerequisite list. make ensures they exist before building the target, but won't rebuild the target just because they're newer (the typical use is a directory that must exist but whose timestamp shouldn't trigger rebuilds).

$^ deliberately does not contain order-only prerequisites. To refer to them, use $| — "the names of all the order-only prerequisites, with spaces between them."

build/foo.o: src/foo.c src/util.h | build
	@echo "first prereq      ($$<): $<"   # src/foo.c
	@echo "normal prereqs    ($$^): $^"   # src/foo.c src/util.h   (no 'build')
	@echo "order-only prereq ($$|): $|"   # build
	$(CC) -c $< -o $@

build:
	mkdir -p build

Here build is an order-only prerequisite: it shows up in $| but never in $^ or $<.

Related variable worth knowing

$+ is like $^ but keeps duplicates in the order they were listed in the makefile. This matters mainly for linker commands where repeating a library name in a specific order is meaningful. (Also: $? = only the prerequisites newer than the target.)

Summary

Variable Expands to
$< first prerequisite
$^ all normal prerequisites, duplicates removed, no order-only
$+ all normal prerequisites, duplicates kept, in listed order
$| all order-only prerequisites
$? prerequisites newer than the target

Sources:

granfalloon · reference0 votes1 day ago