How to use to makefiles –Compiling Hello World

When managing the build process of your source files,compiling ,recompiling and keeping track of which object files need to be rebuilt can bee a tedious task. Make tools were created to ease that build process.All you have to do is tell them the structure of your project and the dependency relationship between your files and you are done! Give the command and your project is built(rebuilt) and all the dirty details are handled for you.

In this article ,we are going to use make tools to build our program from the sources ;we will use make both on Linux and Windows and show how nmake lets you do the same thing on Windows.This tutorial is part of our series on building software from source code so feel free to browse around.

The hello world program we will be compiling is shown below:

void printHello();


#include “printHello.h”
void printHello()
 printf(“Hello World”);


#include “printHello.h”
int main ()
 return 0;


Notice that in the printHello.c file ,we have the #include “printHello.h” preprocessor directive.This shows that the printHello.c file depends on printHello.h.The same can be seen on the “main.c” source file.One thing we have to tell make is which file depends on which ,more concretely :”make ,my friend ,here is what you need to know,printHello.c depends on printHello.h and main.c depends on printHello.c”.

File Dependency Graph

File Dependency Graph








To use make tools ,you need to provide two pieces of information .One is the dependency relationships between the files in our projects[Which files depend on which] ,the second thing is the compiler commands(the same commands we have been using in previous tutorials) to generate our target files(object or binary executable).

OK ,I know two things I have to tell make : dependency information and compiler commands,but how exactly do I tell it and how do I use it to build my project?Well one thing before I answer your question.There are a lot of make implementations out there and they all came up with various names for “dependency information” and
“compiler commands”. This should be no problem as long as you know the concepts behind these names.

Now to your question.You take your “dependency information” and your”compiler commands” and write them in a file that is named “makefile” or “Makefile”.You cannot name this file anything else.You can not name it coolMakeFile ,ironMake or whatever.YOU HAVE TO NAME IT “makefile” or “Makefile”.This is because make tools have been designed to look for makefiles and work on the information they find in there.If you name yours coolMakeFile, make will still look for makefile in your directory ,it sure won’t find it and your build will fail.(Edit:You can call make with options to use your custom name for makefiles but it is still good to follow the standard 🙂 ).

With your makefile in place ,just type make ,nmake or whatever command the specific make tool you are using specifies ,this will command your maketool to analyze the makefile in the directory and use the information in there to build your project.No need to retype compiler commands ,no need to keep track of object files ,no nothing!Our build process carried out automatically and in the most efficient possible way.Make tools are cool right?

There are quite a lot of different flavors of make tools our there,I use two of them quite often and the actual goal of this tutorial is to get you up to speed using them.These are make and nmake.I have tried to keep this tutorial as simple ,the goal is to let you focus on things involved in working with make tools and how they fit together to ease the build process.It is my (personal) belief that once you are introduced to a concept in the most basic possible way ,you can go on and complicate things yourself.Make sure you nail how make tools are used :-).

Enough talk ,now to the real meat of the tutorial .We are going to build our hello world program;make will be used both on Linux and Windows and nmake will be used on Windows.

Building Hello world C Linux -gcc-make

make was designed by the GNU project and is installed by default on most linux distributions.To use it change to the directory of your project ,mine is


The contents of my directory are as shown below:

Directory Contents

Directory Contents









Now we create our makefile.Create it as you would for any other file and do not give it any extension.My makefile is as shown below.Note that it has to be located in the same directory as your source files.


printHello.o: printHello.c printHello.h
[  TAB ]gcc -c printHello.c
main.o: main.c printHello.h
[  TAB ]gcc -c main.c
finalBinary:main.o printHello.o
[  TAB ]gcc main.o printHello.o -o finalBinary

Note that [ TAB ] means that you have to indent the line one TAB space relative to the line above it. make was designed to expect you to write your makefile exactly like that.make will have trouble parsing your makefile if you do not follow this guideline.My makefile created with the nano text editor is shown below:

Makefile Inside Nano

Makefile Inside Nano











With your makefile in place ,type

make finalBinary

on the terminal and your executable is generated as shown below.Just after you type the command the make shows you the compiler commands it is running .Listing the directory after it is done shows the generated binary is present and we can run it just by typing


on the terminal

Linux GCC make command

Linux GCC make command












Now that you have seen your makefile working ,a few explanations on the syntax used in there.The line

printHello.o: printHello.c printHello.h

tells make that we want to generate an object file named printHello.o and that file depends on two files: printHello.c and printHello.h. The next line is the compiler command .The same compiler command you would type on the terminal to generate the object file.Refer to previous tutorials on how to use compiler commands on the terminal.

Now is the chance to learn something about make terminology .A makefile is a set of rules each rule is organized as follows:

target: prerequisite-1 prerequisite-2 ....prerequisite-n
[TAB]  command

So the first two lines of our makefiles are a rule. printHello.o is our target ,printHello.c and
printHello.h are prerequisites for the target(things the target depends on) and gcc -c printHello.c is the compiler command to generate our target.

That’s it .Organize how you want to build your project into a set of rules ,write them in your makefile and you are one command away (make or nmake 🙂 )from your final executable.

One final thing you should note is that we passed an argument to make.This argument is the target we want make to generate for us.If you just type make with no argument ,make will generate the first target in the make file and this is printHello.o in our case.So make sure you pass the name of the target you want to generate as an argument to make.

Building Hello World C Windows –mingw -make

Mingw is a project that has ported gcc(and make ) to windows.We use the same commands as we do in native linux.To use mingw ,go to their page and download the install binary:Mine has been installed in this directory:

C:\Program Files\CodeBlocks\MinGW\bin

Scrolling through your install directory you can see a binary called mingw32-make as shown below:

mingw32-make location in File Exploarer

mingw32-make location in File Exploarer











This is our make binary ,in other words ,we can call it with the “finalBinary” argument and it should build our hello world program right?

Note :We assume you have your makefile created and located in the same location as your source files.Just use any text editor (I use notepad++) and save the file without extension.(no .txt ,no .c no nothing). Refer to the figure below and make sure you read the Building Hello world C Linux -gcc-make section for clarity.

Windows Create Make File

Windows Create Make File

Open your command prompt ,change to the directory containing your files and type the following command to call your mingw32-make program:

C:\Program Files\CodeBlocks\MinGW\bin\mingw32-make finalBinary

I get the “C:Program” is not recognized as an internal command” error as shown below:

Call mingw32-make Error

Call mingw32-make Error

This is because we have a space between Program and Files in the “path\name” of our program.The program name on the command prompt can’t have spaces inside.Wrap that “path/name” inside quotes and run the command again as shown below:

call mingw32-make  with quotes

call mingw32-make with quotes

mingw32-make lists the commands it is running to compile our code and generates both the object files and the finalBinary.exe executable.

The quotes solved the first problem but usually you just want to type mingw32-make and see your work done without specifying the location .You can set that up by adding the path to your mingw32-make binary (that is C:\Program Files\CodeBlocks\MinGW\bin\ in our case) to the PATH environment variable.This link[LINK ] is a good reference on how to set environment variables.

With the location of our mingw32-make binary file added to the system PATH variable.Close your prompt and open it again.Change to the location of your source files and type:

mingw32-make finalBinary

Your files are built as shown below.Type


to see hello world printed on your prompt.

Building Hello World C Windows –msvc -nmake

nmake is a flavour of make that was created by microsoft to help build programs compiled with msvc.The syntax is pretty much the same as the one we used with the GNU make utility but differences arise as you start writing complex makefiles for your projects.

The nmake version of our makefile looks as follows:


printHello.obj: printHello.c printHello.h
[TAB]    cl /c printHello.c
main.obj: main.c printHello.h
[TAB]    cl /c main.c
finalBinary.exe: main.obj printHello.obj
[TAB]    link /out:finalBinary.exe main.obj printHello.obj

Also ,notice that object files have the extension .obj ,the commands are compiler commands we would type on the command prompt if we wanted to compile manually.[ TAB ] is a way to indicate that the line is indented exactly one tab space relative to the line just above.My makefile is shown below in the notepad++ text editor.

nmake hello world makefile

nmake hello world makefile

Save your makefile in the location of your source files and open the visual studio command prompt.This a specialized prompt with some configurations and variables set for you in advance.You open in by Clicking on start ->all programs->microsoft visual studio[Version]->>visual Studio tools->Visual Studio Command Prompt[Version]

List Directory contents

List Directory contents


nmake finalBinary.exe

nmake gets busy building your project as shown below and generates your finalBinary.exe file.Type


and you see hello world printed on your screen as shown below:

call nmake from command prompt

call nmake from command prompt

It sure gets more complicated than this in real world programs but by now you have an overall grasp of what is involved in using nmake to manage your builds with the msvc compiler.If you need to dig depper you can check out the official documents from microsoft.I find the information there not easy to browse through though.You might want to combine that with what this link provides ,and this one helped .You can sure leave a comment in case you run into other problems building your program.

We have covered so much in terms of what make tools and makefiles are and the problems that they were designed to solve.We have built our hello world project both on Linux and Windows using two popular compilers gcc and msvc.

In production software development ,you usually do not write makefiles yourself ,but you write your source code in an IDE and the IDE calls a build automation tool.It is this build automation tool that generates makefiles.We will not go into build automation in this tutorial ,but at I least I will give you the name of one that I use very often. This is qmake ,and a wikipedia link if you want to dig deeper 🙂 .Comments ,suggestions are always welcome.I hope this ‘s been informative to you and I would like to thank you for reading.

Posted in Programming, Tips and tricks, Tutorials and tagged , , , , , , , , , .

Daniel Gakwaya loves computer Hardware/Software.He is a Software Engineer at BLIKOON and lead developer of bliboard-The whiteboard system currently marketed by the company.He is known to hack around on any piece of tech that happens to pick his interest. More on his tech endeavors here
Follow him on Twitter

One Comment

Comments are closed.