platform_build_soong/android/androidmk.go

1000 lines
34 KiB
Go
Raw Normal View History

// Copyright 2015 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.
// This file offers AndroidMkEntriesProvider, which individual modules implement to output
// Android.mk entries that contain information about the modules built through Soong. Kati reads
// and combines them with the legacy Make-based module definitions to produce the complete view of
// the source tree, which makes this a critical point of Make-Soong interoperability.
//
// Naturally, Soong-only builds do not rely on this mechanism.
package android
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/pathtools"
)
func init() {
RegisterAndroidMkBuildComponents(InitRegistrationContext)
}
func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
}
// Enable androidmk support.
// * Register the singleton
// * Configure that we are inside make
var PrepareForTestWithAndroidMk = GroupFixturePreparers(
FixtureRegisterWithContext(RegisterAndroidMkBuildComponents),
FixtureModifyConfig(SetKatiEnabledForTests),
)
// Deprecated: Use AndroidMkEntriesProvider instead, especially if you're not going to use the
// Custom function. It's easier to use and test.
type AndroidMkDataProvider interface {
AndroidMk() AndroidMkData
BaseModuleName() string
}
type AndroidMkData struct {
Class string
SubName string
DistFiles TaggedDistFiles
OutputFile OptionalPath
Disabled bool
Include string
Required []string
Host_required []string
Target_required []string
Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)
Extra []AndroidMkExtraFunc
Entries AndroidMkEntries
}
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
// Interface for modules to declare their Android.mk outputs. Note that every module needs to
// implement this in order to be included in the final Android-<product_name>.mk output, even if
// they only need to output the common set of entries without any customizations.
type AndroidMkEntriesProvider interface {
// Returns AndroidMkEntries objects that contain all basic info plus extra customization data
// if needed. This is the core func to implement.
// Note that one can return multiple objects. For example, java_library may return an additional
// AndroidMkEntries object for its hostdex sub-module.
AndroidMkEntries() []AndroidMkEntries
// Modules don't need to implement this as it's already implemented by ModuleBase.
// AndroidMkEntries uses BaseModuleName() instead of ModuleName() because certain modules
// e.g. Prebuilts, override the Name() func and return modified names.
// If a different name is preferred, use SubName or OverrideName in AndroidMkEntries.
BaseModuleName() string
}
// The core data struct that modules use to provide their Android.mk data.
type AndroidMkEntries struct {
// Android.mk class string, e.g EXECUTABLES, JAVA_LIBRARIES, ETC
Class string
// Optional suffix to append to the module name. Useful when a module wants to return multiple
// AndroidMkEntries objects. For example, when a java_library returns an additional entry for
// its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a
// different name than the parent's.
SubName string
// If set, this value overrides the base module name. SubName is still appended.
OverrideName string
// Dist files to output
DistFiles TaggedDistFiles
// The output file for Kati to process and/or install. If absent, the module is skipped.
OutputFile OptionalPath
// If true, the module is skipped and does not appear on the final Android-<product name>.mk
// file. Useful when a module needs to be skipped conditionally.
Disabled bool
// The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
// If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
Include string
// Required modules that need to be built and included in the final build output when building
// this module.
Required []string
// Required host modules that need to be built and included in the final build output when
// building this module.
Host_required []string
// Required device modules that need to be built and included in the final build output when
// building this module.
Target_required []string
header bytes.Buffer
footer bytes.Buffer
// Funcs to append additional Android.mk entries or modify the common ones. Multiple funcs are
// accepted so that common logic can be factored out as a shared func.
ExtraEntries []AndroidMkExtraEntriesFunc
// Funcs to add extra lines to the module's Android.mk output. Unlike AndroidMkExtraEntriesFunc,
// which simply sets Make variable values, this can be used for anything since it can write any
// Make statements directly to the final Android-*.mk file.
// Primarily used to call macros or declare/update Make targets.
ExtraFooters []AndroidMkExtraFootersFunc
// A map that holds the up-to-date Make variable values. Can be accessed from tests.
EntryMap map[string][]string
// A list of EntryMap keys in insertion order. This serves a few purposes:
// 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this,
// the outputted Android-*.mk file may change even though there have been no content changes.
// 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR),
// without worrying about the variables being mixed up in the actual mk file.
// 3. Makes troubleshooting and spotting errors easier.
entryOrder []string
// Provides data typically stored by Context objects that are commonly needed by
//AndroidMkEntries objects.
entryContext AndroidMkEntriesContext
}
type AndroidMkEntriesContext interface {
Config() Config
}
type AndroidMkExtraEntriesContext interface {
Provider(provider blueprint.ProviderKey) interface{}
}
type androidMkExtraEntriesContext struct {
ctx fillInEntriesContext
mod blueprint.Module
}
func (a *androidMkExtraEntriesContext) Provider(provider blueprint.ProviderKey) interface{} {
return a.ctx.ModuleProvider(a.mod, provider)
}
type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries)
type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string)
// Utility funcs to manipulate Android.mk variable entries.
// SetString sets a Make variable with the given name to the given value.
func (a *AndroidMkEntries) SetString(name, value string) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = []string{value}
}
// SetPath sets a Make variable with the given name to the given path string.
func (a *AndroidMkEntries) SetPath(name string, path Path) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = []string{path.String()}
}
// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid.
// It is a no-op if the given path is invalid.
func (a *AndroidMkEntries) SetOptionalPath(name string, path OptionalPath) {
if path.Valid() {
a.SetPath(name, path.Path())
}
}
// AddPath appends the given path string to a Make variable with the given name.
func (a *AndroidMkEntries) AddPath(name string, path Path) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = append(a.EntryMap[name], path.String())
}
// AddOptionalPath appends the given path string to a Make variable with the given name if it is
// valid. It is a no-op if the given path is invalid.
func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) {
if path.Valid() {
a.AddPath(name, path.Path())
}
}
// SetPaths sets a Make variable with the given name to a slice of the given path strings.
func (a *AndroidMkEntries) SetPaths(name string, paths Paths) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = paths.Strings()
}
// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings
// only if there are a non-zero amount of paths.
func (a *AndroidMkEntries) SetOptionalPaths(name string, paths Paths) {
if len(paths) > 0 {
a.SetPaths(name, paths)
}
}
// AddPaths appends the given path strings to a Make variable with the given name.
func (a *AndroidMkEntries) AddPaths(name string, paths Paths) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...)
}
// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true.
// It is a no-op if the given flag is false.
func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
if flag {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = []string{"true"}
}
}
// SetBool sets a Make variable with the given name to if the given bool flag value.
func (a *AndroidMkEntries) SetBool(name string, flag bool) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
if flag {
a.EntryMap[name] = []string{"true"}
} else {
a.EntryMap[name] = []string{"false"}
}
}
// AddStrings appends the given strings to a Make variable with the given name.
func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
if len(value) == 0 {
return
}
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
}
a.EntryMap[name] = append(a.EntryMap[name], value...)
}
// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
// for partial MTS test suites.
func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) {
// MTS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
// To reduce repetition, if we find a partial MTS test suite without an full MTS test suite,
// we add the full test suite to our list.
if PrefixInList(suites, "mts-") && !InList("mts", suites) {
suites = append(suites, "mts")
}
a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
}
// The contributions to the dist.
type distContributions struct {
// Path to license metadata file.
licenseMetadataFile Path
// List of goals and the dist copy instructions.
copiesForGoals []*copiesForGoals
}
// getCopiesForGoals returns a copiesForGoals into which copy instructions that
// must be processed when building one or more of those goals can be added.
func (d *distContributions) getCopiesForGoals(goals string) *copiesForGoals {
copiesForGoals := &copiesForGoals{goals: goals}
d.copiesForGoals = append(d.copiesForGoals, copiesForGoals)
return copiesForGoals
}
// Associates a list of dist copy instructions with a set of goals for which they
// should be run.
type copiesForGoals struct {
// goals are a space separated list of build targets that will trigger the
// copy instructions.
goals string
// A list of instructions to copy a module's output files to somewhere in the
// dist directory.
copies []distCopy
}
// Adds a copy instruction.
func (d *copiesForGoals) addCopyInstruction(from Path, dest string) {
d.copies = append(d.copies, distCopy{from, dest})
}
// Instruction on a path that must be copied into the dist.
type distCopy struct {
// The path to copy from.
from Path
// The destination within the dist directory to copy to.
dest string
}
// Compute the contributions that the module makes to the dist.
func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContributions {
amod := mod.(Module).base()
name := amod.BaseModuleName()
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
// Collate the set of associated tag/paths available for copying to the dist.
// Start with an empty (nil) set.
var availableTaggedDists TaggedDistFiles
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
// Then merge in any that are provided explicitly by the module.
if a.DistFiles != nil {
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
// Merge the DistFiles into the set.
availableTaggedDists = availableTaggedDists.merge(a.DistFiles)
}
// If no paths have been provided for the DefaultDistTag and the output file is
// valid then add that as the default dist path.
if _, ok := availableTaggedDists[DefaultDistTag]; !ok && a.OutputFile.Valid() {
availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path())
}
// If the distFiles created by GenerateTaggedDistFiles contains paths for the
// DefaultDistTag then that takes priority so delete any existing paths.
if _, ok := amod.distFiles[DefaultDistTag]; ok {
delete(availableTaggedDists, DefaultDistTag)
}
// Finally, merge the distFiles created by GenerateTaggedDistFiles.
availableTaggedDists = availableTaggedDists.merge(amod.distFiles)
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
if len(availableTaggedDists) == 0 {
// Nothing dist-able for this module.
return nil
}
// Collate the contributions this module makes to the dist.
distContributions := &distContributions{}
if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
distContributions.licenseMetadataFile = amod.licenseMetadataFile
}
// Iterate over this module's dist structs, merged from the dist and dists properties.
for _, dist := range amod.Dists() {
// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
goals := strings.Join(dist.Targets, " ")
// Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
var tag string
if dist.Tag == nil {
// If the dist struct does not specify a tag, use the default output files tag.
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
tag = DefaultDistTag
} else {
tag = *dist.Tag
}
// Get the paths of the output files to be dist'd, represented by the tag.
// Can be an empty list.
tagPaths := availableTaggedDists[tag]
if len(tagPaths) == 0 {
// Nothing to dist for this tag, continue to the next dist.
continue
}
if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
errorMessage := "%s: Cannot apply dest/suffix for more than one dist " +
"file for %q goals tag %q in module %s. The list of dist files, " +
"which should have a single element, is:\n%s"
Differentiate between no dist tag and an empty dist tag Change https://r.android.com/1335521 added tag property to the Dist struct so that it could be used to select one of a number of different output files to copy to the dist instead of the single file that the module type made available for dist. The output files were selected by passing the tag to OutputFiles(tag). Module types that wanted to support this new approach had to explicitly set AndroidMkEntries.DistFiles = GenerateTaggedDistFiles(module). Unfortunately, doing that had a side effect of changing the behavior of dist entries without a tag. That was because the change treated a tag that was not specified, as being the same as "". So, prior to the change no tag meant use the default dist file but after it meant use the paths returned by OutputFiles(""). That changed the behavior of the java.Library type which affected the behavior of the android_app module type. Prior to the change the java_library would make the Library.outputFile available for dist when no tag was specified. After that change it would make Library.outputFile plus Library.extraOutputFiles. The latter is usually empty except for android_app which adds some extra files into there which will now be copied to the dist. That change may have been intentional but there was no mention of it in the change or the bug. Even if it wasn't intentional it may still be beneficial. Any module type that wants to add support for tags in dist runs the risk of introducing similar changes in behavior. This change differentiates between the tag not being set and the tag being set to "" to avoid that possibility and to make the default behavior explicit for those module types that have switched. It does so as follows: * Adds a DefaultDistTag constant that is used when the tag is not set. It is a string that is unlikely to be used as an actual tag as it does not start with a . and uses some special characters. * The DefaultDistTag is used in MakeDefaultDistFiles(paths) to indicate that the supplied paths are the default ones and and also in GenerateTaggedDistFiles() for Dist structures that have no tag property set. * The DefaultDistTag is passed to OutputFiles(tag) just in case the module type has explicitly defined the paths to associate with that tag in there. If it has then it overrides the legacy behavior. If it has not then it is just ignored and falls back to using the previous behavior. * The java.Library.OutputFiles(tag) method explicitly handles the DefaultDistTag and returns Library.outputFile for it which restores the behavior from before the change that added dist.tag support. * Similar change was made to apexBundle.OutputFiles(tag) in order to preserve its previous behaviour. * The customModule used by TestGetDistContributions has been modified to also preserve its previous behavior after this change. Test: m nothing m dist sdk - before and after this change, compare result to make sure that there are no significant differences. Test the effect on the apex by following instructions in http://b/172951145 Bug: 174226317 Change-Id: Ib8f0d9307751cc2ed34e3d9a5538d3c144666f6d
2020-11-25 17:37:46 +01:00
panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths))
}
copiesForGoals := distContributions.getCopiesForGoals(goals)
// Iterate over each path adding a copy instruction to copiesForGoals
for _, path := range tagPaths {
// It's possible that the Path is nil from errant modules. Be defensive here.
if path == nil {
tagName := "default" // for error message readability
if dist.Tag != nil {
tagName = *dist.Tag
}
panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
}
dest := filepath.Base(path.String())
if dist.Dest != nil {
var err error
if dest, err = validateSafePath(*dist.Dest); err != nil {
// This was checked in ModuleBase.GenerateBuildActions
panic(err)
}
}
ext := filepath.Ext(dest)
suffix := ""
if dist.Suffix != nil {
suffix = *dist.Suffix
}
productString := ""
if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product {
productString = fmt.Sprintf("_%s", a.entryContext.Config().DeviceProduct())
}
if suffix != "" || productString != "" {
dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext
}
if dist.Dir != nil {
var err error
if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
// This was checked in ModuleBase.GenerateBuildActions
panic(err)
}
}
copiesForGoals.addCopyInstruction(path, dest)
}
}
return distContributions
}
// generateDistContributionsForMake generates make rules that will generate the
// dist according to the instructions in the supplied distContribution.
func generateDistContributionsForMake(distContributions *distContributions) []string {
var ret []string
for _, d := range distContributions.copiesForGoals {
ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals))
// Create dist-for-goals calls for each of the copy instructions.
for _, c := range d.copies {
if distContributions.licenseMetadataFile != nil {
ret = append(
ret,
fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
}
ret = append(
ret,
fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
}
}
return ret
}
// Compute the list of Make strings to declare phony goals and dist-for-goals
// calls from the module's dist and dists properties.
func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string {
distContributions := a.getDistContributions(mod)
if distContributions == nil {
return nil
}
return generateDistContributionsForMake(distContributions)
}
// Write the license variables to Make for AndroidMkData.Custom(..) methods that do not call WriteAndroidMkData(..)
// It's required to propagate the license metadata even for module types that have non-standard interfaces to Make.
func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) {
AndroidMkEmitAssignList(w, "LOCAL_LICENSE_KINDS", a.EntryMap["LOCAL_LICENSE_KINDS"])
AndroidMkEmitAssignList(w, "LOCAL_LICENSE_CONDITIONS", a.EntryMap["LOCAL_LICENSE_CONDITIONS"])
AndroidMkEmitAssignList(w, "LOCAL_NOTICE_FILE", a.EntryMap["LOCAL_NOTICE_FILE"])
if pn, ok := a.EntryMap["LOCAL_LICENSE_PACKAGE_NAME"]; ok {
AndroidMkEmitAssignList(w, "LOCAL_LICENSE_PACKAGE_NAME", pn)
}
}
// fillInEntries goes through the common variable processing and calls the extra data funcs to
// generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file.
type fillInEntriesContext interface {
ModuleDir(module blueprint.Module) string
Config() Config
ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
ModuleType(module blueprint.Module) string
}
func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
a.entryContext = ctx
a.EntryMap = make(map[string][]string)
amod := mod.(Module)
base := amod.base()
name := base.BaseModuleName()
if a.OverrideName != "" {
name = a.OverrideName
}
if a.Include == "" {
a.Include = "$(BUILD_PREBUILT)"
}
a.Required = append(a.Required, amod.RequiredModuleNames()...)
a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...)
a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...)
for _, distString := range a.GetDistForGoals(mod) {
fmt.Fprintf(&a.header, distString)
}
fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS) # "+ctx.ModuleType(mod))
// Collect make variable assignment entries.
a.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
a.SetString("LOCAL_MODULE", name+a.SubName)
a.AddStrings("LOCAL_LICENSE_KINDS", base.commonProperties.Effective_license_kinds...)
a.AddStrings("LOCAL_LICENSE_CONDITIONS", base.commonProperties.Effective_license_conditions...)
a.AddStrings("LOCAL_NOTICE_FILE", base.commonProperties.Effective_license_text.Strings()...)
// TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ?
if base.commonProperties.Effective_package_name != nil {
a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *base.commonProperties.Effective_package_name)
} else if len(base.commonProperties.Effective_licenses) > 0 {
a.SetString("LOCAL_LICENSE_PACKAGE_NAME", strings.Join(base.commonProperties.Effective_licenses, " "))
}
a.SetString("LOCAL_MODULE_CLASS", a.Class)
a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
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 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())
}
mark platform un-availability A module is marked unavailable for platform when 1) it does not have "//apex_available:platform" in its apex_available property, or 2) it depends on another module that is unavailable for platform. In that case, LOCAL_NOT_AVAILABLE_FOR_PLATFORM is set to true for the module in the Make world. Later, that flag is used to ensure that there is no module with the flag is installed to the device. The reason why this isn't entirely done in Soong is because Soong doesn't know if a module will be installed to the device or not. To explain this, let's have an example. cc_test { name: "mytest", static_libs: ["libfoo"]} cc_library_static { name: "libfoo", static_libs: ["libbar"]} cc_library { name: "libbar", apex_available: ["com.android.xxx"]} Here, libbar is not available for platform, but is used by libfoo which is available for platform (apex_available defaults to "//apex_available:platform"). libfoo is again depended on by mytest which again is available for platform. The use of libbar should be allowed in the context of test; we don't want to make libbar available to platform just for the dependency from test because it will allow non-test uses of the library as well. Soong by itself can't tell whether libfoo and libbar are used only in the context of a test. There could be another module depending them, e.g., cc_library_shared { name: "mylib", static_libs: ["libfoo"] } can exist and it might be installed to the device, in which case we really should trigger an error. Since Make has the knowledge of what's installed and what's not, the check should be done there. Bug: 153073816 Test: m Test: remove "//apex_available:platform" from libmdnssd (it is currently installed to /system/lib), and check that `m system_image` fails Change-Id: Ia304cc5f41f173229e8a154e90cea4dce46dcebe
2020-04-07 09:37:39 +02:00
if am, ok := mod.(ApexModule); ok {
a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
}
archStr := base.Arch().ArchType.String()
host := false
switch base.Os().Class {
case Host:
if base.Target().HostCross {
// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
if base.Arch().ArchType != Common {
a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
}
} else {
// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
if base.Arch().ArchType != Common {
a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
}
}
host = true
case Device:
// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
if base.Arch().ArchType != Common {
if base.Target().NativeBridge {
hostArchStr := base.Target().NativeBridgeHostArchName
if hostArchStr != "" {
a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
}
} else {
a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
}
}
if !base.InVendorRamdisk() {
a.AddPaths("LOCAL_FULL_INIT_RC", base.initRcPaths)
}
if len(base.vintfFragmentsPaths) > 0 {
a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", base.vintfFragmentsPaths)
}
a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
a.SetString("LOCAL_VENDOR_MODULE", "true")
}
a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific))
a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific))
a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific))
if base.commonProperties.Owner != nil {
a.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner)
}
}
if host {
makeOs := base.Os().String()
if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl {
makeOs = "linux"
}
a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
a.SetString("LOCAL_IS_HOST_MODULE", "true")
}
prefix := ""
if base.ArchSpecific() {
switch base.Os().Class {
case Host:
if base.Target().HostCross {
prefix = "HOST_CROSS_"
} else {
prefix = "HOST_"
}
case Device:
prefix = "TARGET_"
}
if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType {
prefix = "2ND_" + prefix
}
}
if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
}
extraCtx := &androidMkExtraEntriesContext{
ctx: ctx,
mod: mod,
}
for _, extra := range a.ExtraEntries {
extra(extraCtx, a)
}
// Write to footer.
fmt.Fprintln(&a.footer, "include "+a.Include)
blueprintDir := ctx.ModuleDir(mod)
for _, footerFunc := range a.ExtraFooters {
footerFunc(&a.footer, name, prefix, blueprintDir)
}
}
// write flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
// given Writer object.
func (a *AndroidMkEntries) write(w io.Writer) {
if a.Disabled {
return
}
if !a.OutputFile.Valid() {
return
}
w.Write(a.header.Bytes())
for _, name := range a.entryOrder {
AndroidMkEmitAssignList(w, name, a.EntryMap[name])
}
w.Write(a.footer.Bytes())
}
func (a *AndroidMkEntries) FooterLinesForTests() []string {
return strings.Split(string(a.footer.Bytes()), "\n")
}
// AndroidMkSingleton is a singleton to collect Android.mk data from all modules and dump them into
// the final Android-<product_name>.mk file output.
func AndroidMkSingleton() Singleton {
return &androidMkSingleton{}
}
type androidMkSingleton struct{}
func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
// Skip if Soong wasn't invoked from Make.
if !ctx.Config().KatiEnabled() {
return
}
var androidMkModulesList []blueprint.Module
ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
androidMkModulesList = append(androidMkModulesList, module)
})
// Sort the module list by the module names to eliminate random churns, which may erroneously
// invoke additional build processes.
sort.SliceStable(androidMkModulesList, func(i, j int) bool {
return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j])
})
transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
if ctx.Failed() {
return
}
err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList)
if err != nil {
ctx.Errorf(err.Error())
}
ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
Output: transMk,
})
}
func translateAndroidMk(ctx SingletonContext, absMkFile string, mods []blueprint.Module) error {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
typeStats := make(map[string]int)
for _, mod := range mods {
err := translateAndroidMkModule(ctx, buf, mod)
if err != nil {
os.Remove(absMkFile)
return err
}
if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod {
typeStats[ctx.ModuleType(amod)] += 1
}
}
keys := []string{}
fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
for k := range typeStats {
keys = append(keys, k)
}
sort.Strings(keys)
for _, mod_type := range keys {
fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
}
return pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
}
func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
defer func() {
if r := recover(); r != nil {
panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod)))
}
}()
// Additional cases here require review for correct license propagation to make.
switch x := mod.(type) {
case AndroidMkDataProvider:
return translateAndroidModule(ctx, w, mod, x)
case bootstrap.GoBinaryTool:
return translateGoBinaryModule(ctx, w, mod, x)
case AndroidMkEntriesProvider:
return translateAndroidMkEntriesModule(ctx, w, mod, x)
default:
// Not exported to make so no make variables to set.
return nil
}
}
// A simple, special Android.mk entry output func to make it possible to build blueprint tools using
// m by making them phony targets.
func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
goBinary bootstrap.GoBinaryTool) error {
name := ctx.ModuleName(mod)
fmt.Fprintln(w, ".PHONY:", name)
fmt.Fprintln(w, name+":", goBinary.InstallPath())
fmt.Fprintln(w, "")
// Assuming no rules in make include go binaries in distributables.
// If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files.
// In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for
// `goBinary.InstallPath()` pointing to the `name`.meta_lic file.
return nil
}
func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) {
// Get the preamble content through AndroidMkEntries logic.
data.Entries = AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
DistFiles: data.DistFiles,
OutputFile: data.OutputFile,
Disabled: data.Disabled,
Include: data.Include,
Required: data.Required,
Host_required: data.Host_required,
Target_required: data.Target_required,
}
data.Entries.fillInEntries(ctx, mod)
// copy entries back to data since it is used in Custom
data.Required = data.Entries.Required
data.Host_required = data.Entries.Host_required
data.Target_required = data.Entries.Target_required
}
// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
provider AndroidMkDataProvider) error {
amod := mod.(Module).base()
if shouldSkipAndroidMkProcessing(amod) {
return nil
}
data := provider.AndroidMk()
if data.Include == "" {
data.Include = "$(BUILD_PREBUILT)"
}
data.fillInData(ctx, mod)
prefix := ""
if amod.ArchSpecific() {
switch amod.Os().Class {
case Host:
if amod.Target().HostCross {
prefix = "HOST_CROSS_"
} else {
prefix = "HOST_"
}
case Device:
prefix = "TARGET_"
}
if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType {
prefix = "2ND_" + prefix
}
}
name := provider.BaseModuleName()
blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
if data.Custom != nil {
// List of module types allowed to use .Custom(...)
// Additions to the list require careful review for proper license handling.
switch reflect.TypeOf(mod).String() { // ctx.ModuleType(mod) doesn't work: aidl_interface creates phony without type
case "*aidl.aidlApi": // writes non-custom before adding .phony
case "*aidl.aidlMapping": // writes non-custom before adding .phony
case "*android.customModule": // appears in tests only
case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
case "*apex.apexBundle": // license properties written
case "*bpf.bpf": // license properties written (both for module and objs)
case "*genrule.Module": // writes non-custom before adding .phony
case "*java.SystemModules": // doesn't go through base_rules
case "*java.systemModulesImport": // doesn't go through base_rules
case "*phony.phony": // license properties written
case "*selinux.selinuxContextsModule": // license properties written
case "*sysprop.syspropLibrary": // license properties written
default:
if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
}
}
data.Custom(w, name, prefix, blueprintDir, data)
} else {
WriteAndroidMkData(w, data)
}
return nil
}
// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
if data.Disabled {
return
}
if !data.OutputFile.Valid() {
return
}
// write preamble via Entries
data.Entries.footer = bytes.Buffer{}
data.Entries.write(w)
for _, extra := range data.Extra {
extra(w, data.OutputFile.Path())
}
fmt.Fprintln(w, "include "+data.Include)
}
func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
provider AndroidMkEntriesProvider) error {
if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
return nil
}
// Any new or special cases here need review to verify correct propagation of license information.
for _, entries := range provider.AndroidMkEntries() {
entries.fillInEntries(ctx, mod)
entries.write(w)
}
return nil
}
Add (obj|tidy)-*_os, and (obj|tidy)-*_subset targets * The obj-* targets only call clang or clang++ to compile C/C++ files, like the tidy-* targets only call clang-tidy. * Add (obj|tidy)-dir_os and module_os-(obj|tidy) phony targets to include only targets of the specified OS. * Add (obj|tidy)-dir_os_subset and module_os_subset-(obj|tidy) phony targets to include only a subset of that OS target group. * Most clang-tidy runs produce the same warnings for all variants of an OS. The *_subset targets reduce runs over multiple variants. * The obj-*subset targets are useful for a quick test to compile at least one variant of every C/C++ file for each OS. * The (obj|tidy)-soong phony target is changed to include only (obj|tidy)-top_level_directory targets instead of ALL module-(obj|tidy) targets in all subdirectories. * For aosp_arm64-eng make tidy-* targets; count NINJA commands: tidy-soong 381K tidy-soong_subset 106K tidy-soong_android 294K tidy-soong_android_subset 73K tidy-soong_linux_glibc 84K tidy-soong_windows 12K tidy-bionic 12K tidy-bionic_subset 2.4K tidy-bionic_android 11.5K tidy-bionic_android_subset 2.1K tidy-bionic_linux_glibc 1K tidy-device_android 7K tidy-device_android_subset 5K tidy-hardware_android 3K tidy-hardware_android_subset 9K libfec_rs-tidy 33 libfec_rs_subset-tidy 9 libfec_rs_android-tidy 18 libfec_rs_android_subset-tidy 3 * For aosp_arm64-eng make obj-* targets; count NINJA commands: obj-soong 399K obj-soong_subset 112K obj-soong_android 305K obj-soong_android_subset 75K obj-soong_linux_glibc 90K obj-soong_linux_glibc_subset 38K obj-soong_windows 12K obj-bionic 15K obj-bionic_subset 3K obj-bionic_android 14K obj-bionic_android_subset 2.3K obj-bionic_linux_glibc 1.3K obj-system-core 6K obj-system-core_subset 3K obj-frameworks-base 16K obj-frameworks-base_subset 6K libfec_rs-obj 33 libfec_rs_subset-obj 9 libfec_rs_android-obj 18 libfec_rs_android_subset-obj 3 Test: NINJA_ARGS="-n" WITH_TIDY=1 make some_obj_tidy_target; compare output commands from various phony targets Bug: 199169329 Bug: 202769240 Change-Id: I186c45dc07c5884888c1063dfc09cf212ffb0ebf
2021-10-12 01:46:56 +02:00
func ShouldSkipAndroidMkProcessing(module Module) bool {
return shouldSkipAndroidMkProcessing(module.base())
}
func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
if !module.commonProperties.NamespaceExportedToMake {
// TODO(jeffrygaston) do we want to validate that there are no modules being
// exported to Kati that depend on this module?
return true
}
// On Mac, only expose host darwin modules to Make, as that's all we claim to support.
// In reality, some of them depend on device-built (Java) modules, so we can't disable all
// device modules in Soong, but we can hide them from Make (and thus the build user interface)
if runtime.GOOS == "darwin" && module.Os() != Darwin {
return true
}
// Only expose the primary Darwin target, as Make does not understand Darwin+Arm64
if module.Os() == Darwin && module.Target().HostCross {
return true
}
return !module.Enabled() ||
module.commonProperties.HideFromMake ||
// Make does not understand LinuxBionic
module.Os() == LinuxBionic ||
// Make does not understand LinuxMusl, except when we are building with USE_HOST_MUSL=true
// and all host binaries are LinuxMusl
(module.Os() == LinuxMusl && module.Target().HostCross)
}
// A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how
// to use this func.
func AndroidMkDataPaths(data []DataPath) []string {
var testFiles []string
for _, d := range data {
rel := d.SrcPath.Rel()
path := d.SrcPath.String()
// LOCAL_TEST_DATA requires the rel portion of the path to be removed from the path.
if !strings.HasSuffix(path, rel) {
panic(fmt.Errorf("path %q does not end with %q", path, rel))
}
path = strings.TrimSuffix(path, rel)
testFileString := path + ":" + rel
if len(d.RelativeInstallPath) > 0 {
testFileString += ":" + d.RelativeInstallPath
}
testFiles = append(testFiles, testFileString)
}
return testFiles
}
// AndroidMkEmitAssignList emits the line
//
// VAR := ITEM ...
//
// Items are the elements to the given set of lists
// If all the passed lists are empty, no line will be emitted
func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) {
doPrint := false
for _, l := range lists {
if doPrint = len(l) > 0; doPrint {
break
}
}
if !doPrint {
return
}
fmt.Fprint(w, varName, " :=")
for _, l := range lists {
for _, item := range l {
fmt.Fprint(w, " ", item)
}
}
fmt.Fprintln(w)
}