C-Makefiles

sammysammy
3 min read

A make- is a build automation tool used to compile and build projects.

Very useful if you have multiple source files.

Makefile is just a configuration file that specifies how the project should be built(rules) and the dependencies between different files.

Makefile has rules and dependencies.

When it's useful?

When you have a large project- a large program with many source files

Dependency management- different files depend on each other

efficiency - recompiles only parts of code that changed hence saving time.

Why use it:

Automation- saves you from having to manually recompile files

Dependencies tracking- able to detect changes and build.

Consistency- ensures consistent build process in different environments for different developers.

How to use it:

Start by creating a file named makefile

Define rules -write rules that specify how to build target files(output files) from dependencies(input files)

Use variables - define variables for compiler options source files and other parameters

create phony targets - for actions that don't produce files but trigger certain tasks e.g cleaning or testing

dependencies- explicitly list dependencies(input files) for each target for proper rebuild

CC = gcc
CFLAGS = -Wall
all: my_program

my_program: main.o utils.o
    $(CC) $(CFLAGS) -o my_program main.o utils.o
main.o: main.c
    ($CC) $(CFLAGS) -c my_program main.c
utils.o: utils.c
    $(CC) $(CFLAGS) -c my_program utils.c
clean:
    rm -f *.o my_program

Explicit rules

specify how to build a specific target explicitly.

target: prerequisite
    recipe

They are useful when you want to specify or be specific on how to build a specific target.

They are explicitly done in makefile.

my_program: main.o utils.o
     gcc -Wall -o my_program main.o utils.o
main.o: main.c utils.h
    gcc -Wall -c main.c
utils.o: utils.c utils.h
    gcc -Wall -c utils.c

Implicit rules

These are predefined rules that do not need explicit instructions.

Often written as pattern rules, specifying a pattern for target and prerequisite names.

%.o: %.c
    recipe

They are handy when you have consistent patterns for building patterns from source files.

CC = gcc
CFLAGS = -Wall
my_program: main.o utils.o
    $(CC) $(CFLAGS) -o my_program main.o utils.o
main.o utils.o: %.o: %.c
    $(CC) $(CFLAGS) -c $<

common rules

Simple rule for compiling source files

%.o: %.c
    $(CC) $(CFLAGS) -c $<

linking them to an executable

my_program: main.o  utils.o
    $(CC) $(CFLAGS) -o my_program main-o utils.o

Phony targets

.PHONY: clean
clean:
    rm -f*.o my_program

Default rule

.DEFAULT_GOAL := all
all: my_program

Setting variables

Basic assignment

variable_name = value

Appending to variables

VARIABLE_NAME += new_value

Using variables

Referencing variables

$(VARIABLE_NAME)

Defining targets with variables

TARGET: $(VARIABLE_NAME):
    recipe

Automatic variables

target: prerequisite1 prerequisite2
    command $@ $^

Example

CC = gcc
CFLAGS = -Wall
SOURCES = main.c utils.c
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = my_program
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
    $(CC) $(CFLAGS) -o $@ $^
%.o:%.c
    $(CC) $(CFLAGS) -c $<
clean:
    rm -f $(OBJECTS) $(EXECUTABLE)
0
Subscribe to my newsletter

Read articles from sammy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sammy
sammy

I am an aspiring software engineer.By writing this article.I am commit myself accountable to provide valuable content to you reader oftenly every weekend about amazing programming concepts and technologies.To help you in your learning journey also.