Build System
#load "build/build.bl"
Compiler integrated build pipeline. Build pipline can be used to manage whole project compilation
process directly in BL. All you need is to create the build file called build.bl
and specify the
build_entry
function inside. When -b
flag is used without need of specifying any files, the
compiler will lookup build.bl
file in the current directory and execute it in compile time. All
compilation steps, target input and output can be specified here.
Example of minimal build.bl:
build :: fn () #build_entry {
// create new executable target
exe :: add_executable("MyProgram");
// add 'main.bl' file into the target 'exe'
add_unit(exe, "main.bl");
// Start compilation
compile(exe);
}
Start build pipeline using our build.bl file:
$ blc -build
Compiler will automatically use build.bl file as build script and execute build function in compile time. SDK file build/build.bl containing compiler API for build pipeline manipulation is loaded implicitly.
warning: Build API is available only in compile-time.
Basics
Create new executable target
Target is a single build target defined as consisting of build Units representing source files needed for compilation. It`s basically a target compiled into an executable or binary file. Use add_executable function to specify your target. There are several options related to target, described later in this documentation.
exe :: add_executable("MyProgram");
Add file into target
Use add_unit function to add source files into the target. There is no need to add
all files you want to use, general load
and import
will do so automatically. Only main
or
entry files must be included.
add_unit(exe, "main.bl");
Specify output directory
Output directory is a directory where all compiler-produced files will be written (i.e. native executables). Use set_output_dir function to specify this directory, current directory is used by default.
set_output_dir(exe, "bin");
Compile target
compile(exe);
Command line argumets
All argumets passed after -build
compiler flag are automatically forwarded into
command_line_arguments
global variable.
BuilderOptions
BuilderOptions :: struct {
verbose: bool;
no_color: bool;
silent: bool;
no_jobs: bool;
no_warning: bool;
full_path_reports: bool;
no_usage_check: bool;
stats: bool;
enable_experimental_targets: bool;
do_cleanup_when_done: bool;
error_limit: s32;
_doc_out_dir: *C.char;
}
Global builder options.
Members
verbose
- Toggle verbose mode. (Off by default.)no_color
- Toggle coloring the terminal output. (Off by default.)silent
- Silent mode reduces amount of stuff printed to the standard output to minimum. (Off by default.)no_jobs
- Toggle multithreading. (On by default.)no_warning
- Disable all compiler warnings. (Off by default.)full_path_reports
- Use full (absolute) paths in compiler reports. (Off by default.)no_usage_check
- Toggle check of unused symbols. (Off by default.)stats
- Toggle printing of some compilation statistics. (Off by default.)enable_experimental_targets
- Toggle experimantal targets. (Off by default.)-
do_cleanup_when_done
- Release memory after compilation. When compiler is executed as a single-shot application (start -> compile -> end) all the time, we can leave releasing of allocated memory to the operating system to get some compilation speed boost. (Off by default.) -
error_limit
- Maximum count of error reported by the compiler.
File: build.bl
get_builder_options
get_builder_options :: fn () BuilderOptions
Returns copy of current builder options. These are by default initializad from command line arguments passed to the compiler.
File: build.bl
set_builder_options
set_builder_options :: fn (opt: BuilderOptions)
Overrides current builder options previously set from the command line or by calling this function.
File: build.bl
Target
Target :: struct {
kind: TargetKind;
build_mode: BuildMode;
debug_info_kind: DebugInfo;
register_split: bool;
verify_llvm: bool;
run_tests: bool;
tests_minimal_output: bool;
no_api: bool;
copy_dependencies: bool;
run: bool;
print_tokens: bool;
print_ast: bool;
emit_llvm: bool;
emit_asm: bool;
emit_mir: bool;
no_bin: bool;
no_llvm: bool;
no_analyze: bool;
assert_mode: AssertMode;
syntax_only: bool;
vmdbg_enabled: bool;
vmdbg_break_on: s32;
enable_experimental_targets: bool;
triple: TargetTriple;
}
Target is representation of whole program workspace, it's a consist of Units, every unit represents one source file.
Members
kind
- See :ref:TargetKind
.build_mode
- Specify build mode of the target. See BuildModedebug_info_kind
- Specify debug information format used for target in debug mode. See DebugInfo.register_split
- Enable split of function arguments and return value into registers.verify_llvm
- Verify LLVM module.run_tests
- Execute compile time tests.tests_minimal_output
- Reduce compile-time tests output (remove results section).no_api
- Disable default API import.copy_dependencies
- Copy all known dependencies into output folder.run
- Execute main function in compile time.print_tokens
- Print out lexer output.print_ast
- Print out AST.emit_llvm
- Emit LLVM IR code into file.emit_asm
- Emit asm code into file.emit_mir
- Emit MIR code into file.no_bin
- Disable generation of native binary.no_llvm
- Disable LLVM backend.no_analyze
- Disable analyze pass of code generation.assert_mode
- See :ref:AssertMode
.syntax_only
- Check only code syntax.vmdbg_enabled
- Enable virtual machine debugger.vmdbg_break_on
- Specify MIR instruction ID to break on if virtual machine debugger is attached.enable_experimental_targets
- Enable experimental build targets.triple
- Target triple according to LLVM.
File: build.bl
TargetKind
TargetKind :: enum {
EXECUTABLE = 0;
SHARED_LIBRARY = 1;
}
Specification of compiler output binary kind.
File: build.bl
TargetArch
TargetArch :: enum s32 {
UNKNOWN = 0;
X86_64 = 1;
AARCH64 = 2;
ARM64 = 3;
}
File: build.bl
TargetVendor
TargetVendor :: enum s32 {
UNKNOWN = 0;
PC = 1;
APPLE = 2;
}
File: build.bl
TargetSystem
TargetSystem :: enum s32 {
UNKNOWN = 0;
WINDOWS = 1;
DARWIN = 2;
LINUX = 3;
}
File: build.bl
TargetEnvironment
TargetEnvironment :: enum s32 {
UNKNOWN = 0;
MSVC = 1;
GNU = 2;
MUSL = 3;
}
File: build.bl
TargetTriple
TargetTriple :: struct {
arch: TargetArch;
vendor: TargetVendor;
os: TargetSystem;
env: TargetEnvironment;
}
File: build.bl
BuildMode
BuildMode :: enum s32 {
DEBUG = 0;
RELEASE_FAST = 1;
RELEASE_SMALL = 2;
RELEASE_WITH_DEBUG_INFO = 3;
}
Specify target build mode. Every Target can be compiled with various configuration
options. The BuildMode
can specify which set of options compiler should use.
Variants
-
DEBUG
- Generates debug symbols and produce binary without any optimizations.IS_DEBUG
global variable is set totrue
in this mode. (false
in all other modes) -
RELEASE_FAST
- Fast release mode; no debug symbols are produced, all possible optimizations are applied to produce binary as fast as possible. Theassert
is disabled unlessTarget.assert_mode
isALWAYS_ENABLED
. -
RELEASE_SMALL
- Small release mode; no debug symbols are produced, optimizations are applied to produce binary reasonably fast and as small as possible. Theassert
is disabled unlessTarget.assert_mode
isALWAYS_ENABLED
. -
RELEASE_WITH_DEBUG_INFO
- Small release mode; with debug symbols produced, optimizations are applied to produce binary reasonably fast and as small as possible. Theassert
is disabled unlessTarget.assert_mode
isALWAYS_ENABLED
.
File: build.bl
DebugInfo
DebugInfo :: enum s32 {
DWARF = 0;
CODE_VIEW = 1;
}
Debug information format.
File: build.bl
AssertMode
AssertMode :: enum s32 {
DEFAULT = 0;
ALWAYS_ENABLED = 1;
ALWAYS_DISABLED = 2;
}
Specification of assert
mode used for Target
.
Variants
-
DEFAULT
- By default compiler emits all assertions in BuildMode. Debug and skips all assertions in all optimized release modes. -
ALWAYS_ENABLED
- Force-enable assertion in all build modes. ALWAYS_DISABLED
- Force-disable assertion in all build modes.
File: build.bl
add_executable
add_executable :: fn (name: string_view) *Target
Add new executable target into the current compilation queue. Target with specified name is
compiled into binary or it can be just executed in compile-time without any output created.
Assemblies are compiled after build_entry
function execution in order they are added.
Example
build :: fn () #build_entry {
exe :: add_executable("MyProgram");
add_unit(exe, "src/main.bl");
mode :: get_build_mode(exe);
switch mode {
BuildMode.DEBUG {
set_output_dir(exe, "build/debug");
}
BuildMode.RELEASE_SMALL,
BuildMode.RELEASE_FAST {
set_output_dir(exe, "build/release");
}
}
compile(exe);
}
File: build.bl
add_library
add_library :: fn (name: string_view) *Target
Add new shared library target target into the current compilation queue.
File: build.bl
add_unit
add_unit :: fn (target: *Target, filepath: string_view)
Add new source file into the target
. Function does nothing when filepath
is already present
in the target
assembly.
File: build.bl
compile
compile :: fn (target: *Target) Error
Start compilation of the target
assembly and return ok
or error
in case compilation failed.
Target is released after the compilation is done.
File: build.bl
compile_all
compile_all :: fn () Error
Compile all created targets one by one in order they were created. See also compile. All targets are released after the compilation is done.
File: build.bl
add_lib_path
add_lib_path :: fn (target: *Target, path: string_view)
Add path for linker library lookup.
File: build.bl
link_library
link_library :: fn (target: *Target, name: string_view)
Add system library. Only name is required (without extension and prefix). Compiler will lookup
for this library in working directory, system PATH
and LINKER_LIB_PATH
variable specified
in bl.conf
file. Linked library can be used also during compile-time execution, in such case
all needed symbols are loaded in compile-time.
In general there is no need to link libraries manually, all needed dependencies should be handled by module import mechanism, however there is still an option do it manually.
Library name platform specific rules:
- On Linux name will be extended by 'lib' prefix and '.so' extension.
- On MacOS name will be extended by 'lib' prefix and '.dylib' extension.
- On Windows name will be extended only by '.dll' extension.
Example
build :: fn () #build_entry {
exe :: add_executable("MyGame");
add_unit(exe, "src/main.bl");
switch PLATFORM {
Platform.WINDOWS { target_windows(exe); }
default { panic("Unknown build target!"); }
}
compile(exe);
}
target_windows :: fn (exe: *Target) {
link_library(exe, "freetype");
link_library(exe, "zlib");
link_library(exe, "png");
}
File: build.bl
append_linker_options
append_linker_options :: fn (target: *Target, option: string_view)
Appends raw string data directly to linker command. Passed option is added without any processing and compatibility validation.
File: build.bl
set_output_dir
set_output_dir :: fn (target: *Target, dir: string_view)
Set build output directory. This is directory where all output files will be written. For example different output directory can be set for any build mode.
Directory path dir
. This can contain non-existing directories separated by /
, compiler will
create all missing directories in passed path.
Specified directory will be used also for build temporary files.
File: build.bl
get_output_dir
get_output_dir :: fn (target: *Target) string_view
Get output directory specified by set_output_dir or empty string.
File: build.bl
ModuleImportPolicy
ModuleImportPolicy :: enum s32 {
SYSTEM = 0;
BUNDLE = 1;
BUNDLE_LATEST = 2;
}
Specify import module policy in set_module_dir function call. Module dependencies of any target can be treated in different ways depending on use case and needs of programmer. Sometimes program stability and maintainability is more important than use of latest versions of modules. These flags can specify how local modules should be updated.
Variants
-
SYSTEM
- Use system modules but prefer local ones in module directory. This option disables any copying and version check. Local module directory can contain custom project related modules you don't want to expose to the whole system. This is the default option. -
BUNDLE
- Bundle only missing modules from system into the local module folder and ignore if there is newer version available. Individual module updates can be done by renaming old one and re-run compilation. Custom modules (not coming from main API folder are kept untouched.) -
BUNDLE_LATEST
- Bundle all missing modules from system into the local module folder and update old ones also. Custom modules (not coming from main API folder are kept untouched.) Compiler will create.bak
backup directory for every module before any updates.
File: build.bl
set_module_dir
set_module_dir :: fn (target: *Target, dir: string_view, policy :: ModuleImportPolicy.SYSTEM)
Sets module directory dir
for target
. All imported modules will be copied into this
directory according to chosen ModuleImportPolicy. Module policy is set
to SYSTEM
by default even if this function has not been called.
File: build.bl
get_module_dir
get_module_dir :: fn (target: *Target) string_view
Get module directory specified by set_module_dir or default one.
File: build.bl
get_module_import_policy
get_module_import_policy :: fn (target: *Target) ModuleImportPolicy
Get module import policy specified by set_module_dir or default one.
File: build.bl
get_default_triple
get_default_triple :: fn () TargetTriple
Returns target triple of the current host machine.
File: build.bl
triple_to_string
triple_to_string :: fn (triple: TargetTriple) string_view
Converts target triple to string.
Note
The result string is allocated using current temporary allocator.
File: build.bl