Skip to content
Home » All Posts » Build Your First C Program with Basic Makefile Structure

Build Your First C Program with Basic Makefile Structure

The c makefile fundamentals

What is a C Makefile?

A Makefile is a text file that guides the build tool make on how to compile code. It contains a series of rules and instructions that define how to compile source codes to final executable file. For example, which compiler to use for compilation? (we commonly use gcc to build a C program or g++ to build a C++ program on Ubuntu Linux), what compiler flags to use?, For C language projects, a Makefile typically includes a list of source files, compiler and linker commands, and the steps to produce the final executable.

On a Unix-based operating system like Ubuntu, we normally build a C program with the make command, which reads the Makefile and compile the final software executable with the specified compiler,

In this section, I will briefly describe the syntax of a basic Makefile to get you familiar with the basics. Below is an example of a simple Makefile:

MYPROG=myprogram
CC=gcc
CFLAGS=-g -O0 -Wall
MYOBJS= myfuncs.o myprogram.o

all: $(MYPROG)

$(MYPROG): $(MYOBJS)
	$(CC) $(CFLAGS) $(MYOBJS) -o $(MYPROG)

myprogram.o:
	$(CC) $(CFLAGS) -c myprogram.c 

myfuncs.o:
	$(CC) $(CFLAGS) -c myfuncs.c
			
clean:
	rm -rf $(MYPROG) $(MYOBJS)

C Makefile Basics: Variable Definitions

You can define a variable in Makefile using [name]=[value] syntax. These variables can be referenced using $(name) syntax. The above example defines the following variables.

MYPROG=myprogram
CC=gcc
CFLAGS=-g -O0 -Wall
MYOBJS= myfuncs.o myprogram.o

The Make Target

When we issue the make command, we have an option to specify a target. For example:

# specify "myprogram" as the target and execute it
$ make myprogram

# specify "clean" as the target and execute it
$ make clean

Without specifying a target in the make command, the all target is selected by default:

# target "all" is selected by default
$ make

It is your responsibility to make sure the Makefile contains the definitions of targets. If a target is not defined, the make command will give you “no rule to make target” error.

Define Make Target in C Makefile

A target can be specified like this:

# Define a build target with this syntax:
[name of target]: [dependencies]
	[put your build commands here]

The Makefile example on the top defines 5 build targets:

all: $(MYPROG)

$(MYPROG): $(MYOBJS)
	$(CC) $(CFLAGS) $(MYOBJS) -o $(MYPROG)

myprogram.o:
	$(CC) $(CFLAGS) -c myprogram.c 

myfuncs.o:
	$(CC) $(CFLAGS) -c myfuncs.c
			
clean:
	rm -rf $(MYPROG) $(MYOBJS)

When user issues the “make” command without selecting a target (defaults to “all”), the Makefile execution can be understood as:

  • Target “all” has a dependency on $(MYPROG), which translates to “myprogram”. This means that “myprogram” runs first because “all” depends on it.
  • Target “myprogram” has dependency on $(MYOBJS), which translates to “myfuncs.o myprogram.o”. This means that “myfuncs.o” target will run first, and then “myprogram.o” runs second because “myprogram” depends on them.
  • Target “myfuncs.o” has no dependencies, and it needs to run the command: “$(CC) $(CFLAGS) -c myfuncs.c”, which translates to “gcc -g -O0 -Wall -c myfuncs.c” to produce an object file call “myfuncs.o”.
  • Target “myprogram.o” has no dependencies, and it needs to run the command: “$(CC) $(CFLAGS) -c myprogram.c”, which translates to “gcc -g -O0 -Wall -c myprogram.c” to produce an object file call “myprogram.o”.
  • Once “myfuncs.o” and “myprogram.o” have completed, we are back at “myprogram” target, and it needs to run the command “$(CC) $(CFLAGS) $(MYOBJS) -o $(MYPROG)”, which translates to “gcc -g -O0 -Wall myfuncs.o myprogram.o -o myprogram” to produce the final executable called “myprogram”.

Likewise, when user issues the “make clean” command, the “clean” target gets invoked and run the command “rm -rf myprogram myfuncs.o myprogram.o”.

Summary

We have gone through the basic fundamentals of a Makefile that you most likely will write one to build your C program on Ubuntu. In large C software project, especially open source projects, makefile structure tends to be very complex and large. In such cases, a Makefile is automatically generated by autotools based on User’s environment and selection of components to build, but yet they still follow the same fundamentals mentioned in this section.

Recommended Reads

Tags:

Join the conversation

Your email address will not be published. Required fields are marked *