Merge "Export Soong install rules to Make" am: 1caea35278 am: 7f5f69f9ba am: 5e5d6332b4

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1869552

Change-Id: Ifc2d7a00569bdb8dcef9853f27e07824cef3d59d
This commit is contained in:
Colin Cross
2021-11-01 22:23:07 +00:00
committed by Automerger Merge Worker
4 changed files with 220 additions and 43 deletions

View File

@@ -516,6 +516,16 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
// If the install rule was generated by Soong tell Make about it.
if amod.InstallBypassMake() && len(base.katiInstalls) > 0 {
// Assume the primary install file is last since it probably needs to depend on any other
// installed files. If that is not the case we can add a method to specify the primary
// installed file.
a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", base.katiInstalls[len(base.katiInstalls)-1].to)
a.SetString("LOCAL_SOONG_INSTALL_PAIRS", base.katiInstalls.BuiltInstalled())
a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths())
}
if am, ok := mod.(ApexModule); ok {
a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
}

View File

@@ -17,6 +17,8 @@ package android
import (
"bytes"
"fmt"
"path/filepath"
"runtime"
"sort"
"strings"
@@ -222,6 +224,9 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
lateOutFile := absolutePath(PathForOutput(ctx,
"late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
installsFile := absolutePath(PathForOutput(ctx,
"installs"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
if ctx.Failed() {
return
}
@@ -229,6 +234,8 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
var vars []makeVarsVariable
var dists []dist
var phonies []phony
var katiInstalls []katiInstall
var katiSymlinks []katiInstall
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
providers = append(providers, *ctx.Config().Get(singletonMakeVarsProvidersKey).(*[]makeVarsProvider)...)
@@ -258,6 +265,11 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
phonies = append(phonies, mctx.phonies...)
dists = append(dists, mctx.dists...)
}
if m.ExportedToMake() {
katiInstalls = append(katiInstalls, m.base().katiInstalls...)
katiSymlinks = append(katiSymlinks, m.base().katiSymlinks...)
}
})
if ctx.Failed() {
@@ -297,6 +309,10 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
ctx.Errorf(err.Error())
}
installsBytes := s.writeInstalls(katiInstalls, katiSymlinks)
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
ctx.Errorf(err.Error())
}
}
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
@@ -405,6 +421,84 @@ func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte {
return buf.Bytes()
}
// writeInstalls writes the list of install rules generated by Soong to a makefile. The rules
// are exported to Make instead of written directly to the ninja file so that main.mk can add
// the dependencies from the `required` property that are hard to resolve in Soong.
func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []byte {
buf := &bytes.Buffer{}
fmt.Fprint(buf, `# Autogenerated file
# Values written by Soong to generate install rules that can be amended by Kati.
`)
preserveSymlinksFlag := "-d"
if runtime.GOOS == "darwin" {
preserveSymlinksFlag = "-R"
}
for _, install := range installs {
// Write a rule for each install request in the form:
// to: from [ deps ] [ | order only deps ]
// cp -f -d $< $@ [ && chmod +x $@ ]
fmt.Fprintf(buf, "%s: %s", install.to.String(), install.from.String())
for _, dep := range install.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
if len(install.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
for _, dep := range install.orderOnlyDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
fmt.Fprintln(buf)
fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@", preserveSymlinksFlag)
if install.executable {
fmt.Fprintf(buf, " && chmod +x $@")
}
fmt.Fprintln(buf)
fmt.Fprintln(buf)
}
for _, symlink := range symlinks {
fmt.Fprintf(buf, "%s:", symlink.to.String())
for _, dep := range symlink.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
if symlink.from != nil || len(symlink.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
if symlink.from != nil {
fmt.Fprintf(buf, " %s", symlink.from.String())
}
for _, dep := range symlink.orderOnlyDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
fmt.Fprintln(buf)
fromStr := ""
if symlink.from != nil {
rel, err := filepath.Rel(filepath.Dir(symlink.to.String()), symlink.from.String())
if err != nil {
panic(fmt.Errorf("failed to find relative path for symlink from %q to %q: %w",
symlink.from.String(), symlink.to.String(), err))
}
fromStr = rel
} else {
fromStr = symlink.absFrom
}
fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
fmt.Fprintln(buf)
fmt.Fprintln(buf)
}
return buf.Bytes()
}
func (c *makeVarsContext) DeviceConfig() DeviceConfig {
return DeviceConfig{c.Config().deviceConfig}
}

View File

@@ -1194,7 +1194,10 @@ type ModuleBase struct {
packagingSpecs []PackagingSpec
packagingSpecsDepSet *packagingSpecsDepSet
noticeFiles Paths
phonies map[string]Paths
// katiInstalls tracks the install rules that were created by Soong but are being exported
// to Make to convert to ninja rules so that Make can add additional dependencies.
katiInstalls katiInstalls
katiSymlinks katiInstalls
// The files to copy to the dist as explicitly specified in the .bp file.
distFiles TaggedDistFiles
@@ -2016,9 +2019,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
m.tidyFiles = append(m.tidyFiles, ctx.tidyFiles...)
m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
for k, v := range ctx.phonies {
m.phonies[k] = append(m.phonies[k], v...)
}
m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...)
m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...)
} else if ctx.Config().AllowMissingDependencies() {
// 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
@@ -2217,12 +2219,52 @@ type moduleContext struct {
module Module
phonies map[string]Paths
katiInstalls []katiInstall
katiSymlinks []katiInstall
// For tests
buildParams []BuildParams
ruleParams map[blueprint.Rule]blueprint.RuleParams
variables map[string]string
}
// katiInstall stores a request from Soong to Make to create an install rule.
type katiInstall struct {
from Path
to InstallPath
implicitDeps Paths
orderOnlyDeps Paths
executable bool
absFrom string
}
type katiInstalls []katiInstall
// BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
// space separated list of from:to tuples.
func (installs katiInstalls) BuiltInstalled() string {
sb := strings.Builder{}
for i, install := range installs {
if i != 0 {
sb.WriteRune(' ')
}
sb.WriteString(install.from.String())
sb.WriteRune(':')
sb.WriteString(install.to.String())
}
return sb.String()
}
// InstallPaths returns the install path of each entry.
func (installs katiInstalls) InstallPaths() InstallPaths {
paths := make(InstallPaths, 0, len(installs))
for _, install := range installs {
paths = append(paths, install.to)
}
return paths
}
func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
return pctx, BuildParams{
Rule: ErrorRule,
@@ -2854,20 +2896,33 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat
orderOnlyDeps = deps
}
rule := Cp
if executable {
rule = CpExecutable
}
if m.Config().KatiEnabled() && m.InstallBypassMake() {
// When creating the install rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
m.katiInstalls = append(m.katiInstalls, katiInstall{
from: srcPath,
to: fullInstallPath,
implicitDeps: implicitDeps,
orderOnlyDeps: orderOnlyDeps,
executable: executable,
})
} else {
rule := Cp
if executable {
rule = CpExecutable
}
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
Default: !m.Config().KatiEnabled(),
})
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
Default: !m.Config().KatiEnabled(),
})
}
m.installFiles = append(m.installFiles, fullInstallPath)
}
@@ -2889,16 +2944,26 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src
}
if !m.skipInstall() {
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": relPath,
},
})
if m.Config().KatiEnabled() && m.InstallBypassMake() {
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
m.katiSymlinks = append(m.katiSymlinks, katiInstall{
from: srcPath,
to: fullInstallPath,
})
} else {
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
Output: fullInstallPath,
Input: srcPath,
Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": relPath,
},
})
}
m.installFiles = append(m.installFiles, fullInstallPath)
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
@@ -2921,15 +2986,25 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str
m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
if !m.skipInstall() {
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
Output: fullInstallPath,
Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": absPath,
},
})
if m.Config().KatiEnabled() && m.InstallBypassMake() {
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
m.katiSymlinks = append(m.katiSymlinks, katiInstall{
absFrom: absPath,
to: fullInstallPath,
})
} else {
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
Output: fullInstallPath,
Default: !m.Config().KatiEnabled(),
Args: map[string]string{
"fromPath": absPath,
},
})
}
m.installFiles = append(m.installFiles, fullInstallPath)
}

View File

@@ -212,13 +212,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext)
installDeps = append(installDeps, installedData)
}
installed := ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
if r.ExportedToMake() {
// Soong handles installation here, but Make is usually what creates the phony rule that atest
// uses to build the module. Create it here for now.
ctx.Phony(ctx.ModuleName(), installed)
}
r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
}
func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -282,6 +276,10 @@ func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFi
func (r *robolectricTest) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := r.Library.AndroidMkEntries()
entries := &entriesList[0]
entries.ExtraEntries = append(entries.ExtraEntries,
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
})
entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string) {