Saturday, July 19, 2014

Markdown Highlighter Languages

Languagehighlight codeLanguagehighlight code
ABAPabapActionScriptas
ActionScript 3as3Adaada
ANTLRantlrANTLR With ActionScript Targetantlr-as
ANTLR With C# Targetantlr-csharpANTLR With CPP Targetantlr-cpp
ANTLR With Java Targetantlr-javaANTLR With ObjectiveC Targetantlr-objc
ANTLR With Perl Targetantlr-perlANTLR With Python Targetantlr-python
ANTLR With Ruby Targetantlr-rubyApacheConfapacheconf
AppleScriptapplescriptaspx-csaspx-cs
aspx-vbaspx-vbAsymptoteasy
BashbashBash Sessionconsole
BatchfilebatBBCodebbcode
BefungebefungeBooboo
BrainfuckbrainfuckCc
C#csharpC++cpp
c-objdumpc-objdumpcfstatementcfs
CheetahcheetahClojureclojure
CMakecmakeCoffeeScriptcoffee-script
Coldufsion HTMLcfmCommon Lispcommon-lisp
cpp-objdumpcpp-objdumpCSScss
CSS+Django/Jinjacss+djangoCSS+Genshi Textcss+genshitext
CSS+Makocss+makoCSS+Myghtycss+myghty
CSS+PHPcss+phpCSS+Rubycss+erb
CSS+Smartycss+smartyCythoncython
Ddd-objdumpd-objdump
Darcs PatchdpatchDebian Control filecontrol
Debian SourcelistsourceslistDelphidelphi
DiffdiffDjango/Jinjadjango
DylandylanEmbedded Ragelragel-em
ERBerbErlangerlang
Erlang erl sessionerlEvoqueevoque
FelixfelixFortranfortran
GASgasGenshigenshi
Genshi TextgenshitextGettext Catalogpot
GherkinCucumberGLSLglsl
GnuplotgnuplotGogo
GroffgroffHamlhaml
HaskellhaskellhaXehx
HTMLhtmlHTML+Cheetahhtml+cheetah
HTML+Django/Jinjahtml+djangoHTML+Evoquehtml+evoque
HTML+Genshihtml+genshiHTML+Makohtml+mako
HTML+Myghtyhtml+myghtyHTML+PHPhtml+php
HTML+Smartyhtml+smartyINIini
IoioIRC logsirc
JavajavaJava Server Pagejsp
JavaScriptjsJavaScript+Cheetahjs+cheetah
JavaScript+Django/Jinjajs+djangoJavaScript+Genshi Textjs+genshitext
JavaScript+Makojs+makoJavaScript+Myghtyjs+myghty
JavaScript+PHPjs+phpJavaScript+Rubyjs+erb
JavaScript+Smartyjs+smartyLighttpd configuration filelighty
Literate HaskelllhsLLVMllvm
LogtalklogtalkLualua
MakefilemakeMakefile (basemake)basemake
MakomakoMatlabmatlab
MiniDminidModelicamodelica
Modula-2modula2MoinMoin/Trac Wiki markuptrac-wiki
MOOCodemoocodeMuPADmupad
MXMLmxmlMyghtymyghty
MySQLmysqlNASMnasm
NewspeaknewspeakNginx configuration filenginx
NumPynumpyobjdumpobjdump
Objective-Cobjective-cObjective-Jobjective-j
OCamlocamlOocooc
PerlperlPHPphp
POVRaypovPrologprolog
PythonpythonPython 3python3
Python 3.0 Tracebackpy3tbPython console sessionpycon
Python TracebackpytbRaw token dataraw
RConsolerconsoleREBOLrebol
RedcoderedcodereStructuredTextrst
RHTMLrhtmlRubyrb
Ruby irb sessionrbconSsplus
SasssassScalascala
SchemeschemeSmalltalksmalltalk
SmartysmartySQLsql
sqlite3consqlite3SquidConfsquidconf
TcltclTcshtcsh
TeXtexText onlytext
ValavalaVB.netvb.net
VimLvimXMLxml
XML+Cheetahxml+cheetahXML+Django/Jinjaxml+django
XML+Evoquexml+evoqueXML+Makoxml+mako
XML+Myghtyxml+myghtyXML+PHPxml+php
XML+Rubyxml+erbXML+Smartyxml+smarty
XSLTxsltYAMLyaml

Tuesday, July 15, 2014

Custom OO Golang Error Handling

This golang code sample demonstrates the following go language features:
  • switch statement
  • classes (struct + methods)
  • variadic function
  • include timestamp in error message
  • custom error type
  • inherit behavior from base class using embedded struct

This example shows how to create a base class *** that provides consistency in error logging.

(***) Go uses structs and associated methods which provides the same functionality as a classical "class" with it's internal methods in Object Oriented (OO) programing.

You can then create error subclasses that have custom behaviors, e.g., emailing admins or sending a text message to a manager.

Having consistent error logging patterns become valuable when you use log analysis tools like Splunk.

Code Example


package main

import (
 "fmt"
 "time"
)

type Err struct {
 errNo int
 when time.Time
 msg string
}

func (e *Err) Error() string {
 return fmt.Sprintf("%v [%d] %s", e.when, e.errNo, e.msg)
}
func (err Err) errorNumber() int {
 return err.errNo
}

type ErrWidget_A struct {
 Err       // Err is an embedded struct - ErrWidget_A inherits it's data and behavior
}
// a behavior only available for the ErrWidget_A
func (e ErrWidget_A) Error() string {
 fmt.Println("do special ErrWidget_A thing...")
 return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg)
}
// a behavior only available for the ErrWidget_A
func (e ErrWidget_A) optionalErrHandlingOperation() {
 fmt.Println("Email the admins...\n")
}

type ErrWidget_B struct {
 Err      // Err is an embedded struct - ErrWidget_B inherits it's data and behavior
}
// a behavior only available for the Widget_B
func (e ErrWidget_B) Error() string {
 fmt.Println("do special Widget_B thing...")
 return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg)
}
// a behavior only available for the Widget_B
func (e ErrWidget_B) optionalErrHandlingOperation() {
 fmt.Println("SMS operations manager...\n")
}

func run() error {
 return &Err{
  8001,
  time.Now(),
  "generic error occurred\n",
 }
}

func run2() *ErrWidget_B {
 errB := new(ErrWidget_B)
 errB.errNo = 6001
 errB.when = time.Now()
 errB.msg = "Widget_B error occurred"
 return errB
}

func RunWidget(modelNo int) (string, error) {
 // Run valid widgets
 switch modelNo {
 case 1:
  return fmt.Sprintf("run widget model %d", modelNo), nil
 case 2:
  return fmt.Sprintf("run widget model %d", modelNo), nil
 default:
  // Error condition - unknown widget model number
  errA := new(ErrWidget_A)
  errA.errNo = 5002
  errA.when = time.Now()
  errA.msg = "Widget_A error occurred"
  return fmt.Sprintf("unable to run unknown model %d", modelNo), errA
 }
}

// Split multiple (variadic) return values into a slice of values
// in this case, where [0] = value and [1] = the error message
func split(args ...interface{}) []interface{} {
 return args
}

func main() {

 // Execute RunWidget function and handle error if necessary
 msg := ""
 // RunWidget(1) succeeds
 x := split(RunWidget(1))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(1) => result(%s)" + msg, x[0])

 // RunWidget(2) succeeds
 x = split(RunWidget(2))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(2) => result(%s)" + msg, x[0])

 // RunWidget(666) fails -
 x = split(RunWidget(666))
 msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])}
 fmt.Printf("RunWidget(666) => result(%s)" + msg, x[0])


 // Throw generic custom error type and handle it
 if err := run(); err != nil { fmt.Println(err) }

 // Throw ErrWidget_B error and handle it by printing and running optional custom behavior
 widget_B_error := run2(); if widget_B_error.errNo != 0 {
  fmt.Println(widget_B_error)
 }
 fmt.Println("")


 timeNow := time.Now()
 // Create and print ErrWidget_A, then call custom behavior
 a := ErrWidget_A {Err{5001, timeNow, "test"}}
 fmt.Println(a)  // fmt will execute Error() method that can have special behavior
 fmt.Println("A ErrWidget_A has this error number: ", a.errorNumber())
 a.optionalErrHandlingOperation()  // Widget_A emails admins

 // Create ErrWidget_B, then call custom behavior
 b := ErrWidget_B {Err{6001, timeNow, "test"}}
 fmt.Println("A ErrWidget_B has this error number: ", b.errorNumber())
 b.optionalErrHandlingOperation()  // Widget_B sends SMS message to managers
 // Since b was not printed by fmt, the special ErrWidget_B behavior is not triggered
}


Output


RunWidget(1) => result(run widget model 1)

RunWidget(2) => result(run widget model 2)

do special ErrWidget_A thing...
RunWidget(666) => result(unable to run unknown model 666), err(2014-07-15 23:58:29.852925228 -0400 EDT [5002] Widget_A error occurred)

2014-07-15 23:58:29.853084372 -0400 EDT [8001] generic error occurred

do special Widget_B thing...
2014-07-15 23:58:29.853095357 -0400 EDT [6001] Widget_B error occurred

do special ErrWidget_A thing...
2014-07-15 23:58:29.853106552 -0400 EDT [5001] test
A ErrWidget_A has this error number:  5001
Email the admins...

A ErrWidget_B has this error number:  6001
SMS operations manager...


Process finished with exit code 0


Notes

In Go, an error is something that implements an Error() function that returns a string. Here's the predefined, built-in interface type error:

type error interface {
    Error() string
}


The fmt package functions automatically call the Error() function when asked to print an error.


References

http://www.golangbootcamp.com/book/interfaces#sec-errors
https://gobyexample.com/errors
http://tour.golang.org/#58

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

OO Example in Golang

This golang code sample demonstrates the following go language features:
  • string and float64 data types
  • constants
  • variables with initializers
  • iterating ranges
  • slices
  • encapsulation / visibility
  • variadic functions
  • new function
  • pointers
  • structs / struct literals
  • methods
  • multiple implicit interfaces
  • signature based polymorphism

Code Example


package main    // Executable commands must always use package main.

import (
    "fmt"       // fmt.Println formats output to console
    "math"      // provides math.Sqrt function
)

// ----------------------
//    Shape interface
// ----------------------
// Shape interface defines a method set (consisting of the area method)
type Shape interface {
    area() float64          // any type that implements an area method is considered a Shape
}
// Calculate total area of all shapes via polymorphism (all shapes implement the area method)
func totalArea(shapes ...Shape) float64 {   // Use interface type as as function argument
    var area float64                        // "..." makes shapes "variadic" (can send one or more)
    for _, s := range shapes {
        area += s.area()    // the current Shape implements/receives the area method
    }                       // go passes the pointer to the shape to the area method
    return area
}

// ----------------------
//    Drawer interface
// ----------------------
type Drawer interface {
    draw()                  // does not return a type
}
func drawShape(d Drawer) {  // associate this method with the Drawer interface
    d.draw()
}

// ----------------------
//      Circle Type
// ----------------------
type Circle struct {        // Since "Circle" is capitalized, it is visible outside this package
    x, y, r float64         // a Circle struct is a collection of fields: x, y, r
}
// Circle implements Shape interface b/c it has an area method
// area is a method, which is special type of function that is associated with the Circle struct
// The Circle struct becomes the "receiver" of this method, so we can use the "." operator
func (c *Circle) area() float64 {   // dereference Circle type (data pointed to by c)
    return math.Pi * c.r * c.r      // Pi is a constant in the math package
}
func (c Circle) draw() {                                
    fmt.Println("Circle drawing with radius: ", c.r)    // encapsulated draw implementation for Circle type
}
// ----------------------
//     Rectangle Type
// ----------------------
type Rectangle struct {     // a struct contains named fields of data
    x1, y1, x2, y2 float64  // define multiple fields with same data type on one line
}
func distance(x1, y1, x2, y2 float64) float64 {         // lowercase functin name visible only in this package
    a := x2 - x1
    b := y2 - y1
    return math.Sqrt(a * a + b * b)
}
// Rectangle implements Shape interface b/c it has an area method
func (r *Rectangle) area() float64 {       // "r" is passed by reference
    l := distance(r.x1, r.y1, r.x1, r.y2)  // define and assign local variable "l"
    w := distance(r.x1, r.y1, r.x2, r.y1)  // l and w only available within scope of area function
    return l * w
}
func (r Rectangle) draw() {                // "r" is passed by value
    fmt.Printf("Rectangle drawing with point1: (%f, %f) and point2: (%f, %f)\n", r.x1, r.y1, r.x2, r.y2)
}
// ----------------------
//    MultiShape Type
// ----------------------
type MultiShape struct {
    shapes []Shape  // shapes field is a slice of interfaces
}
//
func (m *MultiShape) area() float64 {
    var area float64
    for _, shape := range m.shapes {    // iterate through shapes ("_" indicates that index is not used)
        area += shape.area()            // execute polymorphic area method for this shape
    }
    return area
}

func main() {
    c := Circle{0, 0, 5}                                            // initialize new instance of Circle type by field order "struct literal"
                                                                    // The new function allocates memory for all  fields, sets each to their zero value and returns a pointer
    c2 := new(Circle)                                               // c2 is a pointer to the instantiated Circle type
    c2.x = 0; c2.y = 0; c2.r = 10                                   // initialize data with multiple statements on one line
    fmt.Println("Circle Area:", totalArea(&c))                      // pass address of circle (c)
    fmt.Println("Circle2 Area:", totalArea(c2))                     // c2 was defined using built-in new function
    r := Rectangle{x1: 0, y1: 0, x2: 5, y2: 5}                      // "struct literal" rectangle (r) initialized by field name
    fmt.Println("Rectangle Area:", totalArea(&r))                   // pass address of rectangle (r)
    fmt.Println("Rectangle + Circle Area:", totalArea(&c, c2, &r))  // can pass multiple shapes
    m := MultiShape{[]Shape{&r, &c, c2}}                            // pass slice of shapes
    fmt.Println("Multishape Area:", totalArea(&m))                  // calculate total area of all shapes
    fmt.Println("Area Totals:", totalArea(&c, c2, &r))              // c2 is a pointer to a circle, &c and &r are addresses of shapes
    fmt.Println("2 X Area Totals:", totalArea(&c, c2, &r, &m))      // twice the size of all areas
    drawShape(c)                                                    // execute polymorphic method call
    drawShape(c2)
    drawShape(r)
}



Output


Circle Area: 78.53981633974483
Circle2 Area: 314.1592653589793
Rectangle Area: 25
Rectangle + Circle Area: 417.69908169872417
Multishape Area: 417.69908169872417
Area Totals: 417.69908169872417
2 X Area Totals: 835.3981633974483
Circle drawing with radius:  5
Circle drawing with radius:  10
Rectangle drawing with point1: (0.000000, 0.000000) and point2: (5.000000, 5.000000)

Process finished with exit code 0




Notes

Nearly every line of this code example is documented; Scroll to the right to see all of the comments. This code example shows how to implement a solution using object oriented techniques in Golang.

Golang does not use a class keyword but is none-the-less object oriented.

Methods and interfaces are the language constructs that define objects and their behavior.

There is no explicit implementation inheritance; However, type embedding can be used for the same purpose.

Golang includes very little ceremony in order to provide language features.
  • no semi-colons at end of each statement
  • little declaration required - golang performs implicit type conversion and eliminates need for var keyword with ":=" operator
  • visibility and encapsulation - Some languages require you to use public, private, friend, etc. keywords. Golang simply looks for capitalization of function/struct names.
  • A type implements an interface by implementing the methods - Some languages require explicit declaration of intent; You don't have to find every interface implementation and label it with the new interface name.

By adding a receiver to a function definition, Golang allows you to associate that method with a structure, whereby you can use the "." operator to call the associated method.

Golang does not have a self or this keyword to reference to the current instance. In the method example of func (c *Circle) area() float64 the receiver struct is named "c". Use that variable name, rather than this to refer to the current instance.

Golang uses signature based polymorphism; If a struct, in the example above, implements an area method that returns a float64, then it is a Shape.

This is what some call "Duck Typing" meaning, "If it walks like a duck and sounds like a duck then it must be a duck."

In our case, if the struct implements the area method then it is a Shape type struct.

You can define a method on any type you define in your package, not just a struct.

You cannot define a method on a type from another package, or on a basic type.

Methods can be associated with a named type func drawShape(d Drawer) or a pointer to a named type func (c *Circle) area() float64.

Benefits of using a pointer receiver:
  • Avoid copying value of parameter on each method call
  • Allow method to modify the value that its receiver points to

Golang is a statically typed language, which has some significant benefits over dynamic languages like:
  • Compiler catches errors that could be otherwise hard to find runtime errors
  • Better documentation via type signatures that include type of arguments
  • Better error reporting, sooner. Compiler will report line number and indicate exactly what caused the bug.
  • Code runs faster
The first one is especially important when your code base grows.

A few important Golang topics not discussed in this post include closures, concurrency, error handling and testing.

A more notable exclusion is lack of mention of Embedding. which is an OO technique used by Go to inherit/embed the implementation from another class.

Go does not use the class keyword, but I refer to a Go class as a struct and it's associated methods, which combined encapsulates the properties and behavior of a "class" of objects.


References

http://www.golang-book.com/
http://golang.org/doc/code.html
http://tour.golang.org/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Monday, July 7, 2014

Run Second Yeoman Webapp Simultaneously

When you generate a webapp using Yeoman its default connection port is 9000 and its default livereload port is 35729.

If you generated a second webapp using yo webapp and want to run it at the same time as the first one, you must change its connection port and livereload port.

Change the connection port to 9001 and livereload port to 35731

Gruntfile.js

Change Connection Port and Livereload Port

        connect: {
            options: {
                port: 9001,
                open: true,
                livereload: 35731,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'


node_modules/grunt-contrib-watch/tasks/lib/livereload.js

Change Livereload Port

module.exports = function(grunt) {

  var defaults = { port: 35731 };


Port Numbers

You can specify any port numbers in the range 1 to 65535. Note that on Mac/OSX and UNIX systems port numbers below 1024 will most likely require root access to be set.

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Tuesday, July 1, 2014

Install godoc

Installation


$ go install code.google.com/p/go.tools/cmd/godoc


Verify Installation


$ godoc fmt Println
func Println(a ...interface{}) (n int, err error)
    Println formats using the default formats for its operands and writes to
    standard output. Spaces are always added between operands and a newline
    is appended. It returns the number of bytes written and any write error
    encountered.


Compilation Errors?

If you see errors like the following when running the go install command...

darwin amd64 go1.2.1 X:none] expected [darwin amd64 go1.2.2 X:none

... Then, you probably have go object files laying around that were compiled under an older version of go.

So, delete them:

$ echo $GOPATH
/Users/lex/dev/go
$ rm -rf $GOPATH/{bin,pkg}


... Now, re-run your go install code.google.com/p/go.tools/cmd/godoc command.

Warning

Before running the rm -rf command always be careful and verify what you are doing.

Command Not Found

In go 1.2.x, godoc is installed in $GOROOT/bin. So, if you installed Go through Homebrew your GOROOT will be in your /usr/local/Cellar/go/<VERISION>/libexec directory, so it add that to your $PATH.

~/.bashrc


Configure GOROOT, GOPATH and PATH in ~/.bashrc


export GOPATH=$HOME/dev/go
export GOROOT=`go env GOROOT`
export PATH=$PATH:$GOROOT/bin




References

http://lexsheehan.blogspot.com/2014/07/golang-development-via-ide.html

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Golang Development via IDE

I use two golang development environments.

  • Command Line Shell / Text Editor
  • Golang IDE


I'll cover what I do in the Command Line Shell in another post.

Install Go

Before you begin working with Go, use Homebrew to install it.


$ brew install go
$ go version
go version go1.2.2 darwin/amd64


Your go version may be different.

Golang IDE

I use Jetbrains tools for a lot of reasons. Here are a few:

  • Go application compilation
  • Syntax highlighting
  • Auto-completion
  • Declaration navigation


For a more complete list see: http://lexsheehan.blogspot.com/2014/03/go-language-intellij-idea-plugin.html

The Golang plugin only works with IntelliJ.

Fortunately, there is a free "Community" version available here: http://www.jetbrains.com/idea/download/

Install the go-language-intellij-idea-plugin from the menu:

IntelliJ IDEA (main menu) > Preferences ... > Plugins

Click "Install JetBrains plugin..." and enter golang as the search term

Then, click the install button for the go-language-intellij-idea-plugin


Declaration Navigation Broken?


If you see red warnings with messages that say something like, "cannot find declaration to go to", then from the menu: File > Invalidate Caches / Restart...


~/.bashrc

Configure GOROOT, GOPATH and PATH in ~/.bashrc

You can also put this in other startup files, but I prefer ~/.bashrc


export GOPATH=$HOME/dev/go
export GOROOT=`go env GOROOT`
export PATH=$PATH:$GOROOT/bin


Homebrew Version

If you used Homebrew to install go, then GOROOT must end in "libexec"; Otherwise, you'll get errors like this:


~/dev/go/samples/src/bitbucket.org/l3x/hello $ go install
hello.go:4:3: cannot find package "fmt" in any of:
 /usr/local/Cellar/go/1.2.2/src/pkg/fmt (from $GOROOT)
 /Users/lex/dev/go/samples/src/fmt (from $GOPATH)
package bitbucket.org/l3x/hello
 imports runtime: cannot find package "runtime" in any of:
 /usr/local/Cellar/go/1.2.2/src/pkg/runtime (from $GOROOT)
 /Users/lex/dev/go/samples/src/runtime (from $GOPATH)


/etc/launchd.conf

Configure GOROOT and GOPATH in /etc/launchd.conf

Create the file if it does not already exist.

setenv GOROOT $GOROOT
setenv GOPATH $GOPATH


Enable launchctl settings without rebooting:


$ launchctl setenv GOROOT $GOROOT
$ launchctl setenv GOPATH $GOPATH


Enable launchctl settings if you start IntelliJ from spotlight.

If you start IntelliJ from the command line, this won't be necessary.

References

http://lexsheehan.blogspot.com/2014/03/go-language-intellij-idea-plugin.html

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

Monday, June 30, 2014

How a Makefile Works

Make is a utility that automatically builds executable programs and libraries from source code by reading files called makefiles which specify how to derive the target program.

Besides building programs, Make can be used to manage any project where some files must be updated automatically from others whenever the others change.

The example below shows how to use a Makefile to automatically compile a C source code file "example.c" (only when it has been changed) and then execute the compiled file "./example".

./example.c

Create the source file.

#include
int main()
{
 printf ("Hello\n");
 return 0;
}


./Makefile

Create the Makefile.

exec: compile
 ./example

compile: \
example.c
 gcc example.c -o example
 echo "compiling..."
 touch compile


Makefile Notes

Make assumes that Makefile targets are files in the same directory in which the make command is executed.

If the target file is already there, and its dependencies didn't change, nothing will be done.

"compile" is a dependency of the exec target. "compile" will be executed prior to executing the exec command "./example"

"example.c" is a dependency of the compile target. (It could be on the same line as "compile", but we used the line continuation character "backslash" to put in on a separate line.)

"compile" will be executed only if "example.c" has been modified.

The touch command creates a "compile" target file (if it does not already exist) and effectively updates its last updated timestamp.

Make compares the timestamp of example.c to compile. If example.c has been modified after compile, it will run the "compile" target.

Preface each line of a target body with a single TAB character. (There is a TAB character in front of "./example" in the "exec" target.)

This is a lot of work for managing one source file, but is a huge time saver when there are many source files in a project. Make will only compile the files that have been changed since the last time the compile target has been executed.

Results


$ ls -lrt
total 16
-rw-r--r--  1 lex  staff   64 Jun 30 12:34 example.c
-rw-r--r--  1 lex  staff  108 Jun 30 12:35 Makefile


There are only two files in our directory now.

Run make command


$ make
gcc example.c -o example
echo "compiling..."
compiling...
touch compile
./example
Hello


Results


$ ls -lrt
total 40
-rw-r--r--  1 lex  staff    64 Jun 30 12:34 example.c
-rw-r--r--  1 lex  staff   108 Jun 30 12:35 Makefile
-rwxr-xr-x  1 lex  staff  8496 Jun 30 12:35 example
-rw-r--r--  1 lex  staff     0 Jun 30 12:35 compile


Now, there are 4 files.

Run the newly created executable


$ ./example
Hello


./example.c

Add ", World!" to the output.

#include
int main()
{
 printf ("Hello, World!\n");
 return 0;
}



$ ls -lrt
total 40
-rw-r--r--  1 lex  staff   108 Jun 30 12:35 Makefile
-rwxr-xr-x  1 lex  staff  8496 Jun 30 12:35 example
-rw-r--r--  1 lex  staff     0 Jun 30 12:35 compile
-rw-r--r--  1 lex  staff    72 Jun 30 12:38 example.c


Now, "example.c" has a more recent timestamp than the "compile" file.


$ make
gcc example.c -o example
echo "compiling..."
compiling...
touch compile
./example
Hello, World!


Summary

  • Make ran the "compile" target, because it was the first target listed in the Makefile
  • Make ran the "compile" target, because it was a dependency of the "exec" target
  • Make compared the compare file's timestamp to its dependency "example.c" and ran it because example.c has a more recent timestamp.


More Complicated Scenarios

This has been a very simple, contrived example to show how a Makefile works.

In order to handle more source files, make allows you to use macros, wildcard pattern matching and string substitution features to automatically include files without modifying your Makefile.

References

http://en.wikipedia.org/wiki/Make_(software)
http://www.gnu.org/software/make/manual/make.html

This work is licensed under the Creative Commons Attribution 3.0 Unported License.