To start the tutorial, clone the Hancho repo and cd into hancho/tutorial:
user@host:~$ git clone https://github.com/aappleby/hancho
Cloning into 'hancho'...
<snip>
user@host:~$ cd hancho/tutorial
user@host:~/hancho/tutorial$
Inside the tutorial folder there's a src
folder with a trivial "Hello
World" application consisting of two files, main.cpp
and util.cpp
:
// src/main.cpp
#include "main.hpp"
#include "util.hpp"
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello World %d\n", get_value());
return 0;
}
// src/util.cpp
#include <stdint.h>
int32_t get_value() {
return 42;
}
Assuming we have GCC installed, compiling it from the command line is straightforward:
user@host:~/hancho/tutorial$ mkdir -p build
user@host:~/hancho/tutorial$ g++ src/main.cpp src/util.cpp -o build/app
user@host:~/hancho/tutorial$ build/app
Hello World 42
Here's how we run the same command using Hancho. First, we create build.hancho
in the tutorial directory:
hancho(
command = [
"mkdir -p build",
"g++ src/main.cpp src/util.cpp -o build/app"
]
)
Hancho build files are just Python code in a file ending in .hancho, with a few minor differences. Hancho build files always have access to a global hancho
object, which we can also call as if it's a function to tell Hancho to do some work. The absolute minimum we can pass to hancho()
is just the command to run.
user@host:~/hancho/tutorial$ ../hancho.py
Loading /home/aappleby/repos/hancho/tutorial/build.hancho
Loading .hancho files took 0.000 seconds
Queueing 1 tasks took 0.000 seconds
[1/1] mkdir -p build g++ src/main.cpp src/util.cpp -o build/app
Running 1 tasks took 0.054 seconds
hancho: BUILD PASSED
Of course we don't actually want to hardcode the file names into the command, so let's use Hancho's text templates to fix that. Templates in Hancho work almost identically to Python F-strings, except that they're lazily-evaluated and can only read variables from the hancho()
invocation they're in.
In addition, parameters named in_*
or out_*
are special - strings inside them are assumed to be filenames, and Hancho will check for changes to any in_
file before deciding to re-run the command.
hancho(
command = "g++ {in_src} -o {out_bin}",
in_src = ["src/main.cpp", "src/util.cpp"],
out_bin = "app",
)
Strings in Hancho tasks use Python-style f-string syntax, minus the 'f' prefix. The {}
blocks can contain arbitrary Python expressions, with the limitation that the expressions can only refer to other fields inside the task or to Hancho's built-in functions (see documentation at FIXME).
Let's see what's inside our task:
# tutorial/tut00.hancho
task = hancho(
desc = "Compile {in_src} -> {out_bin}",
command = "g++ {in_src} -o {out_bin}",
in_src = ["src/main.cpp", "src/util.cpp"],
out_bin = "app",
)
print(task)
There's quite a lot of stuff in there:
aappleby@Neurotron:~/repos/hancho/tutorial$ ../hancho.py -f tut00.hancho -v
Loading /home/aappleby/repos/hancho/tutorial/tut00.hancho
Task @ 0x727f0371d6a0 {
root_dir = "/home/aappleby/repos/hancho/tutorial",
root_path = "/home/aappleby/repos/hancho/tutorial/tut00.hancho",
repo_name = "",
repo_dir = "/home/aappleby/repos/hancho/tutorial",
build_root = "{root_dir}/build",
build_tag = "",
mod_name = "tut00",
mod_dir = "/home/aappleby/repos/hancho/tutorial",
mod_path = "/home/aappleby/repos/hancho/tutorial/tut00.hancho",
desc = "Compile {in_src} -> {out_bin}",
command = "g++ {in_src} -o {out_bin}",
in_src = [
"src/main.cpp",
"src/util.cpp",
],
out_bin = "app",
task_dir = "{mod_dir}",
build_dir = "{build_root}/{build_tag}/{repo_name}/{rel_path(task_dir, repo_dir)}",
_task_index = 0,
in_files = [],
out_files = [],
_state = 0,
_reason = None,
asyncio_task = None,
_loaded_files = [
"/home/aappleby/repos/hancho/tutorial/tut00.hancho",
],
_stdout = "",
_stderr = "",
_returncode = -1,
}
At the top you can see the global paths that Hancho uses internally, followed by the arguments we passed to hancho()
, followed by the task-specific task_dir
and build_dir
, and finally some private Hancho bookkeeping fields.
In this build file we define a Rule
that contains a
command
with two template variables in_*
and out_*
,
and then we call the rule and give it our source files and our output filename.
Hancho then does the fill-in-the-blanks for us and runs the command, which we
can see with the -v
(verbosity) flag:
user@host:~/hancho/tutorial$ rm -rf build
user@host:~/hancho/tutorial$ ../hancho.py -f tut00.hancho -v
Loading /home/user/hancho/tutorial/tut00.hancho
Loading .hancho files took 0.000 seconds
[1/1] Compile /home/user/hancho/tutorial/src/main.cpp /home/user/hancho/tutorial/src/util.cpp -> /home/user/hancho/tutorial/build/app
Reason: Rebuilding because /home/user/hancho/tutorial/build/app is missing
.$ g++ /home/user/hancho/tutorial/src/main.cpp /home/user/hancho/tutorial/src/util.cpp -o /home/user/hancho/tutorial/build/app
[1/1] Task passed - 'Compile /home/user/hancho/tutorial/src/main.cpp /home/user/hancho/tutorial/src/util.cpp -> /home/user/hancho/tutorial/build/app'
user@host:~/hancho/tutorial$ build/app
Hello World 42
If we run Hancho a second time, nothing will happen because nothing in
in_*
has changed.
aappleby@Neurotron:~/repos/hancho/tutorial$ ../hancho.py -f tut00.hancho -v
Loading /home/aappleby/repos/hancho/tutorial/tut00.hancho
Loading .hancho files took 0.000 seconds
If we change a source file and run Hancho again, it will do a rebuild.
aappleby@Neurotron:~/repos/hancho/tutorial$ touch src/main.cpp
aappleby@Neurotron:~/repos/hancho/tutorial$ ../hancho.py -f tut00.hancho -v
Loading /home/aappleby/repos/hancho/tutorial/tut00.hancho
Loading .hancho files took 0.000 seconds
[1/1] Compile /home/aappleby/repos/hancho/tutorial/src/main.cpp /home/aappleby/repos/hancho/tutorial/src/util.cpp -> /home/aappleby/repos/hancho/tutorial/build/app
Reason: Rebuilding because /home/aappleby/repos/hancho/tutorial/src/main.cpp has changed
.$ g++ /home/aappleby/repos/hancho/tutorial/src/main.cpp /home/aappleby/repos/hancho/tutorial/src/util.cpp -o /home/aappleby/repos/hancho/tutorial/build/app
[1/1] Task passed - 'Compile /home/aappleby/repos/hancho/tutorial/src/main.cpp /home/aappleby/repos/hancho/tutorial/src/util.cpp -> /home/aappleby/repos/hancho/tutorial/build/app'
The above example is not a particularly useful way to use Hancho, but it should check that your installation is working.