BuildExe “Script” example#
Basic Procedure#
Since we are writing our scripts in C++ we first need to compile our “script” to an executable, and then execute it to build targets.
Attention
Limitation of script mode
We need to compile our build “script” using a HOST toolchain. We cannot use a cross compiler here.
Helloworld “script” example#
Write your C++ “script”
Write your
compile.toml
fileWrite your
build.toml
file- Invoke
buildexe
from the command line from the [workspace] folder Pay attention to the
root_dir
andbuild_dir
parameters set in yourcompile.toml
andbuild.toml
file.These directories are relative to the directory from which you invoke buildexe
- Invoke
./buildexe --config compile.toml --config $BUILDCC_HOME/host/host_toolchain.toml
Your target will now be present in
[build_dir]/[toolchain_name]/[target_name]
(taken frombuild.toml
andbuild.helloworld.cpp
)
Directory structure#
Write your C++ “script”#
From the “script” below we can see that we have a few lines of boilerplate
Setup args
Setup register (pre and post callback requirements)
We then setup our main toolchain-target pairs. Highlighted below
- Specify your toolchain
Verify the toolchain existance on your machine by using the
.Verify
APIIf multiple similar toolchains are detected (due to multiple installations), the first found toolchain is picked
You can pass in the
VerifyToolchainConfig
to narrow down your search and verification.
- Specify your compatible target
Every specific target is meant to use a specific target.
For example:
ExecutableTarget_gcc
specialized target can use theToolchain_gcc
specialized toolchain but notToolchain_msvc
.
- Use the Register
.Build
API. We use callbacks here to avoid cluttering ourint main
function. arg_gcc.state
contains ourbuild
andtest
values passed in frombuild.toml
(see below). The.Build
API conditionally selects the target at run time.IMPORTANT Please do not forget to invoke the Target
.Build
API. This API registers the variousCompileCommandTasks
andLinkCommandTasks
.IMPORTANT In line with the above statement, Once the Target
.Build
API has been executed (tasks have been registered), do not attempt to add more information to the Targets. Internally the.Build
API locks the target from accepting further input and any attempt to do so willstd::terminate
your program (this is by design).
- Use the Register
1#include "buildcc.h"
2
3using namespace buildcc;
4
5void clean_cb();
6// All specialized targets derive from BaseTarget
7void hello_world_build_cb(BaseTarget & target);
8
9int main(int argc, char ** argv) {
10 // Setup your args
11 ArgToolchain arg_gcc;
12
13 Args::Init()
14 .AddToolchain("gcc", "GCC toolchain", arg_gcc)
15 .Parse(argc, argv);
16
17 // Register
18 Reg::Init();
19
20 // Pre build steps
21 // for example. clean your environment
22 Reg::Call(Args::Clean()).Func(clean_cb);
23
24 // Build steps
25 // Main setup
26 Toolchain_gcc gcc;
27 ExecutableTarget_gcc hello_world("hello_world", gcc, "");
28
29 Reg::Toolchain(arg_gcc.state)
30 .Func([&](){ gcc.Verify() })
31 .Build(hello_world_build_cb, hello_world);
32
33 // Build your targets
34 Reg::Run();
35
36 // Post build steps
37 // for example. clang compile commands database
38 plugin::ClangCompileCommands({&hello_world}).Generate();
39
40 return 0;
41}
42
43void clean_cb() {
44 fs::remove_all(env::get_project_build_dir());
45}
46
47void hello_world_build_cb(BaseTarget & target) {
48 // Add your source
49 target.AddSource("src/main.cpp");
50
51 // Initializes the target build tasks
52 target.Build();
53}
Write your compile.toml
file#
1# Settings
2root_dir = ""
3build_dir = "_build_internal"
4loglevel = "info"
5clean = false
6
7# BuildExe run mode
8mode = "script"
9
10# Target information
11name = "build.helloworld"
12type = "executable"
13relative_to_root = ""
14srcs = ["build.helloworld.cpp"]
15
16[script]
17configs = ["build.toml"]
root_dir
tells BuildExe your project root directory relative from where it is invoked andbuild_dir
tells BuildExe that the built artifacts should be inserted in this directory relative from where it is invoked.clean
deletes yourbuild_dir
completely for a fresh setup.mode
consists of script and immediate mode. See the Basic Procedure uml diagrams for a better understanding of the differences and purpose.Script Mode: BuildExe “Script” example
Immediate Mode: BuildExe “Immediate” example
- Setup your target information
name
of your compiled “script” executabletype
MUST always be executable in script moderelative_to_root
is a QOL feature to point to a path inside your root where the build “scripts” reside.srcs
and equivalent are files that you want to compile. Please see Compile Options for BuildExe for a full list of target options and inputs for script mode
- [script] submodule
configs
are .toml files passed to our compiled “script” executable. Please see Build Options for “scripts” for a full list of default build options.The values inside
configs
are converted to--config [file].toml --config [file2].toml
and so on and passed with the generated executable.In this example:
./build.helloworld --config build.toml
is run which generates your targets.
Write your build.toml
file#
1# Root
2root_dir = ""
3build_dir = "_build"
4loglevel = "debug"
5
6# Project
7clean = false
8
9# Toolchain
10[toolchain.gcc]
11build = true
12test = false
Please see the
.cpp
example above and correlate with these options.root_dir
tells BuildExe your project root directory relative from where it is invoked andbuild_dir
tells BuildExe that the built artifacts should be inserted in this directory relative from where it is invoked.clean
invokes yourclean_cb
which determines how your build must be cleaned. In this example we delete thebuild_dir
for a fresh setup.- [toolchain.gcc] submodule
This is a nested submodule of
toolchain
->gcc
->--build
,--test
options and so on.The naming convention follows
toolchain.[name]
provided when using the.AddToolchain
API.In our example:
args.AddToolchain("gcc", "GCC toolchain", arg_gcc);
The
build
andtest
values are used by theRegister
module.In our example
arg_gcc.state.build
andarg_gcc.state.test
REASONING The reason why this has been done is because Buildcc allows your to mix multiple toolchains in a single script. We can now conditionally (at run time) choose the toolchains with which we would want to compile our targets.