Writing Buildfiles
- Buildfiles
- Accessing Toolsets
- Targets and Dependencies
- Buildfile Specific Settings
- Default Targets
- Linking Libraries
- Linking Third-Party Libraries
- Per-Target Settings
Buildfiles are the plain Lua scripts that specify the targets and dependencies for a build. They have the extension .forge and appear throughout the directory hierarchy of a project.
The buildfile()
function, used to load a buildfile, temporarily updates the working directory to the directory containing the buildfile and then executes the buildfile. This makes relative paths in the buildfile relative to the buildfile.
Having buildfile relative paths leads naturally to having a hierarchy of buildfiles per source directory where buildfiles in parent directories loading buildfiles from directories beneath their own.
Separating the dependency graph definition in buildfiles from the configuration in the root build script allows the buildfiles to be reused between different projects that might need different configurations. For example the buildfile for a library can be reused by several projects each with different configurations.
Buildfiles
Here we continue the example of the previous section building a C++ static library and executable to print the classic “Hello World!”. The two buildfiles involved are listed fully below and significant features described in the following paragraphs.
From src/library/library.forge a C++ static library implementing the classic “Hello World!” is compiled and archived:
for _, cc in toolsets('^cc.*') do
cc:StaticLibrary '${lib}/hello_world' {
cc:Cxx '${obj}/%1' {
'hello_world.cpp';
};
};
end
From src/executable/executable.forge a C++ executable is linked that uses the library above to print “Hello World!”:
local version = os.date( '%Y.%m.%d' );
for _, cc in toolsets('^cc.*') do
local cc = cc:inherit {
subsystem = 'CONSOLE';
stack_size = 32768;
};
cc:all {
cc:Executable '${bin}/hello_world' {
'${lib}/hello_world';
cc:Cxx '${obj}/%1' {
defines = {
('VERSION="\\"%s\\""'):format( version );
};
'main.cpp';
};
};
};
end
Accessing Toolsets
Buildfiles retrieve toolsets defined in the root build script by looping over toolsets with identifiers that match a pattern. Multiple toolsets are useful when building for multiple architectures (e.g. armv7, arm64, etc) for Android or iOS.
for _, cc in toolsets('^cc.*') do
-- Define targets using the `cc` toolset here.
end
The loop over toolsets('^cc.*')
iterates over the toolsets that were registered in forge.lua with identifiers that start with cc
. This pattern is a Lua pattern not a regular expression. See 6.4.1 Patterns in the Lua manual.
Targets and Dependencies
Targets are the nodes in the dependency graph. Typically each target has an associated file that it builds, a rule to define its behavior, and a list of dependencies that must be built first.
Create targets by calling the rules defined on a toolset like the calls made to cc:StaticLibrary
and cc:Cxx
below. Identifiers are interpolated with settings or functions looked up from the toolset, global variables, and environment variables in that order.
Add dependencies by making a call on the depending target passing the dependencies in a table. Strings passed in this call are implicitly converted into targets representing source files also with interpolation.
for _, cc in toolsets('^cc.*') do
cc:StaticLibrary '${lib}/hello_world' {
cc:Cxx '${obj}/%1' {
'hello_world.cpp';
};
};
end
Target creation and dependency calls are usually chained together. You will often see, as in this example, C++ source files being compiled to object files as Cxx
targets being passed straight to a StaticLibrary
target to be archived into a static library.
Buildfile Specific Settings
Apply setting specific to a buildfile by inheriting settings from a toolset into a new, temporary toolset and overriding those settings that need to change.
for _, cc in toolsets('^cc.*') do
local cc = cc:inherit {
subsystem = 'CONSOLE';
stack_size = 32768;
};
-- Define targets using the inherited `cc` toolset here.
end
Default Targets
Buildfiles communicate their entry-point/root-level targets by adding them as dependencies of a special target “all” in their directory. The root build script for a project can then add these “all” targets to the “all” target in the root directory so that building from the root directory defaults to building all important targets for the project.
for _, cc in toolsets('^cc.*') do
cc:all {
-- Define or list default targets here.
};
end
Linking Libraries
Libraries are linked into an executable or dynamic library by listing them as dependencies of the executable target. String values appearing as dependencies are interpolated so that ${lib}/hello_world
is expanded appropriately.
for _, cc in toolsets('^cc.*') do
-- ...
cc:all {
cc:Executable '${bin}/hello_world' {
'${lib}/hello_world';
cc:Cxx '${obj}/%1' {
'main.cpp';
};
};
};
end
Linking Third-Party Libraries
Third party libraries that exist outside of the project can be passed as a list in the library
attribute of the dependencies call. In this case the libraries are the system libraries pthread and dl for thread and dynamic linking support on Linux. Other scenarios might be third-party libraries that are not provided in source form.
local libraries;
if operating_system() == 'linux' then
libraries = {
'pthread',
'dl'
};
end
-- ...
for _, cc in toolsets('^cc.*') do
cc:all {
cc:Executable '${bin}/forge' {
'${lib}/forge_${architecture}';
libraries = libraries;
-- ...
};
};
end
Per-Target Settings
Some settings are available to be set on each target by passing fields with string keys in a dependency call. See the documentation for each rule for the exact settings that this is available for.
For example pre-processor macros are specified by setting the defines
attribute of the dependencies call to for a Cc
or Cxx
target. Consecutive calls are cumulative with each other and with defines specified in the settings.
local version = ('%s'):format( os.date('%Y.%m.%d') );
-- ...
forge:Cxx '${obj}/%1' {
defines = {
('VERSION="\\"%s\\""'):format( version );
};
'Application.cpp',
'main.cpp'
};
-- ...