Make and Makefile

What are Make and MakeFiles, and how does it work?

Image by: Opensource.com

Introduction

The Makefile is a text file that contains a script(set fo task) for compiling and building source code into a binary executable. Developers usually place the file in the same directory as the source files. Most of the open-source libraries and projects use Make for building. For example, the following projects have Makefile in the root or /configure folders inside the repository:
  • Shutter   - open-source feature-rich screenshot tool for Linux based operating systems 
  • Gparted  - is a free partition editor for graphically managing your disk partitions
The make is especially effective in large projects where thousands of dependencies, libraries and source files must compile and link together, making hardcoding an impossible task to accomplish. Its purpose is to save time for recompilation and rebuilding. Furthermore, make keeps track of any changes for each file which allows recompiling only the files that were changed since the last build, dramatically decreasing the effort.

Before starting, make sure that you have installed make locally. Cloning one of the repositories above and running the make command in the terminal will execute the build script and produce a runnable binary.

Basic Example and Usage

<target>: <prerequisites>
          <recipe>
First of all, let's create a new directory and add a Makefile inside:
$ mkidr yourDir
$ cd yourDir
$ vim Makefile
With the following content:
hello:
       @echo "Hello, World!"
Now we can try to run the make command in the current directory, which will produce the following:
$ make
Hello, World!

Advanced Example

The example above does not include any prerequisites and variables, so let's fix it. 
Imagine that we have two C files and one Header that we need to compile and combine into one executable:
CC=cc
CFLAGS=-O1 -g
all:    three
clean:    
        rm *.o || true

three:  two.o one.o
        ${CC} ${CFLAGS} -o three two.o one.o

two.o:  two.c two.h
        ${CC} ${CFLAGS} -c two.c

one.o:  one.c
        ${CC} ${CFLAGS} -c one.c
In the snippet above, two binary targets one.o and two.o linked together, producing the three executable. Not to mention the variables at the top defining the compiler and flags, making it much easier to change the configuration in one place and use it everywhere. Additionally, note all "fake" targets appearing at the top, which make will execute it by default. It will perform the targets specified inside it. Note clean "fake" target that will remove all the binary files.

Let's run it:
$ make     
cc -O1 -g -c one.c
cc -O1 -g -o three two.o one.o
$ ll
total 36K
-rw-rw-r-- 1 whoiam whoiam  208 Feb 26 20:44 Makefile
-rw-rw-r-- 1 whoiam whoiam    0 Feb 26 20:46 one.c
-rw-rw-r-- 1 whoiam whoiam 1.5K Feb 26 20:46 one.o
-rwxrwxr-x 1 whoiam whoiam  18K Feb 26 20:46 three
-rw-rw-r-- 1 whoiam whoiam   30 Feb 26 20:45 two.c
-rw-rw-r-- 1 whoiam whoiam    0 Feb 26 20:44 two.h
-rw-rw-r-- 1 whoiam whoiam 2.8K Feb 26 20:45 two.o
We can execute the make again:
$ make 
make: Nothing to be done for 'all'.
Make keeps track of last-modified timestamps (mtime) for each file,  recompiling when you introduce any changes.

Fake Targets

We can specify "fake" targets that perform specific operations or combine existing instructions in the Makefile into one command. It might be effective in the case of batch execution of scripts in one run. For example:
  • all: may build all targets and binaries specified 
  • docs: may generate documentation
  • install: may install all files and dependencies(i.e. npm -i)
  • clean: may clean all executables, binaries and intermediate files
  • dist-clean: may erase all files not included in the original distribution
  • check: may be used to run tests 

Conclusion

You can learn more about makefiles by referring to the official GNU Make manual for complete documentation and handy examples. Additionally, I would recommend using bash scripting to build source code for small projects as an alternative. I can also recommend learning about automake, which automates the makefile generation for different platforms. Overall, I would say that a Makefile is a great tool that can make developing life a little bit easier by automating the build process.

Author: Iurii Kondrakov 
GitHub: github.com

Comments