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
- Root
Emakefile - Optional subdirectories each with their own
Emakefile - Targets referenced using
//path/to/file/targets:targetor//path/to/file/target
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
- Absolute paths
Start with//and always point from the rootEmakefile.
Example://archive/other-folder/variables:firstname - Relative paths
Start with a single/and are resolved relative to the currentEmakefile.
Example:/archive/other-folder/variables:firstname - Local paths
If you omit the leading slash, the reference stays within the currentEmakefile.
Example:variables:firstname
Example project structure
my-project/
ββ Emakefile
ββ archive/
ββ Emakefile
ββ other-folder/
ββ Emakefile
- From the root
Emakefileto theother-folderone:- Relative path β
/archive/other-folder/ - Absolute path β
//archive/other-folder/
- Relative path β
Referencing elements
At the end of a path, you must specify the section and the element name:
- Variable
//archive/other-folder/variables:firstname - Secret
//archive/other-folder/secrets:my-deep-secret - Target
//archive/other-folder/targets:my-best-target
Shortcut for targets:
You can omit thetargetssection since it is the default.
Example://archive/other-folder/my-best-target
Summary
//β start from root/β go down into subfolders from current file- no prefix β stay in the same
Emakefile section:nameβ point to a variable, secret, or target- omit
targets:β directly reference a target
π 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:
deps: dependencies (other targets)steps: actions to executeparallel: (optional) run steps concurrently
Example:
targets:
build:
deps: [clean]
steps:
- description: Compile
shell:
cmd: cargo build
π Next Steps
- Learn about all available actions: Actions Reference
- Understand the
.emakefolder: Emake Folder