Sunday, September 13, 2020

Makefile : the forgotten Unix command for build automation

1. Introduction:


A software program (or services, a term used nowadays to describe software that runs in the cloud instead of your on your computer) is usually created from multiple separate source files, libraries, etc. Multiple source files are compiled IN ORDER, and libraries are linked in, to make a software program. The compile step requires the multiple separate source code files to be compiled in sequence. 


You change a source file, you run one command, and all needed associated source files that is impacted by the change in the source file is recompiled. The end result is new, updated version of the software program with the latest source code change(s).

There are multiple build automation software for this, such as Ant, Maven, Gradle, etc. But before diving into these automation software, you can actually learn on your Unix based laptop, using a Unix command called "make". 



2. The anatomy of a Makefile


The Unix "make" command has been available since 1976.  The simple idea behind make is that:


   1) you have a bunch of source files

   2) you know how to compile the source files into final code

   3) you know how to run the final code


You "codify" these into a text file called Makefile. I won't go into the syntax of a Makefile here, but rather focus on what it does for now. Using a Hello java program. Let's look at a Makefile :


   --- Makefile ---

   target : <tab> dependency 

   <tab> command


Decoding the Makefile:


   target: the compiled file, such as Hello.class; this of this as the output of the command

   dependency : the source code that the compiled file (target) depends on, such as Hello.java

   command: how do you compile the dependency (source file) into the target (compiled file), 

                     such as javac Hello.java


So for the above example:


   Hello.class:    Hello.java

                          javac Hello.java


This says Hello.class depends on Hello.java. If Hello.class is older than Hello.java, invoke the command "javac Hello.java" to compile and update Hello.class.


3. A Real Example:


Let's use a simple working Hello java example:

class Hello {

   public static void main (String [] sin) {

      System.out.println("Hello!");

   

   }

}

   1) you have a bunch of source files (say Hello.java)

   2) you know how to compile the source files into final code (javac Hello.java)

   3) you know how to run the final code (java Hello.class)


If you want to try out a simple Unix command line way of building a Java application (just prints Hello), you can follow along:



----- Makefile -----


go:     Hello.class     

        java Hello



Hello.class:    Hello.java

        javac Hello.java


clean:

        rm -f Hello.class



---- using make to build & run, for the very first time  ---

%make -n # let's see what make will do, but don't do it, could have used --dry-run

ac-a01:0HelloWorld chiangal$ make -n


javac Hello.java

java Hello

%make # compile, run, but this time, do it for reals

ac-a01:0HelloWorld chiangal$ make


javac Hello.java

java Hello

Hello


%make # this time only run

ac-a01:0HelloWorld chiangal$ make


java Hello

Hello


%vi Hello.java # modify the source file Hello.java by adding ! to Hello

class Hello {

   public static void main (String [] sin) {

      System.out.println("Hello!");


   }

}

%make # because the source code Hello.java has been changed, make will re-compile, run

chiangal-a01:0HelloWorld chiangal$ make


javac Hello.java

java Hello

Hello!


%make -f clean; ls Hello.class # everything works, let's clean up and go to sleep, but let's look at command first

ac-a01:0HelloWorld chiangal$ make -n clean; ls Hello.class 


rm -f Hello.class

Hello.class


%make clean; ls Hello.class # looks good, let's do it : remove generated files

ac-a01:0HelloWorld chiangal$ make clean; ls Hello.class 


rm -f Hello.class

ls: Hello.class: No such file or directory



4. Conclusion:

The unix "make" command is a good way to learn about build automation on your own laptop that supports some flavor of Unix (like MacOS). In one command "make", the Unix will read the Makefile that you have created, knows what the final program is (Hello.class), reads the Makefile to find dependencies on how to build Hello.class (depends on Hello.java, the command to compile it is javac Hello.java). 

No comments :

Post a Comment