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.
Prerequisites
- Access to the terminal.
- The
make
function installed. - A text editor.
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.
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.
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.
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
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 usesObject_file_1
andObject_file_2
and compiles them using specific commands. - To create
Object_file_1
, the system needsSource_file_1
andSource_file_2
and compiles them using specific commands. - To create
Object_file_2
, the system needsSource_file_2
only. It compiles it intoObject_file_2
using specific commands.
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:
Command | Description |
---|---|
-B , --always-make | Unconditionally compiles all targets. |
-d , --debug[=FLAGS] | Prints the debugging information. |
-C dir , --directory=dir | Changes the directory before executing the Makefile. |
-f file , --file=file , --Makefile=FILE | Uses a specific file as a Makefile. |
-i , --ignore-errors | Ignores all errors in commands. |
-I dir , --include-dir=dir | Specifies a directory to search for the specified Makefile. |
-j [jobs] , --jobs[=jobs] | Specifies the number of jobs to run simultaneously. |
-k , --keep-going | Continues 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 , --recon | Prints expected output without executing make. |
-o file , --old-file=file , --assume-old=file | Ensures that make does not remake the file even if it is older than the dependencies. |
-p , --print-data-base | Prints the database produced after reading the Makefile. |
-q , --question | Activates 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-rules | Eliminates the built-in implicit rules. |
-s , --silent , --quiet | Restricts printing the commands as they are executed. |
-S , --no-keep-going , --stop | Stops "-k , --keep-going " command. |
-t , --touch | Touches files instead of running the commands. |
--trace | Traces each target's disposition. |
-W file , --what-if=file , --new-file=file , --assume-new=file | Ignores the fact that the target file has been modified. |
--warn-undefined-variables | Warns 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
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;
}
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. Theint
beforemain
indicates this function returns an integer value, a whole number. The return value frommain
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 themyText()
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;
}
The content includes:
#include <stdio.h>
. This statement brings in the standard library that lets you use functions likeprintf
, 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 namedmyText
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, theprintf
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);
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
3. List all the files in the current directory with the ls command:
ls
The system creates the new executable, a.out. You can also see the executable via a file explorer:
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
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.
2. Open the file and use the basic Makefile syntax as the guideline:
3. Type the new executable's name as the target, for example, my_app.
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.
5. Hit TAB and invoke the gcc compiler for the object files:
<TAB> gcc main.o text.o
6. Add the -o
flag and name the target my_app.
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
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
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
4. After completing the Makefile, save it and type:
make
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
The terminal shows that running the command created my_app. To run the my_app file, type:
./my_app
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:
2. Change the text to "Where am I?"
:
3. Save the file, open the terminal, and run:
make
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
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
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
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
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
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
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
When running make
in the terminal, the command reads the C
variable as gcc
:
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.