func checkReexportLibsMutator(mctx blueprint.TopDownMutatorContext) {
	if l, ok := getLibrary(mctx.Module()); ok {
		for _, lib := range l.Properties.Reexport_libs {
			if !utils.ListsContain(lib,
				l.Properties.Shared_libs,
				l.Properties.Static_libs,
				l.Properties.Header_libs,
				l.Properties.Whole_static_libs,
				l.Properties.Export_header_libs) {
				panic(fmt.Errorf("%s reexports unused library %s", mctx.ModuleName(), lib))
			}
		}
	}
}
Check that each module only reexports libraries that it is actually using.
package core
import (
	"errors"
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
	"github.com/google/blueprint"
	"github.com/ARM-software/bob-build/internal/graph"
	"github.com/ARM-software/bob-build/internal/utils"
)
const (
	tocExt = ".toc"
)
var depOutputsVarRegexp = regexp.MustCompile(`^\$\{(.+)_out\}$`)
type propertyExporter interface {
	exportCflags() []string
	exportIncludeDirs() []string
	exportLdflags() []string
	exportLdlibs() []string
	exportLocalIncludeDirs() []string
	exportSharedLibs() []string
}
type CommonProps struct {
	SourceProps
	IncludeDirsProps
	InstallableProps
	EnableableProps
	AndroidProps
	AliasableProps
	Cflags []string
}
type BuildProps struct {
	Out *string
	Export_cflags []string
	Conlyflags []string
	Cxxflags []string
	Asflags []string
	Ldflags []string
	Export_ldflags []string
	Library_version string
	Version_script *string
	Shared_libs []string `bob:"first_overrides"`
	ExtraSharedLibs []string `blueprint:"mutated"`
	Static_libs []string `bob:"first_overrides"`
	Reexport_libs []string `bob:"first_overrides"`
	ResolvedReexportedLibs []string `blueprint:"mutated"`
	ResolvedStaticLibs []string `blueprint:"mutated"`
	Whole_static_libs []string `bob:"first_overrides"`
	Header_libs []string `bob:"first_overrides"`
	Export_header_libs []string `bob:"first_overrides"`
	Ldlibs []string `bob:"first_overrides"`
	Generated_headers []string `bob:"first_overrides"`
	Export_generated_headers []string `bob:"first_overrides"`
	Generated_sources []string
	Generated_deps []string
	Export_local_include_dirs []string `bob:"first_overrides"`
	Export_include_dirs []string `bob:"first_overrides"`
	Build_wrapper *string
	Add_lib_dirs_to_rpath *bool
	Forwarding_shlib *bool
	StripProps
	AndroidPGOProps
	AndroidMTEProps
	TargetType tgtType `blueprint:"mutated"`
}
func (b *BuildProps) processBuildWrapper(ctx blueprint.BaseModuleContext) {
	if b.Build_wrapper != nil {
		*b.Build_wrapper = strings.TrimSpace(*b.Build_wrapper)
		firstWord := strings.SplitN(*b.Build_wrapper, " ", 1)[0]
		if firstWord[0] != '/' {
			if strings.ContainsAny(firstWord, "/") {
				*b.Build_wrapper = getBackendPathInSourceDir(getBackend(ctx), *b.Build_wrapper)
			}
		}
	}
}
type Build struct {
	CommonProps
	BuildProps
	Target TargetSpecific
	Host   TargetSpecific
	SplittableProps
}
func (l *Build) getTargetSpecific(tgt tgtType) *TargetSpecific {
	if tgt == tgtTypeHost {
		return &l.Host
	} else if tgt == tgtTypeTarget {
		return &l.Target
	} else {
		panic(fmt.Errorf("Unsupported target type: %s", tgt))
	}
}
func (l *Build) isHostSupported() bool {
	if l.Host_supported == nil {
		return false
	}
	return *l.Host_supported
}
func (l *Build) isTargetSupported() bool {
	if l.Target_supported == nil {
		return true
	}
	return *l.Target_supported
}
func (l *Build) isForwardingSharedLibrary() bool {
	if l.Forwarding_shlib == nil {
		return false
	}
	return *l.Forwarding_shlib
}
func (l *Build) isRpathWanted() bool {
	if l.Add_lib_dirs_to_rpath == nil {
		return false
	}
	return *l.Add_lib_dirs_to_rpath
}
func (l *Build) getBuildWrapperAndDeps(ctx blueprint.ModuleContext) (string, []string) {
	if l.Build_wrapper != nil {
		depargs := map[string]string{}
		files := getDependentArgsAndFiles(ctx, depargs)
		buildWrapper := *l.Build_wrapper
		for k, v := range depargs {
			buildWrapper = strings.Replace(buildWrapper, "${"+k+"}", v, -1)
		}
		return buildWrapper, files
	}
	return "", []string{}
}
func (l *BuildProps) processPaths(ctx blueprint.BaseModuleContext, g generatorBackend) {
	prefix := projectModuleDir(ctx)
	l.Export_local_include_dirs = utils.PrefixDirs(l.Export_local_include_dirs, prefix)
	l.processBuildWrapper(ctx)
}
func (l *Build) processPaths(ctx blueprint.BaseModuleContext, g generatorBackend) {
	l.BuildProps.processPaths(ctx, g)
	l.CommonProps.processPaths(ctx, g)
}
func (c *CommonProps) processPaths(ctx blueprint.BaseModuleContext, g generatorBackend) {
	prefix := projectModuleDir(ctx)
	c.SourceProps.processPaths(ctx, g)
	c.InstallableProps.processPaths(ctx, g)
	c.IncludeDirsProps.Local_include_dirs = utils.PrefixDirs(c.IncludeDirsProps.Local_include_dirs, prefix)
}
type library struct {
	moduleBase
	simpleOutputProducer
	Properties struct {
		Features
		Build
		Defaults []string
		VersionScriptModule *string `blueprint:"mutated"`
	}
}
var _ defaultable = (*library)(nil)
var _ featurable = (*library)(nil)
var _ targetSpecificLibrary = (*library)(nil)
var _ installable = (*library)(nil)
var _ enableable = (*library)(nil)
var _ propertyExporter = (*library)(nil)
var _ matchSourceInterface = (*library)(nil)
var _ propertyEscapeInterface = (*library)(nil)
var _ splittable = (*library)(nil)
var _ aliasable = (*library)(nil)
func (l *library) defaults() []string {
	return l.Properties.Defaults
}
func (l *library) defaultableProperties() []interface{} {
	return []interface{}{
		&l.Properties.Build.CommonProps,
		&l.Properties.Build.BuildProps,
		&l.Properties.Build.SplittableProps,
	}
}
func (l *library) build() *Build {
	return &l.Properties.Build
}
func (l *library) featurableProperties() []interface{} {
	return []interface{}{
		&l.Properties.Build.CommonProps,
		&l.Properties.Build.BuildProps,
		&l.Properties.Build.SplittableProps,
	}
}
func (l *library) targetableProperties() []interface{} {
	return []interface{}{
		&l.Properties.Build.CommonProps,
		&l.Properties.Build.BuildProps,
		&l.Properties.Build.SplittableProps,
	}
}
func (l *library) features() *Features {
	return &l.Properties.Features
}
func (l *library) getTarget() tgtType {
	return l.Properties.TargetType
}
func (l *library) getInstallableProps() *InstallableProps {
	return &l.Properties.InstallableProps
}
func (l *library) getInstallDepPhonyNames(ctx blueprint.ModuleContext) []string {
	return getShortNamesForDirectDepsIf(ctx,
		func(m blueprint.Module) bool {
			tag := ctx.OtherModuleDependencyTag(m)
			if _, ok := m.(*externalLib); ok {
				return false
			}
			if tag == installDepTag || tag == sharedDepTag {
				return true
			}
			return false
		})
}
func (l *library) getEnableableProps() *EnableableProps {
	return &l.Properties.Build.EnableableProps
}
func (l *library) getAliasList() []string {
	return l.Properties.getAliasList()
}
func (l *library) supportedVariants() (tgts []tgtType) {
	if l.Properties.isHostSupported() {
		tgts = append(tgts, tgtTypeHost)
	}
	if l.Properties.isTargetSupported() {
		tgts = append(tgts, tgtTypeTarget)
	}
	return
}
func (l *library) disable() {
	f := false
	l.Properties.Enabled = &f
}
func (l *library) setVariant(tgt tgtType) {
	l.Properties.TargetType = tgt
}
func (l *library) getSplittableProps() *SplittableProps {
	return &l.Properties.SplittableProps
}
func (l *library) getTargetSpecific(tgt tgtType) *TargetSpecific {
	return l.Properties.getTargetSpecific(tgt)
}
func (l *library) outputName() string {
	if l.Properties.Out != nil {
		return *l.Properties.Out
	}
	return l.Name()
}
func (l *library) getDebugInfo() *string {
	return l.Properties.getDebugInfo()
}
func (l *library) getDebugPath() *string {
	return l.Properties.getDebugPath()
}
func (l *library) setDebugPath(path *string) {
	l.Properties.setDebugPath(path)
}
func (m *library) stripOutputDir(g generatorBackend) string {
	return getBackendPathInBuildDir(g, string(m.Properties.TargetType), "strip")
}
func (l *library) altName() string {
	return l.outputName()
}
func (l *library) altShortName() string {
	if len(l.supportedVariants()) > 1 {
		return l.altName() + "__" + string(l.Properties.TargetType)
	}
	return l.altName()
}
func (l *library) getEscapeProperties() []*[]string {
	return []*[]string{
		&l.Properties.Asflags,
		&l.Properties.Cflags,
		&l.Properties.Conlyflags,
		&l.Properties.Cxxflags,
		&l.Properties.Ldflags}
}
func (l *library) getSourceProperties() *SourceProps {
	return &l.Properties.SourceProps
}
func (l *library) getMatchSourcePropNames() []string {
	return []string{"Ldflags", "Cflags", "Conlyflags", "Cxxflags"}
}
func (l *library) shortName() string {
	if len(l.supportedVariants()) > 1 {
		return l.Name() + "__" + string(l.Properties.TargetType)
	}
	return l.Name()
}
func (l *library) GetGeneratedHeaders(ctx blueprint.ModuleContext) (includeDirs []string, orderOnly []string) {
	visited := map[string]bool{}
	mainModule := ctx.Module()
	ctx.WalkDeps(func(child, parent blueprint.Module) bool {
		tag := ctx.OtherModuleDependencyTag(child)
		importHeaderDirs := false
		visitChildren := false
		childMustBeGenerated := true
		if parent == mainModule {
			if tag == generatedHeaderTag || tag == exportGeneratedHeaderTag {
				importHeaderDirs = true
				visitChildren = false
			} else if tag == staticDepTag || tag == sharedDepTag || tag == reexportLibsTag {
				importHeaderDirs = true
				visitChildren = true
				childMustBeGenerated = false
			}
		} else {
			if tag == exportGeneratedHeaderTag {
				importHeaderDirs = true
				visitChildren = false
			}
		}
		if importHeaderDirs {
			if gs, ok := getGenerateCommon(child); ok {
				if _, seen := visited[child.Name()]; !seen {
					visited[child.Name()] = true
					includeDirs = append(includeDirs, gs.genIncludeDirs()...)
					ds, ok := child.(dependentInterface)
					if !ok {
						panic(fmt.Errorf("generated_headers %s must have outputs()", child.Name()))
					}
					orderOnly = append(orderOnly, getHeadersGenerated(ds)...)
				}
			} else if childMustBeGenerated {
				panic(fmt.Errorf("%s dependency on non-generated module %s", tag.(dependencyTag).name, child.Name()))
			}
		}
		return visitChildren
	})
	return
}
func (l *library) getAllGeneratedSourceModules(ctx blueprint.ModuleContext) (modules []string) {
	ctx.VisitDirectDepsIf(
		func(m blueprint.Module) bool { return ctx.OtherModuleDependencyTag(m) == generatedSourceTag },
		func(m blueprint.Module) {
			if gs, ok := getGenerateCommon(m); ok {
				modules = append(modules, gs.Name())
			}
		})
	return
}
func (l *library) GetExportedVariables(ctx blueprint.ModuleContext) (expLocalIncludes, expIncludes, expCflags []string) {
	visited := map[string]bool{}
	ctx.VisitDirectDeps(func(dep blueprint.Module) {
		if !(ctx.OtherModuleDependencyTag(dep) == wholeStaticDepTag ||
			ctx.OtherModuleDependencyTag(dep) == staticDepTag ||
			ctx.OtherModuleDependencyTag(dep) == sharedDepTag ||
			ctx.OtherModuleDependencyTag(dep) == reexportLibsTag) {
			return
		} else if _, ok := visited[dep.Name()]; ok {
			return
		}
		visited[dep.Name()] = true
		if pe, ok := dep.(propertyExporter); ok {
			expLocalIncludes = append(expLocalIncludes, pe.exportLocalIncludeDirs()...)
			expIncludes = append(expIncludes, pe.exportIncludeDirs()...)
			expCflags = append(expCflags, pe.exportCflags()...)
		}
	})
	return
}
func (l *library) getVersionScript(ctx blueprint.ModuleContext) *string {
	if l.Properties.VersionScriptModule != nil {
		module, _ := ctx.GetDirectDep(*l.Properties.VersionScriptModule)
		outputs := module.(dependentInterface).outputs()
		if len(outputs) != 1 {
			panic(errors.New(ctx.OtherModuleName(module) + " must have exactly one output"))
		}
		return &outputs[0]
	}
	if l.Properties.Build.Version_script != nil {
		path := getBackendPathInSourceDir(getBackend(ctx), *l.Properties.Build.Version_script)
		return &path
	}
	return nil
}
func (l *library) processPaths(ctx blueprint.BaseModuleContext, g generatorBackend) {
	l.Properties.Build.processPaths(ctx, g)
	versionScript := l.Properties.Build.Version_script
	if versionScript != nil {
		matches := depOutputsVarRegexp.FindStringSubmatch(*versionScript)
		if len(matches) == 2 {
			l.Properties.VersionScriptModule = &matches[1]
		} else {
			*versionScript = filepath.Join(projectModuleDir(ctx), *versionScript)
		}
	}
}
func (m *library) filesToInstall(ctx blueprint.BaseModuleContext) []string {
	return m.outputs()
}
func (l *library) checkField(cond bool, fieldName string) {
	if !cond {
		panic(fmt.Sprintf("%s has field %s set", l.Name(), fieldName))
	}
}
func (l *library) exportCflags() []string           { return l.Properties.Export_cflags }
func (l *library) exportIncludeDirs() []string      { return l.Properties.Export_include_dirs }
func (l *library) exportLocalIncludeDirs() []string { return l.Properties.Export_local_include_dirs }
func (l *library) exportLdflags() []string          { return l.Properties.Export_ldflags }
func (l *library) exportLdlibs() []string           { return l.Properties.Ldlibs }
func (l *library) exportSharedLibs() []string       { return l.Properties.Shared_libs }
type staticLibrary struct {
	library
}
func (m *staticLibrary) GenerateBuildActions(ctx blueprint.ModuleContext) {
	if isEnabled(m) {
		getBackend(ctx).staticActions(m, ctx)
	}
}
func (m *staticLibrary) outputFileName() string {
	return m.outputName() + ".a"
}
type sharedLibrary struct {
	library
	fileNameExtension string
}
var _ linkableModule = (*sharedLibrary)(nil)
var _ sharedLibProducer = (*sharedLibrary)(nil)
var _ stripable = (*sharedLibrary)(nil)
func (m *sharedLibrary) getLinkName() string {
	return m.outputName() + m.fileNameExtension
}
func (m *sharedLibrary) getSoname() string {
	name := m.getLinkName()
	if m.library.Properties.Library_version != "" {
		var v = strings.Split(m.library.Properties.Library_version, ".")
		name += "." + v[0]
	}
	return name
}
func (m *sharedLibrary) getRealName() string {
	name := m.getLinkName()
	if m.library.Properties.Library_version != "" {
		name += "." + m.library.Properties.Library_version
	}
	return name
}
func (l *sharedLibrary) strip() bool {
	return l.Properties.Strip != nil && *l.Properties.Strip
}
func (m *sharedLibrary) librarySymlinks(ctx blueprint.ModuleContext) map[string]string {
	symlinks := map[string]string{}
	if m.library.Properties.Library_version != "" {
		soname := m.getSoname()
		realName := m.getRealName()
		if soname == realName {
			panic(fmt.Errorf("module %s has invalid library_version '%s'",
				m.Name(),
				m.library.Properties.Library_version))
		}
		symlinks[m.getLinkName()] = soname
		symlinks[soname] = realName
	}
	return symlinks
}
func (m *sharedLibrary) GenerateBuildActions(ctx blueprint.ModuleContext) {
	if isEnabled(m) {
		getBackend(ctx).sharedActions(m, ctx)
	}
}
func (m *sharedLibrary) outputFileName() string {
	return m.getLinkName()
}
func (m *sharedLibrary) getTocName() string {
	return m.getRealName() + tocExt
}
type binary struct {
	library
}
var _ linkableModule = (*binary)(nil)
var _ stripable = (*binary)(nil)
func (l *binary) strip() bool {
	return l.Properties.Strip != nil && *l.Properties.Strip
}
func (m *binary) GenerateBuildActions(ctx blueprint.ModuleContext) {
	if isEnabled(m) {
		getBackend(ctx).binaryActions(m, ctx)
	}
}
func (m *binary) outputFileName() string {
	return m.outputName()
}
func (l *library) LibraryFactory(config *bobConfig, module blueprint.Module) (blueprint.Module, []interface{}) {
	l.Properties.Features.Init(&config.Properties, CommonProps{}, BuildProps{}, SplittableProps{})
	l.Properties.Host.init(&config.Properties, CommonProps{}, BuildProps{})
	l.Properties.Target.init(&config.Properties, CommonProps{}, BuildProps{})
	return module, []interface{}{&l.Properties, &l.SimpleName.Properties}
}
func staticLibraryFactory(config *bobConfig) (blueprint.Module, []interface{}) {
	module := &staticLibrary{}
	return module.LibraryFactory(config, module)
}
func sharedLibraryFactory(config *bobConfig) (blueprint.Module, []interface{}) {
	module := &sharedLibrary{}
	if config.Properties.GetBool("osx") {
		module.fileNameExtension = ".dylib"
	} else {
		module.fileNameExtension = ".so"
	}
	return module.LibraryFactory(config, module)
}
func binaryFactory(config *bobConfig) (blueprint.Module, []interface{}) {
	module := &binary{}
	return module.LibraryFactory(config, module)
}
func getBinaryOrSharedLib(m blueprint.Module) (*library, bool) {
	if sl, ok := m.(*sharedLibrary); ok {
		return &sl.library, true
	} else if b, ok := m.(*binary); ok {
		return &b.library, true
	}
	return nil, false
}
func getLibrary(m blueprint.Module) (*library, bool) {
	if bsl, ok := getBinaryOrSharedLib(m); ok {
		return bsl, true
	} else if sl, ok := m.(*staticLibrary); ok {
		return &sl.library, true
	}
	return nil, false
}
func checkLibraryFieldsMutator(mctx blueprint.BottomUpMutatorContext) {
	m := mctx.Module()
	if b, ok := m.(*binary); ok {
		props := b.Properties
		b.checkField(len(props.Export_cflags) == 0, "export_cflags")
		b.checkField(len(props.Export_include_dirs) == 0, "export_include_dirs")
		b.checkField(len(props.Export_ldflags) == 0, "export_ldflags")
		b.checkField(len(props.Export_local_include_dirs) == 0, "export_local_include_dirs")
		b.checkField(len(props.Reexport_libs) == 0, "reexport_libs")
		b.checkField(props.Forwarding_shlib == nil, "forwarding_shlib")
	} else if sl, ok := m.(*sharedLibrary); ok {
		props := sl.Properties
		sl.checkField(len(props.Export_ldflags) == 0, "export_ldflags")
		sl.checkField(props.Mte.Memtag_heap == nil, "memtag_heap")
		sl.checkField(props.Mte.Diag_memtag_heap == nil, "memtag_heap")
	} else if sl, ok := m.(*staticLibrary); ok {
		props := sl.Properties
		sl.checkField(props.Forwarding_shlib == nil, "forwarding_shlib")
		sl.checkField(props.Version_script == nil, "version_script")
		sl.checkField(props.Mte.Memtag_heap == nil, "memtag_heap")
		sl.checkField(props.Mte.Diag_memtag_heap == nil, "memtag_heap")
	}
}