+# For an explanation of the
+# targets ...: target-pattern: prereq-patterns ...
+# syntax, see
+# http://www.gnu.org/software/make/manual/html_node/Static-Usage.html
+# For an explanation of $@, $^ and other special variables, see
+# http://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
+# For an explanation of .SECONDEXPANSION, see
+# http://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html
+# `$$` escapes make-variable expansion for the first pass through the
+# recipe. See
+# http://www.gnu.org/software/make/manual/html_node/Variables-in-Recipes.html
+#
+# What's going on here? During the read-in phase, Make expands the
+# rule to
+# hello_world goodbye_world: % : $($(@)_OBJECTS)
+# Because we're using .SECONDEXPANSION, Make expands the prerequisites
+# again during the target-update phase. If we're building
+# hello_world, $(@) will expand to hello_world, and we'll have
+# hello_world goodbye_world: hello_world : $(hello_world_OBJECTS)
+# as the variable expansion continues, we end up with
+# hello_world goodbye_world: hello_world : hello_world.o
+# which is the final rule used to determine the prerequisites.
+#
+# The recipe expands to
+# gcc -o hello_world hello_world.o $(hello_world_LIBS)
+# which expands to (if hello_world_LIBS was set to `-lm`)
+# gcc -o hello_world hello_world.o -lm
+#
+# Striking the right balance between "everything handled
+# automatically" (i.e. "complicated") and "everything handled
+# manually" (i.e. tedious) is difficult, and maybe this rule crosses
+# the line. The simpler alternative would be to define your own
+# prerequisites for each program you wish to compile, and you're
+# certainly allowed to go that route if you wish.
+.SECONDEXPANSION:
+$(C_PROGRAMS): % : $$($$(@)_OBJECTS)
+ $(CC) $(LDFLAGS) -o $@ $^ $($(@)_LIBS)
+
+.SECONDEXPANSION:
+$(CXX_PROGRAMS): % : $$($$(*)_OBJECTS)
+ $(CXX) $(LDFLAGS) -o $@ $^ $($(@)_LIBS)