BuildAMation
![]() | This article has multiple issues. Please help or discuss these issues on the . (Learn how and when to remove these template messages)
|
Developer(s) | Mark Final |
---|---|
Initial release | 2015 |
Stable release | 2.0.0
/ September 9, 2019[1] |
Written in | C# |
Operating system | Windows, macOS, Linux |
Type | Software development tools |
License | New BSD License |
Website | buildamation |
BuildAMation (Bam) is a desktop multi-platform free and open-source software system for writing a single description of how to build software for desktop computers. It defines an extensible architecture based on the C#, exposing a declarative syntax to describe the dependencies between build-able modules. The core assembly exposes a generic dependency system, while packages of C# scripts extend support into multi-threaded command line builds, Microsoft Visual Studio project and solution generation, Apple Xcode project and workspace generation, and Makefile generation.
Features[]
BuildAMation supports building code for C/C++, and Objective C derivatives. It writes build output to a folder named the build root. This out-of-place build ensures that source trees are not modified by a build, and performing a clean build is as simple as deleting one directory.
BuildAMation is extensible by means of defining packages.[2] Packages are any directory containing a special bam folder, which contains files that BuildAMation uses. The files required are an XML file, called the package definition file, which resides directly in the bam folder, which describes the package dependencies. Also, in a Scripts subdirectory of bam, there are C# files that exposes what the current package does. Packages can be logically grouped into repositories.
Example BuildAMation packages provided offer support for various compiler toolchains, and build modes.[2] Such toolchains are Microsoft Visual Studio, Clang for Apple, GCC for Linux, and multiple versions of each. Build modes define how BuildAMation generates its output. Native build mode runs a (multi threaded) command line build, whereas the VSSolution build mode generates a Microsoft Visual Studio solution and projects.
Packages define modules.[2] Modules are either concrete buildable entities or provide an abstract base class for being able to build a class of entity. Each module may refer to a tool, which is what is used to perform the build on that module. A tool is another module, allowing tools to either be prebuilt (e.g. a compiler), or can be built as part of the current build. Tools define settings through a collection of interfaces, which expose named properties for each option to the tool. Settings have default values, but each module can individually override these settings through the use of patches. Patches can either be private (only applied to the current module) or public (applied to the current module and those modules that depend on it). Public patches allow such states as header include paths to be exposed, for example, from a module representing a static library.
Paths in BuildAMation scripts use macros[2] in order to maintain some level of abstraction and reuse. Macros are enclosed in $(macroname) markup. Predefined string functions can also be used in paths, and are enclosed in @funcname(...) markup. The combination of macros and functions allow modules to reuse and recombine parts of source paths to generate output paths.
Invocation[]
BuildAMation provides a command line utility called bam. This executable should be invoked in any package directory to build that package.[3]
Example script[]
Below is an example BuildAMation script from the suite of test packages provided with the release. It generates two dynamic libraries written in C, an executable that uses both libraries, and then collates the three binaries into a directory so that they are runnable.
using Bam.Core;
namespace Test13;
public sealed class DynamicLibraryA : C.DynamicLibrary
{
protected override void Init(Bam.Core.Module parent)
{
base.Init(parent);
this.CreateHeaderContainer("$(packagedir)/include/dynamicLibraryA.h");
this.CreateCSourceContainer("$(packagedir)/source/dynamicLibraryA.c");
this.PublicPatch((settings, appliedTo) =>
{
var compiler = settings as C.ICommonCompilerSettings;
if (null != compiler)
{
compiler.IncludePaths.AddUnique(this.CreateTokenizedString("$(packagedir)/include"));
}
});
if (this.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows) &&
this.Linker is VisualCCommon.LinkerBase)
{
this.LinkAgainst<WindowsSDK.WindowsSDK>();
}
}
}
public sealed class DynamicLibraryB : C.DynamicLibrary
{
protected override void Init(Bam.Core.Module parent)
{
base.Init(parent);
this.CreateHeaderContainer("$(packagedir)/include/dynamicLibraryB.h");
this.CreateCSourceContainer("$(packagedir)/source/dynamicLibraryB.c");
this.PublicPatch((settings, appliedTo) =>
{
var compiler = settings as C.ICommonCompilerSettings;
if (null != compiler)
{
compiler.IncludePaths.AddUnique(this.CreateTokenizedString("$(packagedir)/include"));
}
});
this.LinkAgainst<DynamicLibraryA>();
if (this.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows) &&
this.Linker is VisualCCommon.LinkerBase)
{
this.LinkAgainst<WindowsSDK.WindowsSDK>();
}
}
}
public sealed class Application : C.ConsoleApplication
{
protected override void Init(Bam.Core.Module parent)
{
base.Init(parent);
var source = this.CreateCSourceContainer("$(packagedir)/source/main.c");
this.PrivatePatch(settings =>
{
var gccLinker = settings as GccCommon.ICommonLinkerSettings;
if (null != gccLinker)
{
gccLinker.CanUseOrigin = true;
gccLinker.RPath.AddUnique("$ORIGIN");
}
});
this.CompileAndLinkAgainst<DynamicLibraryA>(source);
this.CompileAndLinkAgainst<DynamicLibraryB>(source);
if (this.BuildEnvironment.Platform.Includes(Bam.Core.EPlatform.Windows) &&
this.Linker is VisualCCommon.LinkerBase)
{
this.LinkAgainst<WindowsSDK.WindowsSDK>();
}
}
}
public sealed class RuntimePackage : Publisher.Collation
{
protected override void Init(Bam.Core.Module parent)
{
base.Init(parent);
var app = this.Include<Application>(C.ConsoleApplication.Key, EPublishingType.ConsoleApplication);
this.Include<DynamicLibraryA>(C.DynamicLibrary.Key, ".", app);
this.Include<DynamicLibraryB>(C.DynamicLibrary.Key, ".", app);
}
}
History[]
What would become BuildAMation begun development in 2010, but was then called Opus, and stored in Google Code. The name was changed in 2014 to BuildAMation to avoid confusion with the existing Opus Make, and moved to a GitHub project. A number of very early pre-releases were made.
The incentive for BuildAMation was to overcome several obstacles observed by Mark Final in his software engineering career; to write a single definition of how to build software but make use of a variety of build methods; to use a real programming language so that debugging and profiling the build system can leverage existing technologies, developer knowledge, and tools; to expose common compiler/linker features by name, rather than having to recall each toolchain syntax.
Early in 2015, the declarative syntax underwent a complete redesign after noticing the original syntax had some limitations. A cleaner, more extensible syntax is now in use, and has helped simplify and enhance existing package scripts.
See also[]
References[]
- ^ "Releases · markfinal/BuildAMation". github.com. BuildAMation. Retrieved 2021-03-28.
- ^ a b c d Final, Mark. "BuildAMation key definitions". BuildAMation. Mark Final. Retrieved 28 December 2015.
- ^ Final, Mark. "BuildAMation - Running Bam". BuildAMation. Mark Final. Retrieved 28 December 2015.
External links[]
- Build automation