func Main() {
	config := &bobConfig{}
	err := config.Properties.LoadConfig(configJSONFile)
	if err != nil {
		panic(err)
	}
	builder_ninja := config.Properties.GetBool("builder_ninja")
	builder_android_bp := config.Properties.GetBool("builder_android_bp")
	builder_android_make := config.Properties.GetBool("builder_android_make")
	pctx.AddNinjaFileDeps(configJSONFile, getPathInBuildDir(".env.hash"))
	var ctx = blueprint.NewContext()
	registerModuleTypes(func(name string, mf factoryWithConfig) {
		factory := func() (blueprint.Module, []interface{}) {
			return mf(config)
		}
		ctx.RegisterModuleType(name, factory)
	})
	ctx.RegisterBottomUpMutator("default_deps1", defaultDepsStage1Mutator).Parallel()
	ctx.RegisterBottomUpMutator("default_deps2", defaultDepsStage2Mutator).Parallel()
	ctx.RegisterTopDownMutator("features_applier", featureApplierMutator).Parallel()
	ctx.RegisterTopDownMutator("template_applier", templateApplierMutator).Parallel()
	ctx.RegisterBottomUpMutator("check_lib_fields", checkLibraryFieldsMutator).Parallel()
	ctx.RegisterBottomUpMutator("strip_empty_components", stripEmptyComponentsMutator).Parallel()
	ctx.RegisterBottomUpMutator("supported_variants", supportedVariantsMutator).Parallel()
	ctx.RegisterBottomUpMutator(splitterMutatorName, splitterMutator).Parallel()
	ctx.RegisterTopDownMutator("target", targetMutator).Parallel()
	ctx.RegisterBottomUpMutator("process_paths", pathMutator).Parallel()
	ctx.RegisterBottomUpMutator("default_applier", defaultApplierMutator).Parallel()
	ctx.RegisterBottomUpMutator("depender", dependerMutator).Parallel()
	ctx.RegisterBottomUpMutator("alias", aliasMutator).Parallel()
	ctx.RegisterBottomUpMutator("generated", generatedDependerMutator).Parallel()
	if handler := initGrapvizHandler(); handler != nil {
		ctx.RegisterBottomUpMutator("graphviz_output", handler.graphvizMutator)
		ctx.RegisterSingletonType("quit_singleton", handler.quitSingletonFactory)
	} else {
		ctx.RegisterTopDownMutator("export_lib_flags", exportLibFlagsMutator).Parallel()
		dependencyGraphHandler := graphMutatorHandler{
			map[tgtType]graph.Graph{
				tgtTypeHost:   graph.NewGraph("All"),
				tgtTypeTarget: graph.NewGraph("All"),
			},
		}
		ctx.RegisterBottomUpMutator("sort_resolved_static_libs",
			dependencyGraphHandler.ResolveDependencySortMutator)  
		ctx.RegisterTopDownMutator("find_required_modules",
			findRequiredModulesMutator).Parallel()
		ctx.RegisterBottomUpMutator("check_disabled_modules",
			checkDisabledMutator).Parallel()
		ctx.RegisterTopDownMutator("check_reexport_libs",
			checkReexportLibsMutator).Parallel()
		ctx.RegisterTopDownMutator("collect_reexport_lib_dependencies",
			collectReexportLibsDependenciesMutator).Parallel()
		ctx.RegisterBottomUpMutator("apply_reexport_lib_dependencies",
			applyReexportLibsDependenciesMutator).Parallel()
		ctx.RegisterTopDownMutator("install_group_mutator", installGroupMutator).Parallel()
		ctx.RegisterTopDownMutator("debug_info_mutator", debugInfoMutator).Parallel()
		if !builder_android_bp {
			ctx.RegisterTopDownMutator("escape_mutator", escapeMutator).Parallel()
		}
		ctx.RegisterTopDownMutator("late_template_mutator", lateTemplateMutator).Parallel()
	}
	if builder_ninja {
		config.Generator = &linuxGenerator{}
	} else if builder_android_bp {
		config.Generator = &androidBpGenerator{}
	} else if builder_android_make {
		config.Generator = &androidMkGenerator{}
	} else {
		panic(errors.New("unknown builder backend"))
	}
	config.Generator.init(ctx, config)
	bootstrap.Main(ctx, config)
}
Main is the entry point for the bob primary builder.

It loads the configuration from .bob.config.json, registers the module type
and mutators, initializes the backend, and finally calls into Blueprint.
package core
import (
	"errors"
	"os"
	"github.com/google/blueprint"
	"github.com/google/blueprint/bootstrap"
	"github.com/ARM-software/bob-build/internal/graph"
)
var (
	bobdir         = os.Getenv("BOB_DIR")
	configFile     = os.Getenv("CONFIG_FILE")
	configOpts     = os.Getenv("BOB_CONFIG_OPTS")
	srcdir         = os.Getenv("SRCDIR")
	configJSONFile = os.Getenv("CONFIG_JSON")
)
type moduleBase struct {
	blueprint.SimpleName
}
type configProvider interface {
	Config() interface{}
}
func projectModuleDir(ctx blueprint.BaseModuleContext) string {
	return ctx.ModuleDir()
}
func getConfig(ctx configProvider) *bobConfig {
	return ctx.Config().(*bobConfig)
}
func getBuildDir() string {
	if bootstrap.BuildDir == "" {
		panic("bootstrap.BuildDir was not initialized!")
	}
	return bootstrap.BuildDir
}
func getSourceDir() string {
	return srcdir
}
func getBobDir() string {
	return bobdir
}