Tutorial 2¶
Recap¶
We have created a root build.rabs
script, and defined some meta and file targets. We added some build functions and dependencies. We've also seen how rabs
builds or rebuilds targets when necessary, and skips targets otherwise. In this tutorial, we will introduce some more target types in rabs
.
Nested Directories¶
So far, we have only used one build.rabs
script in a single directory. Larger projects are usually organized in multiple, nested directories. rabs
provides a number of built-in functions and features for dealing with complex project structures, some of which we will cover here.
To start, create a new directory called src
within the tutorial
directory created in the previous tutorial. This is where we will put source code files for our tutorial project. Inside the new src
, create another file called build.rabs
with the following content:
1print("Hello from a subdirectory!\n")
2
3DEFAULT => fun print("Building DEFAULT in src\n")
Note that this build.rabs
file does not need to start with :< ROOT >:
.
Note
Nested build.rabs
files may also start with :< ROOT >:
without problems. In fact, this is useful for nested projects (using a git submodule for example) which can be built both independently or as part of a larger project.
Finally, add one more line to the build.rabs
file in the root tutorial
directory:
1:< ROOT >:
2
3print("Hello world!\n")
4
5var Test := meta("TEST") => fun() print("Building TEST again\n")
6
7var Test2 := file("test.txt") => fun(Target) do
8 var File := Target:open("w")
9 File:write("Hello world!\n")
10 File:close
11end
12
13DEFAULT[Test, Test2] => fun() print("Building DEFAULT again\n")
14
15var Input := file("input.txt")
16var Output := file("output.txt")[Input] => fun(Target) do
17 execute('cp {Input} {Output}')
18end
19
20subdir("src")
21
22DEFAULT[Output]
The final directory structure should look like this:
- 🖹 build.rabs
- 📁 src
- 🖹 build.rabs
Run rabs
as before (in the root tutorial
directory).
$ rabs -s -c
Looking for library path at /usr/lib/rabs
RootPath = /tutorial
Building in /tutorial
Rabs version = 2.11.0
Build iteration = 33
Hello world!
Hello from a subdirectory!
1 / 6 #0 Updated file:input.txt to iteration 1
2 / 6 #0 Updated meta:::TEST to iteration 1
3 / 6 #0 Updated file:output.txt to iteration 1
4 / 6 #0 Updated file:test.txt to iteration 1
Building DEFAULT in src
5 / 6 #0 Updated meta:/src::DEFAULT to iteration 33
Updating due to meta:/src::DEFAULT
Building DEFAULT again
6 / 6 #0 Updated meta:::DEFAULT to iteration 33
When rabs
runs the subdir("src")
function, it loads and runs the file src/build.rabs
. It also automatically creates a new meta target called DEFAULT
specific to the src
directory, and adds it as a dependency of DEFAULT
in the root directory.
Contexts¶
Now we have multiple targets, defined in multiple build.rabs
files located in different directories. In most programming languages, definitions in different files are kept seperate except through module imports or similar mechanisms. Since rabs
is designed to simplify building large nested projects, definitions in build.rabs
files are automatically made available to build.rabs
in nested directories.
Similarly, build.rabs
files in nested directories can affect (add or update) definitions in their parent directories. As a result, rabs
defines the concept of a context when running code. Typically, a context is associated with the directory of the current build.rabs
file. Each context has a single parent context, typically the context of the parent directory. It is however possible to create multiple contexts within a single directory, which we will see in a later tutorial.
Symbol Targets¶
Build instructions are often parameterised:
Various flags or options are passed to external programs such as compilers.
The same project can be built in different configurations by passing options to the build program (in this case
rabs
).
rabs
provides symbol targets to store and retrieve values containing parameters, flags, options, etc. Symbols are created by assigning to an identifier which has not been declared as a variable.
1:< ROOT >:
2
3var Variable := "value"
4
5Symbol := "value"
6
7print('Variable = ', Variable, '\n')
8print('Symbol = ', Symbol, '\n')
Here, Variable
is a normal variable and Symbol
is a symbol. Both have been assigned the same value, "value"
and can be used in code by their identifiers. Although symbols are similar to variables in many ways, they also have a number of extra properties:
Symbols are tracked automatically as dependencies when used in a build function. If the value of a symbol is changed during a subsequent build,
rabs
will rebuild any targets whose build functions used the symbol.Symbols are inherited by contexts, and can be overridden (redefined) in a context without affecting the parent context.
RootPath = /home/raja/Work/Rabs/work/tutorial1 Building in /home/raja/Work/Rabs/work/tutorial1 Rabs version = 2.19.5 Build iteration = 1 Hello world! Hello from a subdirectory! 1 / 6 #0 Updated file:input.txt to iteration 1 Building TEST again 2 / 6 #0 Updated meta:::TEST to iteration 1 /home/raja/Work/Rabs/work/tutorial1: cp /home/raja/Work/Rabs/work/tutorial1/input.txt /home/raja/Work/Rabs/work/tutorial1/output.txt 0.000474 seconds. 3 / 6 #0 Updated file:output.txt to iteration 1 4 / 6 #0 Updated file:test.txt to iteration 1 Building DEFAULT in src 5 / 6 #0 Updated meta:/src::DEFAULT to iteration 1 Building DEFAULT again 6 / 6 #0 Updated meta:::DEFAULT to iteration 1