Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3d87d31 authored by Colin Cross's avatar Colin Cross
Browse files

Define Soong phony rules in Make

To support dist-for-goals in Soong, we need to define all phony rules
in Make so that dist-for-goals can insert additional dependencies on
them.  Collect all the phony rules in phonySingleton and write them
out as Make rules when Soong is embedded in Make, or as blueprint.Phony
rules when Soong is run standalone.

Test: m checkbuild
Change-Id: I68201eff30744b0f487fc4f11f033767b53a627d
parent 2fce23ae
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ bootstrap_go_package {
        "package_ctx.go",
        "package_ctx.go",
        "path_properties.go",
        "path_properties.go",
        "paths.go",
        "paths.go",
        "phony.go",
        "prebuilt.go",
        "prebuilt.go",
        "proto.go",
        "proto.go",
        "register.go",
        "register.go",
+54 −12
Original line number Original line Diff line number Diff line
@@ -17,12 +17,11 @@ package android
import (
import (
	"bytes"
	"bytes"
	"fmt"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strconv"
	"strings"
	"strings"


	"github.com/google/blueprint"
	"github.com/google/blueprint"
	"github.com/google/blueprint/pathtools"
	"github.com/google/blueprint/proptools"
	"github.com/google/blueprint/proptools"
)
)


@@ -84,6 +83,11 @@ type MakeVarsContext interface {
	// builder whenever a file matching the pattern as added or removed, without rerunning if a
	// builder whenever a file matching the pattern as added or removed, without rerunning if a
	// file that does not match the pattern is added to a searched directory.
	// file that does not match the pattern is added to a searched directory.
	GlobWithDeps(pattern string, excludes []string) ([]string, error)
	GlobWithDeps(pattern string, excludes []string) ([]string, error)

	// Phony creates a phony rule in Make, which will allow additional DistForGoal
	// dependencies to be added to it.  Phony can be called on the same name multiple
	// times to add additional dependencies.
	Phony(names string, deps ...Path)
}
}


var _ PathContext = MakeVarsContext(nil)
var _ PathContext = MakeVarsContext(nil)
@@ -133,6 +137,7 @@ type makeVarsContext struct {
	config  Config
	config  Config
	pctx    PackageContext
	pctx    PackageContext
	vars    []makeVarsVariable
	vars    []makeVarsVariable
	phonies []phony
}
}


var _ MakeVarsContext = &makeVarsContext{}
var _ MakeVarsContext = &makeVarsContext{}
@@ -144,6 +149,11 @@ type makeVarsVariable struct {
	strict bool
	strict bool
}
}


type phony struct {
	name string
	deps []string
}

func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
	if !ctx.Config().EmbeddedInMake() {
	if !ctx.Config().EmbeddedInMake() {
		return
		return
@@ -152,11 +162,15 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
	outFile := absolutePath(PathForOutput(ctx,
	outFile := absolutePath(PathForOutput(ctx,
		"make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
		"make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())


	lateOutFile := absolutePath(PathForOutput(ctx,
		"late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())

	if ctx.Failed() {
	if ctx.Failed() {
		return
		return
	}
	}


	vars := []makeVarsVariable{}
	vars := []makeVarsVariable{}
	var phonies []phony
	for _, provider := range makeVarsProviders {
	for _, provider := range makeVarsProviders {
		mctx := &makeVarsContext{
		mctx := &makeVarsContext{
			SingletonContext: ctx,
			SingletonContext: ctx,
@@ -166,6 +180,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
		provider.call(mctx)
		provider.call(mctx)


		vars = append(vars, mctx.vars...)
		vars = append(vars, mctx.vars...)
		phonies = append(phonies, mctx.phonies...)
	}
	}


	if ctx.Failed() {
	if ctx.Failed() {
@@ -174,17 +189,16 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {


	outBytes := s.writeVars(vars)
	outBytes := s.writeVars(vars)


	if _, err := os.Stat(absolutePath(outFile)); err == nil {
	if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
		if data, err := ioutil.ReadFile(absolutePath(outFile)); err == nil {
		ctx.Errorf(err.Error())
			if bytes.Equal(data, outBytes) {
				return
			}
		}
	}
	}


	if err := ioutil.WriteFile(absolutePath(outFile), outBytes, 0666); err != nil {
	lateOutBytes := s.writeLate(phonies)

	if err := pathtools.WriteFileIfChanged(lateOutFile, lateOutBytes, 0666); err != nil {
		ctx.Errorf(err.Error())
		ctx.Errorf(err.Error())
	}
	}

}
}


func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
@@ -263,6 +277,26 @@ my_check_failed :=


	fmt.Fprintln(buf, "\nsoong-compare-var :=")
	fmt.Fprintln(buf, "\nsoong-compare-var :=")


	fmt.Fprintln(buf)

	return buf.Bytes()
}

func (s *makeVarsSingleton) writeLate(phonies []phony) []byte {
	buf := &bytes.Buffer{}

	fmt.Fprint(buf, `# Autogenerated file

# Values written by Soong read after parsing all Android.mk files.


`)

	for _, phony := range phonies {
		fmt.Fprintf(buf, ".PHONY: %s\n", phony.name)
		fmt.Fprintf(buf, "%s: %s\n", phony.name, strings.Join(phony.deps, "\\\n  "))
	}

	return buf.Bytes()
	return buf.Bytes()
}
}


@@ -299,6 +333,10 @@ func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool)
	c.addVariableRaw(name, value, strict, sort)
	c.addVariableRaw(name, value, strict, sort)
}
}


func (c *makeVarsContext) addPhony(name string, deps []string) {
	c.phonies = append(c.phonies, phony{name, deps})
}

func (c *makeVarsContext) Strict(name, ninjaStr string) {
func (c *makeVarsContext) Strict(name, ninjaStr string) {
	c.addVariable(name, ninjaStr, true, false)
	c.addVariable(name, ninjaStr, true, false)
}
}
@@ -318,3 +356,7 @@ func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
func (c *makeVarsContext) CheckRaw(name, value string) {
func (c *makeVarsContext) CheckRaw(name, value string) {
	c.addVariableRaw(name, value, false, false)
	c.addVariableRaw(name, value, false, false)
}
}

func (c *makeVarsContext) Phony(name string, deps ...Path) {
	c.addPhony(name, Paths(deps).Strings())
}
+32 −52
Original line number Original line Diff line number Diff line
@@ -207,6 +207,10 @@ type ModuleContext interface {
	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
	// and performs more verification.
	// and performs more verification.
	Build(pctx PackageContext, params BuildParams)
	Build(pctx PackageContext, params BuildParams)
	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
	// phony rules or real files.  Phony can be called on the same name multiple times to add
	// additional dependencies.
	Phony(phony string, deps ...Path)


	PrimaryModule() Module
	PrimaryModule() Module
	FinalModule() Module
	FinalModule() Module
@@ -722,6 +726,7 @@ type ModuleBase struct {
	installFiles       InstallPaths
	installFiles       InstallPaths
	checkbuildFiles    Paths
	checkbuildFiles    Paths
	noticeFiles        Paths
	noticeFiles        Paths
	phonies            map[string]Paths


	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
	// Only set on the final variant of each module
	// Only set on the final variant of each module
@@ -1093,26 +1098,17 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
	}
	}


	if len(allInstalledFiles) > 0 {
	if len(allInstalledFiles) > 0 {
		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-install")
		name := namespacePrefix + ctx.ModuleName() + "-install"
		ctx.Build(pctx, BuildParams{
		ctx.Phony(name, allInstalledFiles.Paths()...)
			Rule:      blueprint.Phony,
		m.installTarget = PathForPhony(ctx, name)
			Output:    name,
		deps = append(deps, m.installTarget)
			Implicits: allInstalledFiles.Paths(),
			Default:   !ctx.Config().EmbeddedInMake(),
		})
		deps = append(deps, name)
		m.installTarget = name
	}
	}


	if len(allCheckbuildFiles) > 0 {
	if len(allCheckbuildFiles) > 0 {
		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-checkbuild")
		name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
		ctx.Build(pctx, BuildParams{
		ctx.Phony(name, allCheckbuildFiles...)
			Rule:      blueprint.Phony,
		m.checkbuildTarget = PathForPhony(ctx, name)
			Output:    name,
		deps = append(deps, m.checkbuildTarget)
			Implicits: allCheckbuildFiles,
		})
		deps = append(deps, name)
		m.checkbuildTarget = name
	}
	}


	if len(deps) > 0 {
	if len(deps) > 0 {
@@ -1121,12 +1117,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
			suffix = "-soong"
			suffix = "-soong"
		}
		}


		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+suffix)
		ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...)
		ctx.Build(pctx, BuildParams{
			Rule:      blueprint.Phony,
			Outputs:   []WritablePath{name},
			Implicits: deps,
		})


		m.blueprintDir = ctx.ModuleDir()
		m.blueprintDir = ctx.ModuleDir()
	}
	}
@@ -1313,6 +1304,9 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
		for k, v := range ctx.phonies {
			m.phonies[k] = append(m.phonies[k], v...)
		}
	} else if ctx.Config().AllowMissingDependencies() {
	} else if ctx.Config().AllowMissingDependencies() {
		// If the module is not enabled it will not create any build rules, nothing will call
		// If the module is not enabled it will not create any build rules, nothing will call
		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1460,6 +1454,7 @@ type moduleContext struct {
	installFiles    InstallPaths
	installFiles    InstallPaths
	checkbuildFiles Paths
	checkbuildFiles Paths
	module          Module
	module          Module
	phonies         map[string]Paths


	// For tests
	// For tests
	buildParams []BuildParams
	buildParams []BuildParams
@@ -1574,6 +1569,11 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {


	m.bp.Build(pctx.PackageContext, convertBuildParams(params))
	m.bp.Build(pctx.PackageContext, convertBuildParams(params))
}
}

func (m *moduleContext) Phony(name string, deps ...Path) {
	addPhony(m.config, name, deps...)
}

func (m *moduleContext) GetMissingDependencies() []string {
func (m *moduleContext) GetMissingDependencies() []string {
	var missingDeps []string
	var missingDeps []string
	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
@@ -2233,9 +2233,8 @@ type buildTargetSingleton struct{}
func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
	var checkbuildDeps Paths
	var checkbuildDeps Paths


	mmTarget := func(dir string) WritablePath {
	mmTarget := func(dir string) string {
		return PathForPhony(ctx,
		return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
			"MODULES-IN-"+strings.Replace(filepath.Clean(dir), "/", "-", -1))
	}
	}


	modulesInDir := make(map[string]Paths)
	modulesInDir := make(map[string]Paths)
@@ -2261,11 +2260,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
	}
	}


	// Create a top-level checkbuild target that depends on all modules
	// Create a top-level checkbuild target that depends on all modules
	ctx.Build(pctx, BuildParams{
	ctx.Phony("checkbuild"+suffix, checkbuildDeps...)
		Rule:      blueprint.Phony,
		Output:    PathForPhony(ctx, "checkbuild"+suffix),
		Implicits: checkbuildDeps,
	})


	// Make will generate the MODULES-IN-* targets
	// Make will generate the MODULES-IN-* targets
	if ctx.Config().EmbeddedInMake() {
	if ctx.Config().EmbeddedInMake() {
@@ -2289,7 +2284,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
	for _, dir := range dirs {
	for _, dir := range dirs {
		p := parentDir(dir)
		p := parentDir(dir)
		if p != "." && p != "/" {
		if p != "." && p != "/" {
			modulesInDir[p] = append(modulesInDir[p], mmTarget(dir))
			modulesInDir[p] = append(modulesInDir[p], PathForPhony(ctx, mmTarget(dir)))
		}
		}
	}
	}


@@ -2297,14 +2292,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
	// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
	// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
	// files.
	// files.
	for _, dir := range dirs {
	for _, dir := range dirs {
		ctx.Build(pctx, BuildParams{
		ctx.Phony(mmTarget(dir), modulesInDir[dir]...)
			Rule:      blueprint.Phony,
			Output:    mmTarget(dir),
			Implicits: modulesInDir[dir],
			// HACK: checkbuild should be an optional build, but force it
			// enabled for now in standalone builds
			Default: !ctx.Config().EmbeddedInMake(),
		})
	}
	}


	// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild.
	// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild.
@@ -2331,23 +2319,15 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
			continue
			continue
		}
		}


		name := PathForPhony(ctx, className+"-"+os.Name)
		name := className + "-" + os.Name
		osClass[className] = append(osClass[className], name)
		osClass[className] = append(osClass[className], PathForPhony(ctx, name))


		ctx.Build(pctx, BuildParams{
		ctx.Phony(name, deps...)
			Rule:      blueprint.Phony,
			Output:    name,
			Implicits: deps,
		})
	}
	}


	// Wrap those into host|host-cross|target phony rules
	// Wrap those into host|host-cross|target phony rules
	for _, class := range SortedStringKeys(osClass) {
	for _, class := range SortedStringKeys(osClass) {
		ctx.Build(pctx, BuildParams{
		ctx.Phony(class, osClass[class]...)
			Rule:      blueprint.Phony,
			Output:    PathForPhony(ctx, class),
			Implicits: osClass[class],
		})
	}
	}
}
}


android/phony.go

0 → 100644
+75 −0
Original line number Original line Diff line number Diff line
// Copyright 2020 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package android

import (
	"sync"

	"github.com/google/blueprint"
)

var phonyMapOnceKey = NewOnceKey("phony")

type phonyMap map[string]Paths

var phonyMapLock sync.Mutex

func getPhonyMap(config Config) phonyMap {
	return config.Once(phonyMapOnceKey, func() interface{} {
		return make(phonyMap)
	}).(phonyMap)
}

func addPhony(config Config, name string, deps ...Path) {
	phonyMap := getPhonyMap(config)
	phonyMapLock.Lock()
	defer phonyMapLock.Unlock()
	phonyMap[name] = append(phonyMap[name], deps...)
}

type phonySingleton struct {
	phonyMap  phonyMap
	phonyList []string
}

var _ SingletonMakeVarsProvider = (*phonySingleton)(nil)

func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
	p.phonyMap = getPhonyMap(ctx.Config())
	p.phonyList = SortedStringKeys(p.phonyMap)
	for _, phony := range p.phonyList {
		p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony])
	}

	if !ctx.Config().EmbeddedInMake() {
		for _, phony := range p.phonyList {
			ctx.Build(pctx, BuildParams{
				Rule:      blueprint.Phony,
				Outputs:   []WritablePath{PathForPhony(ctx, phony)},
				Implicits: p.phonyMap[phony],
			})
		}
	}
}

func (p phonySingleton) MakeVars(ctx MakeVarsContext) {
	for _, phony := range p.phonyList {
		ctx.Phony(phony, p.phonyMap[phony]...)
	}
}

func phonySingletonFactory() Singleton {
	return &phonySingleton{}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -104,6 +104,9 @@ func (ctx *Context) Register() {


	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)


	// Register phony just before makevars so it can write out its phony rules as Make rules
	ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(phonySingletonFactory))

	// Register makevars after other singletons so they can export values through makevars
	// Register makevars after other singletons so they can export values through makevars
	ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))
	ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))


Loading