ong before Windows became the de facto operating system on the desktopeven before IBM released the first Personal Computer with 16KB of memory, software engineers had realized the need for automation tools to facilitate large-scale development efforts. In 1960s and 70s, when software projects began growing in complexity, developers found it increasingly difficult to work in unity with each other. Unforeseen problems during integration often forced the team back to coding. Furthermore, in some extreme cases, two programmers' combined efforts could be producing less reliable code when compared to any one of them working alone. It started to become clear that two programmers were not necessarily twice as productive as one. These observations contradicted the conventional wisdom of the industrial age. The software industry definitely needed new methods to make development efforts more predictable. Most of the tools and concepts we take for granted today flourished out of this crisis: source code control systems, structured programming, and even object oriented programming, to name just a few.
The Basics of make
One of the important products of the period is the make utility, which consists of a simple, yet expandable rule evaluation engine geared towards producing binary executables from source files and libraries along with a makefile consisting of the rules. The difference between make implementations in UNIX and Windows is considerable, but the underlying concepts are the same:
Suppose you have a VB form named Startup.vb, and a VB class named Helper.vb, which are used to build your application, VBApp.exe. The dependency between these three files is represented in the makefile as follows:
VBApp.exe: Startup.vb Helper.vb
vbc /out:VBApp.exe Startup.vb Helper.vb
The first line establishes Startup.vb and Helper.vb as two prerequisites for VBApp.exe, whereas the second line tells the utility how to produce VBApp.exe using the two. Note that the second line is indented with a tab. This marks it as a command line, rather than a dependency line. You can add as many command lines as you wish to produce VBApp.exe, just make sure to start each line with a tab.
The command line to invoke make is simple:
When invoked, make looks for makefile in the directory in which it's been invoked. make then parses the makefile looking for instructions on how to build the target, VBApp.exe. Here, the target depends on Startup.vb and Helper.vb, resulting in the invocation of the Visual Basic compiler.
You can add as many levels of dependencies as possible. For a slightly more complicated project, VBApp.exe may depend on Startup.vb and Helper.dll, which could be a C# DLL consisting of one class, in file Helper.cs. In this case, there would be two inference rules in your file:
VBApp.exe: Startup.vb Helper.dll
vbc /out:VBApp.exe /r:Helper.dll Startup.vb
csc /out:Helper.dll /t:library Helper.cs
To produce the Helper.dll without worrying about VBApp.exe, simply type nmake Helper.dll. Make evaluates rules that pertain only to the specific, desired target. It leaves out unrelated portions of the makefile.
By now, the idea and the opportunities that make presents should be clear: Every dependency is processed recursively until the topmost level is satisfied; and the evaluation tree can be as deep or wide as you like.