Software manual for Jake



Jake is a build utility. Its name comes from: Jobs Make. Parallel jobs are used to make goals.

Jake was inspired by the reliable "make" utility. However, the goal is not to support everything make can do. Rather, to provide a clear approach to achieve user-defined goals. If it is also faster, the better.

The rules and dependencies should all be visible in the config files. This helps for clarity and aims to eliminate the cases of: "maybe another rule was applied", "maybe another tool was launched".

Jake does not know what a compiler is, neither a linker. Simple enough is easier to handle. Limits are not imposed where there is no need to. The user controls what tool, when and how to use it, in order to achieve the chosen goals.

The makefiles which follow to jake syntax can be used directly. Known unsupported make-specific constructs are ignored. e.g. if constructs.


The syntax is roughly a subset of "make" syntax. With few small additions.

Goals, dependencies and rules

goal : dependency ... dependency | order-only-dependency ... order-only-dependency
  rule command
  rule command

A goal is usually a file on file system. When the file exists, its modification time is used.

The goal is re-build when:

  • All dependencies exist.
  • The goal file does not exist, or it is a "phony" goal.
  • At least one dependency is newer.

The goal is Not re-build when:

  • All its dependencies are not newer than the goal.

Re-build means:

  • Run sequentially each command, in the given order.
  • When one command fails, stop and set the goal status fail.
  • When all commands succeed, the current time-stamp is assigned to the goal, internally.

An order-only-dependency need only to exist before the goal is made. Its time is not compared with the goal time. Dependencies after char | are considered order-only-dependencies.

  • The rules usually create a file, with the path exactly as the goal. On the next build, the time-stamp of this file is used.
  • If a file need-not to be created, but a rebuild is not always necessary, a good practice is to use touch goal to create an empty file anyway. Then the goal time-stamp is saved to file-system for the next build to use it.

All parts of the goal are optional, except the goal itself. Dependencies part or rules part can be empty.


usual-goal : dependency ... dependency
  rule command
  rule command
goal-with-order-only-dependency : | order-only-dependency ... order-only-dependency
  rule command
  rule command
goal-with-no-rules : dependency | order-only-dependency
goal-only :

Rule commands are indented by spaces or tab characters.

  • Command prefix - means: consider this command returned code 0.
  • Command prefix @ means: do not echo this command.

Goals are combined in the order they are found.

goal : dep1


goal : dep2

When goal is used, internally it looks like this:

goal : dep1 dep2

Phony goals

.PHONY: special-goal

The special-goal is a phony goal.

  • It is always considered for rebuild, on first-time use.
  • Even if the path special-goal exists, it is rebuild.

Default goal

When Jake is launched without any goal in the command line arguments, the default goal is used.

There is only one default goal: the first one found in a Jake file.

Alternatively, the default goal can be changed like this:

.DEFAULT_GOAL := new-default-goal

Special dependencies

A recursive-directory-dependency:

  • Ends with /..
  • Its time-stamp is the newest, given all files found recursively in that directory or subdirectories.
  • When it exists on file-system, it must be a directory.
  • Not all systems support, or are configured to propagate a file modified time its "container", the directory. And then to update also the upper directory. Even if that feature works, the time update should stop when a sym-link to a directory is part of the dependency path.

  • A recursive-directory-dependency is computed recursively from file-system, only for files. Directories are scanned, but their time-stamp is ignored. The scan may take a bit longer, but is more reliable compared to using the directory timestamp.

Escape character

  • One backslash \ char at the end of the line means: join with the next line.
  • One backslash \ char can be used elsewhere in the line to escape the next char.


  • Internally / is used as a path separator.
  • \ can also be used on Windows. However, it is translated internally to / and back, and it is not officially supported.
  • Spaces in a path are not officially supported. Spaces can make the rules harder to follow. Spaces would also require extra escapes and/or quotes, re-conversion and extra CPU time.


# this is a comment, to the end of the line
// this is also a comment, to the end of the line


  • Environment variables can be used in a Jake file.
  • export VAR command is supported.
  • export VAR=value on a single line is supported as of version v2.30-r0811.

Jake uses JAKE_FLAGS, which can be set in the environment or in a Jake file.

  • When it is found in the environment, it is parsed before the command line arguments.
  • When it is set in a Jake file, it overrides what was set by the command line arguments.

In addition, the following are available:


  • Linux and Windows are currently available.


  • On Linux, the value from the environment is used.
  • On Windows, when not defined, the value is read from the OS.


  • On Linux, the value from the environment is used.
  • On Windows, when not defined, the value is taken from USERNAME.


  • On Linux, the value from the environment is used.
  • On Windows, when not defined, the value is taken from USERPROFILE, else from HOMEDRIVE and HOMEPATH.

These additional variables provide support for flexible-enough cross-compiling build rules.


# variable assignment
VAR = value   // for compatibility with make
VAR = "value"
VAR = 'value' // variables in this string are not expanded right away
VAR := value  // for compatibility with make
VAR += "appended value"

# using variables
include $(VAR_PATH)



include "file"

Include directive allow to use include instructions from another Jake file.

  • The file must exist. It is included in this line and parsed.

-include "file"

This form of Include directive allow to use compiler-generated dependencies, if the compiler generated that file.

  • The file may exist or not.
  • When file exists, it is included in this line and parsed.
  • When file does not exist, this line is ignored.

Wrong syntax

Lines with a wrong/unknown syntax are usually ignored. This is to allow to use Makefiles.

However, there may be cases when errors are reported for known wrong syntax, and the build will not start.


Previous Article Next Article