Linux make Command with Examples

October 23, 2024

Introduction

The Linux make command is a commonly used utility by sysadmins and developers. The command assists in the compilation process and is a must-have tool for building large applications.

make minimizes repetition and speeds up compilation to speed up the process and save time.

This article shows how to use the Linux make command with examples.

Linux Make Command With Examples

Prerequisites

Note: If make is not available on the system, use sudo apt install make to install it.

How Does the make Command Work?

The make command compiles different program pieces and builds a final executable. The command reads a Makefile that contains rules, commands, and dependencies required for the project. The purpose of make is to automate file compilation and make the process less time-consuming. 

The command works with any programming language as long as there is a suitable compiler or build tool that turns the code into a format the system can run.

When working with only a few files, compiling is straightforward. The process invokes the compiler and lists the file names. For example, if there are three files:

  • file1.c.
  • file2.c.
  • file3.h.

The first two are C source code files containing the main program logic. The file3.h is a header file that contains declarations (like functions or variables) used by the C source files.

How Does the make Command Work?

To invoke the compiler, run:

gcc file1.c file2.c file3.h

The gcc command has no output but creates an a.out file, a standard compiled executable.

a.out File Created in the Compile Folder

When working with only a few source files (e.g., two or three), recompiling everything is simple because you can run the gcc command that lists all the files.

When you work on larger applications with dozens, hundreds, or even thousands of source files, recompiling everything is inefficient and time-consuming. Therefore, even if you modify just one file, recompiling the entire project requires reprocessing all files. This process can take a long time, especially if each file includes other files or has many dependencies.

The make command automates this process by only recompiling the files that need to be updated, which avoids unnecessary recompilation of unchanged files. When executed, make searches the Makefile for instructions, e.g., file descriptions and modification times. Additionally, the tool decides which files need to be updated and issues the necessary commands.

What Are Makefiles?

A Makefile is a text file containing a set of rules that instruct make how to build an application.

The Makefile basic syntax is:

target: dependencies
<TAB> commands

Parts of the syntax are:

  • Target. Names of the file or action to be created or updated after executing make. It can be an executable, object, or any other file.
  • Dependencies (object files). Names of the files (separated by spaces) that the target depends on.
  • Commands. Rules describing how to create or update the target when dependencies change.
Makefile Target and Dependencies

Note: The commands in Makefiles always come after the TAB key. Otherwise, the command does not work.

A Makefile contains several rules that tell make how to build a program. Each rule explains how to create a target from object files.

The first rule is the most important, and it often describes how to build the final program (the target) from the pieces the system has yet to create (the dependencies).

For example, when creating a target from two object files, the basic structure looks like this:

EXECUTABLE: Object_file_1 Object_file_2
<TAB> commands
Makefile Executable and Object Files

After setting rule one, the next rule is about creating object files from source files.

The make command works by compiling source files into object files and then compiling object files into the target file, the final executable. The Makefile syntax with the rules mentioned above is:

EXECUTABLE: Object_file_1 Object_file_2
<TAB> commands

Object_file_1: Source_file_1 Source_file_2
<TAB> commands

Object_file_2: Source_file_2
<TAB> commands

The syntax means that:

  • To create EXECUTABLE, the system uses Object_file_1 and Object_file_2 and compiles them using specific commands.
  • To create Object_file_1, the system needs Source_file_1 and Source_file_2 and compiles them using specific commands.
  • To create Object_file_2, the system needs Source_file_2 only. It compiles it into Object_file_2 using specific commands.
Makefile Executable and Object Files and Source Files

The Makefile organizes all compilation rules in one place. This makes it easier to understand and manage the build process compared to typing long compile commands each time. If you change a source file, make knows exactly which object files need to be recompiled and which parts of the program need updating. make only recompiles that specific file and any files that depend on it.

Linux make Command Syntax

The basic make command syntax looks like this:

make [OPTIONS]

When executed without arguments, make builds the first target from the Makefile.

Linux make Command Options

The make command is widely used due to its effectiveness, variety, and ability to perform specific actions. While the command prints results when run without options, adding arguments expands make's usability.

Here are the most used options:

CommandDescription
-B, --always-makeUnconditionally compiles all targets.
-d, --debug[=FLAGS]Prints the debugging information.
-C dir, --directory=dirChanges the directory before executing the Makefile.
-f file, --file=file, --Makefile=FILEUses a specific file as a Makefile.
-i, --ignore-errorsIgnores all errors in commands.
-I dir, --include-dir=dirSpecifies a directory to search for the specified Makefile.
-j [jobs], --jobs[=jobs]Specifies the number of jobs to run simultaneously.
-k, --keep-goingContinues running make for as long as possible after getting an error.
-l [load], --load-average[=load]Specifies that no new task should be started if other tasks are in the queue.
-n, --dry-run, --just-print, --reconPrints expected output without executing make.
-o file, --old-file=file, --assume-old=fileEnsures that make does not remake the file even if it is older than the dependencies.
-p, --print-data-basePrints the database produced after reading the Makefile.
-q, --questionActivates the Question mode, in which make doesn't run any commands but returns an exit status zero if the target has already been compiled.
-r, --no-builtin-rulesEliminates the built-in implicit rules.
-s, --silent, --quietRestricts printing the commands as they are executed.
-S, --no-keep-going, --stopStops "-k, --keep-going" command.
-t, --touchTouches files instead of running the commands.
--traceTraces each target's disposition.
-W file, --what-if=file, --new-file=file, --assume-new=fileIgnores the fact that the target file has been modified.
--warn-undefined-variablesWarns that an unknown variable is referenced.

Linux make Command Examples

The best way to understand make and Makefiles is by running the command and different options on a simple program.

Note: The following examples are written in C language.

For example, to build an executable that prints the message "Learn about Makefiles," follow these steps:

1. Create a directory called Test using the mkdir command:

mkdir Test

The command has no output.

2. Navigate to the directory using the cd command:

cd Test
cd Test terminal output

3. Make three source files: main.c, text.c, and text.h using the touch command:

touch main.c text.c text.h

The command has no output.

4. Access main.c in your text editor of choice.

The main.c file is a crucial part of a C program, as it contains the main() function, which serves as the entry point for program execution. The main function is where the program begins its execution. Therefore, when you run a C program, the operating system looks for the main function to start the process.

5. Add the following content to the file:

#include "text.h"

int main() {
    myText();
    return 0;
}
main.c file

This main.c file includes:

  • #include "text.h". The include directive allows the compiler to access the declarations of functions, types, and constants defined in text.h.
  • int main(). The main function serves as the entry point for the program. The int before main indicates this function returns an integer value, a whole number. The return value from main serves as a signal to the operating system about the program's execution status, with 0 indicating success and non-zero values indicating an error.
  • myText(). A function call invokes the myText() function, which is defined in a different file.
  • return 0. The return statement indicates the program has been completed successfully.

6. Access the text.c file.

The text.c file is a source file that defines the myText function declared in text.h. Moreover, it includes necessary libraries and helps organize the code by separating function declarations from their actual implementation.

7. Add the following contents to the file:

#include <stdio.h>
#include "text.h"

void myText(void) {
    printf("Learn about makefiles!\n");
    return;
}
text.c file

The content includes:

  • #include <stdio.h>. This statement brings in the standard library that lets you use functions like printf, which is used to display text on the screen.
  • include "text.h". The include statement ensures the compiler knows the functions, types, and constants declared in text.h.
  • void myText(void). The function definition determines a function named myText that does not take any parameters and does not return a value.
  • printf("Learn about makefiles!\n"). The function body is in curly braces. Inside, the printf function is called to output the string "Learn about makefiles!\n" to the console.
  • return. The return function automatically returns control to the calling function when it reaches the end.

8. Access text.h.

The text.h file is a header file in C programming. It contains declarations of functions, variables, or other elements that will be used in multiple source files.

9. Add the following contents to the file:

void myText(void);
text.h file

In a header file, this line declares the function myText without providing its full implementation. It informs other parts of the program that the myText function exists and can be called, even though the actual code for the function is written in text.c.

Create a Program

There are two ways to create a program:

  • Compile files by invoking the gcc compiler. This method is suitable for quick compilation or smaller programs.
  • Use make and Makefiles. This method is more efficient for larger projects with multiple dependencies and source files.

Create Program with gcc Compiler

Use the gcc compiler for simple programs or quick tests. Otherwise, use Makefiles when working with a large number of files.

To create a program with the compiler:

1. Open the terminal and navigate to the directory containing the files.

2. Invoke the gcc compiler and type the name of both c files. gcc doesn't require compiling the header because it's already included in the c files.

gcc main.c text.c
gcc Terminal Output

3. List all the files in the current directory with the ls command:

ls
gcc and ls Terminal Output

The system creates the new executable, a.out. You can also see the executable via a file explorer:

a.out File Created in the Test Folder

Note: Add -o [file_name].c at the end of the command to name the file differently.

4. Test whether the compilation was successful, with:

./a.out
Invoking the a.out Executable Terminal Output

The terminal shows the executable works properly.

Create a Program with make and Makefiles

Creating a program with make and Makefiles simplifies the process of compiling and managing multiple files in a project. Moreover, by using a Makefile, you automate compilation steps and ensure only necessary parts of the program are rebuilt when changes are made. make does this by checking the modification time of the files.

Take the following steps:

1. Create a new text document in the same directory as the source files and name it Makefile.

Makefile in the Test Folder

2. Open the file and use the basic Makefile syntax as the guideline:

Makefile Syntax

3. Type the new executable's name as the target, for example, my_app.

Makefile Target

4. Add object files main.o and text.o as the dependencies (object files). The make command recompiles the target if the object files are newer than the target.

Makefile Dependencies

5. Hit TAB and invoke the gcc compiler for the object files:

<TAB> gcc main.o text.o
Makefile Commands

6. Add the -o flag and name the target my_app.

Makefile -o Flag

After writing the first rule, the Makefile looks like this:

my_app: main.o text.o
<TAB> gcc main.o text.o -o my_app
Makefile With the First Rule Completed

Next, instruct the Makefile on how to create main.o:

1. Set main.o as the target.

2. Type in main.c as the dependency. main.c serves to create and update main.o.

3. Write the following command to update main.o every time main.c changes:

gcc -c main.c

4. Add the -c flag to instruct the Makefile not to create a new executable but only to read the code and compile the object file.

After adding the content, the Makefile looks like this:

my_app: main.o text.o
<TAB> gcc main.o text.o -o my_app
main.o: main.c
<TAB> gcc -c main.c
Makefile for Object File main.c

Finally, create text.o by following these steps:

1. Set text.o as the target.

2. Add both text.c and text.h as dependencies.

3. Write the following command to update text.o every time dependencies change:

gcc -c text.c

In the end, the Makefile looks like this:

my_app: main.o text.o
<TAB> gcc main.o text.o -o my_app
main.o: main.c
<TAB> gcc -c main.c
text.o: text.c text.h
<TAB> gcc -c text.c
Makefile for Object File text.c

4. After completing the Makefile, save it and type:

make
make Command Terminal Output

The make command creates two object files (main.o and text.o) and the executable (my_app).

To verify that make created new files, run the ls command:

ls
make and ls Commands Terminal Output

The terminal shows that running the command created my_app. To run the my_app file, type:

./my_app
Executing my_app Terminal Output

Update the Program

When one source file is changed, make only updates object files that depend on that source file. For instance, to change the text displayed when running my_app from "Learn about Makefiles" to "Where am I?", follow these steps:

1. Open text.c in the text editor:

Changing the text.c Message

2. Change the text to "Where am I?":

Changed the text.c File Message

3. Save the file, open the terminal, and run:

make
Make Command After the Changes Terminal Output

The make command detects changes in text.c and recompiles only that file. It also links the updated object file to the executable.

4. Verify the change by running the executable:

./my_app
ls Command to Verify Changes

Compile All Files

To compile all files and not only the changed files, use -B or --always-make options.

For example, change the text in the text.c file back to "Learn about Makefiles", save the file, and enter:

make -B
make -B Terminal Output

The output shows that make compiles all the files in the directory, even the ones that haven't been changed.

Clean Object Files

When a user runs make for the first time, the command creates object files and the target based on the data in the Makefile. However, to declutter the source directory and remove object files and the executable, add the clean function to the Makefile:

clean:
<TAB> rm *.o my_app
Makefile and Clean Command

The command consists of:

  • clean. The name of the rule.
  • rm *.o my_app. The command that deletes all files ending with .o (object files) and the my_app executable file.

To clean object files and the executable, enter:

make clean
make clean and ls Terminal Output

After running ls, the terminal shows that the object files and my_app have been removed.

Run make in Debug Mode

Run make in debug mode to print additional info about the compiling process. For example, execute make with the -d option to display the debugging output:

make -d
make -d Terminal Output

Use Different File as the Makefile

By default, make looks for a file called Makefile or makefile in the current directory. However, to use another file, run:

make -f [file_name]

For example, if a Makefile is my_file, execute:

make -f my_file
make -f Terminal Output

Use Variables

Variables in Makefiles represent multiple file names, arguments, targets, dependencies, commands, source directories, or other items. Furthermore, a variable has a name and represents a string of text called the variable's value.

To define a variable, use =. For example, substitute gcc with a variable C.

C=gcc

my_app: main.o text.o
<TAB> $ (C) main.o text.o -o my_app

main.o:main.c
<TAB> $ (C) -c main.c
        
text.o: text.c text.h
<TAB> $ (C) -c text.c
make Command Variables

When running make in the terminal, the command reads the C variable as gcc:

Make Command with Variables Terminal Output

Conclusion

The examples in this tutorial explained how to use the make command in Linux to compile files into executables.

Next, download the Linux commands cheat sheet to learn other important Linux commands.

Was this article helpful?
YesNo
Sara Zivanov
Sara Zivanov is a technical writer at phoenixNAP who is passionate about making high-tech concepts accessible to everyone. Her experience as a content writer and her background in Engineering and Project Management allows her to streamline complex processes and make them user-friendly through her content.
Next you should read
How to Set Environment Variables in Linux
December 17, 2020

Environment variables play a significant role in setting up the system and shell configuration at the beginning of every shell session. This tutorial explains how to view, set, manage...
Read more
How to Uninstall or Remove Software Packages From Ubuntu
May 23, 2024

This guide will walk you through several methods for removing old or unwanted software from an Ubuntu Linux system...
Read more
How to Install a Desktop (GUI) on an Ubuntu Server
August 4, 2022

Want to add a desktop environment after you install Ubuntu server? By default, Ubuntu Server does not include a Graphical User Interface (GUI) and that...
Read more
How to Build Linux Kernel From Scratch {Step-By-Step Guide}
November 12, 2020

All Linux distributions come with a predefined kernel. However, they are usually outdated. Follow this step-by-step guide to learn how to build a Linux kernel from scratch...
Read more