42

I was using a Makefile from the book "Advanced Linux Programming (2001)" [code]. It was strange for me to see that GNU make does compile the code correctly, without even specifying a compiler in the Makefile. It's like baking without any recipe!

This is a minimal version of the code:

test.c

int main(){}

Makefile

all:            test

and make really works! This is the command it executes:

cc     test.c   -o test

I couldn't find anything useful in the documentation. How this is possible?


P.S. One additional note: Even the language is not specified; Because test.c is available, GNU make uses cc. If there exists test.cpp or test.cc (when there is no test.c), it uses g++ (and not c++).

Ho1
  • 2,552
  • 3
  • 20
  • 25
  • 4
    "It's like baking without any recipe!" A recipe would tell you to boil water, but not whether you should boil water using a pan on a gas stove, a pan on an induction stove, an electric kettle, or a cauldron placed on a tripod over a fire. It wouldn't even tell ou where you should get your water. This is like telling `make` to boil water, and using its internal rules, `make` will just figure out how ;) – Rhymoid Nov 23 '16 at 21:48
  • 2
    @Rhymoid It's like yelling out: **I want a cake!** And then a robot called `make` checks your fridge and finds out there's some flour available, then bakes a default cake for you from its internal recipe. :-) – Ho1 Nov 24 '16 at 05:49
  • @Ho1 : The robot might ask, Which cake you want to have sir ? :) :D – Thushi Jan 04 '17 at 08:17

1 Answers1

70

Make does this using its built-in rules. These tell it in particular how to compile C code and how to link single-object programs.

You actually don't even need a Makefile:

make test

would work without one.

To see the hidden rules that make all of this possible, use the -p option with no Makefile:

make -p -f /dev/null

The -r option disables these built-in rules.

As pointed out by alephzero, Make has had built-in rules for a very long time (if not always); Stuart Feldman's first version in Unix V7 defines them in files.c, and his 1979 paper mentions them. They're also part of the POSIX specification. (This doesn't mean that all implementations of Make support them — the old Borland Make for DOS doesn't, at least up to version 3.0.)

Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
  • 1
    Yes....but I think there is more magic than POSIX lets on. POSIX defines the default C compiler as "c99" rather than "cc". OK, so I'd expect all but the most unusual sites to have that linked or symlinked to cc. But how does it know to use a *C* compiler? Historical assumption perhaps? As a side note, gcc is sensitive to file extensions, e.g. "cc a.f" fails, presumably because gcc is expecting Fortran. – AlwaysLearning Nov 22 '16 at 20:13
  • @KingZoingo If if finds a C file with the same name, it uses the C compiler. If there is a C++ file with the same name, it uses the C++ compiler. Visual Studio also differs between .c and .cpp, but in Unix that file extensions aren't usually taken seriously, this is something odd. – Ho1 Nov 22 '16 at 21:23
  • @Ho1 GCC has teh option `-x` to set the language explicitely, the ability to use file endings is just a convenience – deamentiaemundi Nov 22 '16 at 21:24
  • 5
    @KingZoingo Make is in effect an inference engine of sorts: it has a set of rules (built-in and from the Makefile), existing artifacts (files in the current directory or named in the Makefile), and requested artifacts (targets in the Makefile); it simply tries to match rules and existing artifacts to determine whether it can use them to obtain the requested artifacts. The built-in rules tell it `test.c` can be used to produce `test`. `make -d` will show you the process in detail... – Stephen Kitt Nov 22 '16 at 21:39
  • 5
    @Ho1 @StephenKitt This was been in `make` long before GNU or POSIX were invented. The first version was written nearly 40 years ago, and there were some prototype versions built from shell scripts even before that. – alephzero Nov 23 '16 at 01:07
  • @alephzero Thanks for the comment. It seems that this feature gradually becomes forgotten. At last I didn't see it in a recent book/article, and manually written Makefiles. Or, is it too primitive that no one wants these defaults? – Ho1 Nov 23 '16 at 01:32
  • @Ho1: Partly, and partly because some of the defaults have been superceded over time. Once upon a time, the makefile command CPP would run the C preprocessor, so you could see what your code would look like with all #defines & #includes expanded, but nowadays most of us expect it to invoke a C++ compiler. – jamesqf Nov 23 '16 at 04:57
  • 3
    @jamesqf `CPP` still invokes the preprocessor (`cc -E` typically); the C++ compiler is `CXX`. – Stephen Kitt Nov 23 '16 at 05:22
  • @jamesqf or rather, I've generally seen Makefiles expect to use `CXX` for the C++ compiler, whether or not they use built-in rules — see also `CPPFLAGS` v. `CXXFLAGS` (which some builds do get wrong, causing problems *e.g.* with Debian's `dpkg-buildflags`). – Stephen Kitt Nov 23 '16 at 05:34
  • 1
    @Ho1 several contributing factors spring to mind: avoiding built-in rules provides more consistent behaviour (especially if you're also building with non-POSIX Make — I haven't checked the built-in rules in `nmake` etc.); `automake`, CMake & co. don't rely on built-in rules AFAIK (nor do Makefiles generated by IDEs); it's easier to reason about self-sufficient Makefiles... Note that it's also faster to build with the built-in rules disabled (see the `-r` option). – Stephen Kitt Nov 23 '16 at 05:40
  • Thanks @alephzero, the original paper actually mentions them indeed! I've updated the answer. – Stephen Kitt Nov 23 '16 at 08:54
  • @StephenKitt Thanks for the detailed answer. Btw, in my Ubuntu system with several c/c++ compilers `cxx` does not exist. But `c++` does. – Ho1 Nov 23 '16 at 10:38
  • 3
    @Ho1 `CXX` in this context is the Make variable, not a command — `$(CXX)` in a Makefile will be replaced by a command to run a C++ compiler. – Stephen Kitt Nov 23 '16 at 10:47
  • @StephenKitt I am concerned about the built-in rule for C++ files. Why `g++`, and why not `c++`, just like `cc`? – Ho1 Nov 23 '16 at 10:55
  • @Ho1 I don't know — `CXX` is [`g++` by default in GNU Make](https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#Implicit-Variables), POSIX doesn't specify how to build C++ code. – Stephen Kitt Nov 23 '16 at 14:40
  • 1
    My copy of the old Borland Make (3.6) for MS-DOS supports built-in rules. For example running `make foo.exe` without a makefile will run `BCC foo.c` if `foo.c` exists. – Ross Ridge Nov 23 '16 at 17:55
  • @RossRidge that's interesting, I tested with version 3.0 which doesn't do anything if no Makefile is present! – Stephen Kitt Nov 23 '16 at 17:59
  • @RossRidge I tried version 3.6 (from Borland C++ 3.1) and it does indeed have built-in rules, five in total (assembler to object, C to object, C++ to object, C to executable, RC to RES). Thanks! (And it uses `$(CPPFLAGS)` for C++ flags, grr...) – Stephen Kitt Nov 23 '16 at 20:34
  • 2
    `make` cares about extensions on Unix. `make` (and `cc`) is probably the main reason to actually care about extensions, in fact, since pattern rules are easier to use than writing the same rule for every source file. – Jonathan Cast Nov 24 '16 at 03:47
  • @Stephen Kitt: Which is why you (or at least a purist like me :-)) have to redefine CPP in your makefiles. – jamesqf Nov 24 '16 at 04:03