- Compiler Options
- Library and Header Paths
- Source and Object Files
- Binary Name
Makefiles are an essential tool in software development. They are used to automate the build process of a program, ensuring that all the necessary steps are taken to compile the source code into an executable. Makefiles are platform-independent, meaning they can be used on any operating system, including Windows, Linux, and macOS.
In this blog post, we will go through the process of creating a makefile from scratch, explaining each step along the way. We will also provide some tips and best practices to help you create an efficient and maintainable makefile.
Makefile is a text file with no extension.
$ touch Makefile
Here’s an example makefile that you can use as a starting point:
# Compiler options CC=gcc CFLAGS=-Wall -Wextra # Library and header paths LIBS=-lm INCS=-I./include # Source and object files SRCS=./src/main.c ./src/foo.c OBJS=$(SRCS:.c=.o) # Binary name TARGET=my_program # Targets all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(LIBS) $(INCS) -o $@ $(OBJS) %.o: %.c $(CC) $(CFLAGS) $(INCS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET)
Let’s go through each section of the makefile and explain what it does.
CC=gcc CFLAGS=-Wall -Wextra
In this section, we define the compiler we want to use (gcc) and any additional compiler flags we want to include (-Wall and -Wextra). By defining the compiler and its associated flags upfront in the makefile, we can ensure that our code is compiled consistently and with the desired settings. Using specific flags like -Wall and -Wextra can catch potential issues early, improving code quality and reliability.
Library and Header Paths
In this section, we define the library and header paths we need to include when compiling our code. LIBS is a list of libraries we want to link to our program (in this case, we’re linking to the math library using -lm). INCS is a list of header files we want to include (in this case, we’re including all header files in the include directory).
Source and Object Files
SRCS=./src/main.c ./src/foo.c OBJS=$(SRCS:.c=.o)
In this section, we define the source files we want to compile and the corresponding object files we want to generate. The “$(SRCS:.c=.o)” syntax replaces the .c extension in SRCS with .o to generate the list of object files. Defining source files and object files is essential in automating the build process and improving productivity for developers.
In this section, we define the name of the binary we want to generate (my_program).
all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(LIBS) $(INCS) -o $@ $(OBJS) %.o: %.c $(CC) $(CFLAGS) $(INCS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET)
In this section, we will define the targets that we want to build using our makefile. To begin with, we have the phony target, “all”, which is dependent on the $(TARGET) target. In other words, when we run the command “make all”, it will automatically trigger the building of the $(TARGET) target.
Moving on, we have the $(TARGET) target, which is dependent on the $(OBJS) target – a list of object files we want to generate. This target compiles our code into a binary file, using the compiler options and library/header paths we previously defined. By doing so, we can ensure that our code is compiled in a consistent and error-free manner.
The make command reads the Makefile and executes the commands listed in it. This can include compiling code, linking libraries, and generating executable files.
Makefiles are a powerful tool for automating the build process of software programs. With Makefiles, developers can define the compilation process and automate it, making the software development process more efficient and less prone to errors. By following the steps outlined in this tutorial, developers can create their own Makefiles and streamline their software development process. Remember to use best practices and keep your Makefiles clean and maintainable to ensure maximum productivity.
Reference links :