Skip to the content.

Easymake is a declarative build system based on YAML files called Emakefile.
It allows you to define targets composed of steps, which execute reusable actions (such as running a shell command, downloading a file, or creating an archive).

Unlike traditional build tools, Easymake emphasizes simplicity, extensibility, and structured documentation.


πŸš€ Getting Started

1. Create your first project

Create a folder my-project and inside it create a file called Emakefile.

targets:
  my_first_target:
    steps:
      - description: Say hello
        shell:
          cmd: echo "Hello !"

Run your target:

cd my-project
emake build //my_first_target

βœ… You should see Hello ! printed.
Emake will also create a .emake folder in your project (learn more about it here).


2. Use variables

Variables make your Emakefile reusable and configurable.


variables:
  name: Linus

targets:
  my_first_target:
    steps:
      - description: Say hello
        shell:
          cmd: echo "Hello {{ variables:name }} !"

Run it and you’ll get:

Hello Linus !

You can also use variables inside in_files or other fields:


variables:
  name: Linus
  linux_readme_url: https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/README

targets:
  my_first_target:
    steps:
      - description: Say hello
        shell:
          in_files:
            - "{{ variables:linux_readme_url }}"
          cmd: echo "Hello {{ variables:name }}! Linux README is here {{ in_files }}"


3. Add target dependencies

Targets can depend on each other. Let’s create an archive before saying hello:


variables:
  name: Linus
  linux_readme_url: https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/README
  linux_credits_url: https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/CREDITS

targets:
  prepare_archive:
    steps:
      - description: Prepare archive containing Readme and Credits
        archive:
          from:
            - "{{ variables:linux_readme_url }}"
            - "{{ variables:linux_credits_url }}"
          to: "{{ EMAKE_OUT_DIR }}/my_archive.tar.gz"

  my_first_target:
    deps:
      - prepare_archive
    steps:
      - description: Say hello
        shell:
          in_files:
            - "{{ EMAKE_OUT_DIR }}/my_archive.tar.gz"
          cmd: echo "Hello {{ variables:name }}! Archive is at {{ in_files }}"


4. Multiple steps in parallel

By default, steps run sequentially. You can set parallel: true when steps are independent:


targets:
  my_first_target:
    parallel: true
    steps:
      - description: Greet
        shell:
          cmd: echo "Hello {{ variables:name }}!"
      - description: Show archive
        shell:
          in_files:
            - "{{ EMAKE_OUT_DIR }}/my_archive.tar.gz"
          cmd: echo "Archive available at {{ in_files }}"


5. Split into multiple Emakefiles

Large projects can be split across multiple Emakefiles. Create the following structure for our example:

πŸ“ Project structure:

my-project/
β”œβ”€ Emakefile
└─ archive/
   └─ Emakefile

Inside archive/Emakefile:


targets:
  prepare_archive:
    steps:
      - description: Prepare archive containing Linux files
        archive:
          from:
            - "{{ //variables:linux_readme_url }}"
            - "{{ //variables:linux_credits_url }}"
          to: "{{ EMAKE_OUT_DIR }}/my_archive.tar.gz"

Note that we don’t use variables from the root Emakefile but you are also able to create variables in this file.

Inside the root Emakefile:


variables:
  name: Linus
  linux_readme_url: https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/README
  linux_credits_url: https://raw.githubusercontent.com/torvalds/linux/refs/heads/master/CREDITS

targets:
  my_first_target:
    deps:
      - //archive/targets:prepare_archive
    steps:
      - description: Say hello
        shell:
          cmd: echo "Hello {{ variables:name }}!"


πŸ›  Command Line

Build a target

emake build [TARGET_PATH]

Use --cwd [PATH] to specify a project directory if not in the current folder.

Clean

Removes the .emake folder.

emake clean

Generate a dependency graph

emake graph [TARGET_PATH]

πŸ“‚ Project Structure


Paths

Paths in Emake are used to reference variables, secrets, and targets across your project structure.
They follow a simple convention inspired by filesystem paths.


Absolute vs Relative paths


Example project structure

my-project/
β”œβ”€ Emakefile
└─ archive/
   β”œβ”€ Emakefile
   └─ other-folder/
      └─ Emakefile

Referencing elements

At the end of a path, you must specify the section and the element name:

Shortcut for targets:
You can omit the targets section since it is the default.
Example:

//archive/other-folder/my-best-target

Summary


πŸ“œ Emakefile Syntax

An Emakefile consists of three main sections:

Variables

Reusable values for commands, URLs, or paths.

variables:
  version: 1.0

Call them with the correct path:


cmd: echo "Version {{ variables:version }}"

Secrets

Secrets are supported for managing credentials (see secrets documentation).

Targets

The core of your build.
Each target has:

Example:

targets:
  build:
    deps: [clean]
    steps:
      - description: Compile
        shell:
          cmd: cargo build

πŸ“– Next Steps