Makefiles

(or What's the best IDE for WATCOM C++)
Hamburg (Germany), the 16th November 1997.
Written by Nils Pipenbrinck aka Submissive/Cubic & $eeN

Table Of Contents: Makefiles I

  1. Introduction
  2. Targets, Rules and Dependencies?
  3. The complete example Makefile
  4. User Macros
  5. Final Words
  6. Contact Me
  7. Link to MakeFiles II

Introduction

What is a makefile, and why should you use them?
If you've ever written a program with more than 2 or 3 sourcefiles without the aid of an IDE (like Watcom C for DOS or pure assembly) you know and hate the following situation: You've found a bug or added a single line to your code and you want to build your program to check if it works. You start your batch-file and wait ages because your stupid batch compiles every single module of your code... This is what makefiles are good for: They can organize and speed up your build progress. This small tutorial will only touch the basics of Makefiles, and most of the stuff is specific to the Watcom Make (since I use it, and I think most of the guys who'll read this will also use Watcom for their coding work). Makefiles aren't usable without a make-program. If you want to execute a Makefile you have to call your Make utility (for watcom it's called WMAKE). I've also examined the Borland MAKE Utility. If you don't have WATCOM WMAKE but still want to use MAKEFILES check out my Makefile Compatibility Chart Page.

Targets, Rules and Dependencies?

First: don't panic, it's not harder to understand than batches! I'll start with a simple example, and won't go into the difficult details of makefile-coding right now...

Imagine you have written a small game with WATCOM C and wrote a couple of sourcefiles like:

So, what do you need to build your game? At first you have to define a TARGET for your game. Usually this target is named as the executable you want to build (in our example it's called game.exe).

The target definition in a makefile looks like this:
game.exe: video.obj mouse.obj game.obj
This means that the make-program knows which object files are needed to build your game.exe. The files listed after the colon are called Dependencies. Most of them are usually object files, but you can include any kind of file you want.

Ok. Now Make knows what's needed to build your game, but it still has no clue how to generate these .obj files you declared in your dependencies. That's what Rules are for. the most simple form of a rule looks like this.

.cpp.obj
  wpp386 $<

or for assembler fans:

.asm.obj
  tasm $<

With this rule the makefile knows how to turn a .asm or .cpp file into a .obj file. If you're wondering what the $< stands for: It's just a macro or placeholder for the current file that has to be compiled.

Right now we know how to build everything needed for game.exe, but we haven't declared how to build game.exe. We have to alter the target again, and add some lines to call the linker:

game.exe: video.obj mouse.obj game.obj
  %write game.lnk NAME   $@
  %write game.lnk SYSTEM DOS4G
  %write game.lnk FILE   video.obj
  %write game.lnk FILE   mouse.obj
  %write game.lnk FILE   game.obj
  wlink  @game.lnk

%write does just what it says, it writes something into the file game.lnk. The first %write command will create the file game.lnk if it doesn't exist, or it'll erase it (so you don't have to worry about the game.lnk file at all, it'll be recreated every time you start MAKE).
$@ is again a macro. It expands to the name of the current target. In our example it's just game.exe.
You can do everything you want in this body, you can start your own tools and call dos-commands. Finally the line wlink @game.lnk executes wlink and passes game.lnk as command file. This will build your game.exe from the object files.

The complete example Makefile

Now here is the makefile nicely formatted and in one piece:

.cpp.obj
  wpp386 $<

game.exe: video.obj mouse.obj game.obj
  %write game.lnk NAME   $@
  %write game.lnk SYSTEM DOS4G
  %write game.lnk FILE   video.obj
  %write game.lnk FILE   mouse.obj
  %write game.lnk FILE   game.obj
  wlink  @game.lnk

Important:
Add a blank line between two different sections and make sure that there is always a blank at the start of the section bodies. The make utility needs this. If you now call your make-utility it will read the makefile, call Wpp386 for each source-module, write the game.lnk and then finally call wlink. The make-utility will stop if any of the make steps (e.g. compiling a sourcefile or linking) returned an error. MAKE will only do the steps needed to build your program. If a .cpp file hasn't changed since the last make, it won't call wpp386 on this file (unless your force it to do so, but I'll explain this later).

User Macros

Now you've written a joystick input module for your game and want to include it in your makefile. To do so, you have to change the makefile at two different lines:

Since all coders are lazy MAKE also supports macros to make our life more fun :) A macro is basically a simple text replacement and it's also very easy to use.

Now we want to replace our dependency list with a macro and also add some other macros (compiler options, name of the executable). The new makefile will look like this:

objects1 = video.obj mouse.obj game.obj joystick.obj
coptions = /5r /s /ox
dest     = game.exe

.cpp.obj
  wpp386 $(coptions) $<

$(dest): $(objects1)
  %write game.lnk NAME   $@
  %write game.lnk SYSTEM DOS4G
  %write game.lnk FILE   {$(objects1)}
  wlink  @game.lnk

I think this is very simple to understand: to declare a macro you just do it like I did it in the first 3 lines. If you want to use a macro you write $(macroname). This makefile is very flexible, and most of my makefiles look exactly the same. I usually also include a rule for .asm files (even if I don't need it). The {$(objects1)} is a trick I saw in someone's makefile: Watcom WLINK is able to process multiple object files in one FILE statement. You only have to group them in {}.

Final Words

Now you have all the tools you need to work successfully with WMAKE. For a start it might be a good idea to cut'n'paste my example makefile and save it as a template for new projects. If you want to learn more about makefiles you should check out the TOOLS helpfile in the watcom-directory, but be warned: this stuff really goes into detail and you might get confused. You will also find other people's makefiles which are completely different to my style. You should know: Everyone has his own coding style, even for makefiles. It might be fun to explore other makefiles and learn their tricks. This can be a challenge, and you might waste a couple of hours on it, but it's definitely fun (a hint for those folks who think they know everything about makefiles: check out the makefile from the LINUX Kernel. If you understand what's going on you are an expert) Afterwards you can be proud and say "I have WMAKE and EDIT. I don't need a stupid IDE." And finally, before I forget it: If you think that make is out of sync, and you want to rebuild your complete application from scratch you should type WMAKE -A . This will build every single dependency from scratch.

Contact Me

If you want to contact me for any reasons (bugs, suggestions, typos or cool makefile-tricks), then write an email.

... please let me read the follow-up tutorial: MAKEFILES For Experienced!


© by submissive