platform_build_soong/cc/gen.go

431 lines
14 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.
package cc
import (
"path/filepath"
"strings"
"android/soong/aidl_library"
"android/soong/bazel"
"android/soong/sysprop/bp2build"
"github.com/google/blueprint"
"android/soong/android"
)
func init() {
pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex")
pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4")
pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
}
var (
lex = pctx.AndroidStaticRule("lex",
blueprint.RuleParams{
Command: "M4=$m4Cmd $lexCmd $flags -o$out $in",
CommandDeps: []string{"$lexCmd", "$m4Cmd"},
}, "flags")
sysprop = pctx.AndroidStaticRule("sysprop",
blueprint.RuleParams{
Command: "$syspropCmd --header-dir=$headerOutDir --public-header-dir=$publicOutDir " +
"--source-dir=$srcOutDir --include-name=$includeName $in",
CommandDeps: []string{"$syspropCmd"},
},
"headerOutDir", "publicOutDir", "srcOutDir", "includeName")
)
type YaccProperties struct {
// list of module-specific flags that will be used for .y and .yy compiles
Flags []string
// whether the yacc files will produce a location.hh file
Gen_location_hh *bool
// whether the yacc files will product a position.hh file
Gen_position_hh *bool
}
func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path,
outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) {
outDir := android.PathForModuleGen(ctx, "yacc")
headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h")
ret := android.Paths{headerFile}
cmd := rule.Command()
// Fix up #line markers to not use the sbox temporary directory
// android.sboxPathForOutput(outDir, outDir) returns the sbox placeholder for the out
// directory itself, without any filename appended.
sboxOutDir := cmd.PathForOutput(outDir)
sedCmd := "sed -i.bak 's#" + sboxOutDir + "#" + outDir.String() + "#'"
rule.Command().Text(sedCmd).Input(outFile)
rule.Command().Text(sedCmd).Input(headerFile)
var flags []string
if props != nil {
flags = props.Flags
if Bool(props.Gen_location_hh) {
locationHeader := outFile.InSameDir(ctx, "location.hh")
ret = append(ret, locationHeader)
cmd.ImplicitOutput(locationHeader)
rule.Command().Text(sedCmd).Input(locationHeader)
}
if Bool(props.Gen_position_hh) {
positionHeader := outFile.InSameDir(ctx, "position.hh")
ret = append(ret, positionHeader)
cmd.ImplicitOutput(positionHeader)
rule.Command().Text(sedCmd).Input(positionHeader)
}
}
cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison").
FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")).
PrebuiltBuildTool(ctx, "bison").
Flag("-d").
Flags(flags).
FlagWithOutput("--defines=", headerFile).
Flag("-o").Output(outFile).Input(yaccFile)
return ret
}
func genAidl(
ctx android.ModuleContext,
rule *android.RuleBuilder,
outDirBase string,
aidlFile android.Path,
aidlHdrs android.Paths,
aidlFlags string,
) (cppFile android.OutputPath, headerFiles android.Paths) {
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
shortName := baseName
// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
// an interface name has a leading I. Those same heuristics have been
// moved here.
if len(baseName) >= 2 && baseName[0] == 'I' &&
strings.ToUpper(baseName)[1] == baseName[1] {
shortName = strings.TrimPrefix(baseName, "I")
}
outDir := android.PathForModuleGen(ctx, outDirBase)
cpp output of an AIDL file is together with the headers For an AIDL file, five files are generated for the CPP backend: cpp output, depfile, and three headers. Previously, the cpp output and the dep file were created at <module_out>/gen/<abs_path_to_input_aidl>.cpp, while the headers were at <module_out>/gen/aidl/<package_name>/*.h. This not only looks inconsistent, but more critically makes it difficult for the aidl compiler to infer the path to the headers that the build system registered as implicit outputs. Inferring the implicit outputs by the aidl compiler is needed because otherwise users will see the error message from sbox just saying that some of the expected files are not created. This can happen when the input AIDL file is put directly into the srcs property without specifying the base directory, e.g. some/subdir/android/foo/IFoo.aidl where the pacakge is actually android.foo. In order to make it easy for developers to fix such an error, I0f23b6027ba3a4755cc2901f4a7f7fc70bffd0ef introduces a check in the aidl compiler which is triggered earlier than the sbox error. The compiler now enforces that the cpp output is at <out_dir>/<package_name>/<type>.app. When the check fails, it suggests to fix that by correctly feeding the AIDL file via filegroup and the path property. This change in Soong is required to satisfy aidl compiler when the base directory is correctly set. The cpp output is now at <module_out>/gen/aidl/<pacakge_name>/<type>.cpp. Bug: 184586092 Test: aidl_unittests Change-Id: I172180a40bded4f6c08679a2d862b086998be1e1
2021-04-07 14:49:34 +02:00
cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
cmd := rule.Command()
cmd.BuiltTool("aidl-cpp").
// libc++ is default stl for aidl-cpp (a cc_binary_host module)
ImplicitTool(ctx.Config().HostCcSharedLibPath(ctx, "libc++")).
FlagWithDepFile("-d", depFile).
Flag("--ninja").
Flag(aidlFlags).
Input(aidlFile).
OutputDir().
cpp output of an AIDL file is together with the headers For an AIDL file, five files are generated for the CPP backend: cpp output, depfile, and three headers. Previously, the cpp output and the dep file were created at <module_out>/gen/<abs_path_to_input_aidl>.cpp, while the headers were at <module_out>/gen/aidl/<package_name>/*.h. This not only looks inconsistent, but more critically makes it difficult for the aidl compiler to infer the path to the headers that the build system registered as implicit outputs. Inferring the implicit outputs by the aidl compiler is needed because otherwise users will see the error message from sbox just saying that some of the expected files are not created. This can happen when the input AIDL file is put directly into the srcs property without specifying the base directory, e.g. some/subdir/android/foo/IFoo.aidl where the pacakge is actually android.foo. In order to make it easy for developers to fix such an error, I0f23b6027ba3a4755cc2901f4a7f7fc70bffd0ef introduces a check in the aidl compiler which is triggered earlier than the sbox error. The compiler now enforces that the cpp output is at <out_dir>/<package_name>/<type>.app. When the check fails, it suggests to fix that by correctly feeding the AIDL file via filegroup and the path property. This change in Soong is required to satisfy aidl compiler when the base directory is correctly set. The cpp output is now at <module_out>/gen/aidl/<pacakge_name>/<type>.cpp. Bug: 184586092 Test: aidl_unittests Change-Id: I172180a40bded4f6c08679a2d862b086998be1e1
2021-04-07 14:49:34 +02:00
Output(cppFile).
ImplicitOutputs(android.WritablePaths{
headerI,
headerBn,
headerBp,
})
if aidlHdrs != nil {
cmd.Implicits(aidlHdrs)
}
cpp output of an AIDL file is together with the headers For an AIDL file, five files are generated for the CPP backend: cpp output, depfile, and three headers. Previously, the cpp output and the dep file were created at <module_out>/gen/<abs_path_to_input_aidl>.cpp, while the headers were at <module_out>/gen/aidl/<package_name>/*.h. This not only looks inconsistent, but more critically makes it difficult for the aidl compiler to infer the path to the headers that the build system registered as implicit outputs. Inferring the implicit outputs by the aidl compiler is needed because otherwise users will see the error message from sbox just saying that some of the expected files are not created. This can happen when the input AIDL file is put directly into the srcs property without specifying the base directory, e.g. some/subdir/android/foo/IFoo.aidl where the pacakge is actually android.foo. In order to make it easy for developers to fix such an error, I0f23b6027ba3a4755cc2901f4a7f7fc70bffd0ef introduces a check in the aidl compiler which is triggered earlier than the sbox error. The compiler now enforces that the cpp output is at <out_dir>/<package_name>/<type>.app. When the check fails, it suggests to fix that by correctly feeding the AIDL file via filegroup and the path property. This change in Soong is required to satisfy aidl compiler when the base directory is correctly set. The cpp output is now at <module_out>/gen/aidl/<pacakge_name>/<type>.cpp. Bug: 184586092 Test: aidl_unittests Change-Id: I172180a40bded4f6c08679a2d862b086998be1e1
2021-04-07 14:49:34 +02:00
return cppFile, android.Paths{
headerI,
headerBn,
headerBp,
}
}
type LexProperties struct {
// list of module-specific flags that will be used for .l and .ll compiles
Flags []string
}
func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) {
var flags []string
if props != nil {
flags = props.Flags
}
flagsString := strings.Join(flags[:], " ")
ctx.Build(pctx, android.BuildParams{
Rule: lex,
Description: "lex " + lexFile.Rel(),
Output: outFile,
Input: lexFile,
Args: map[string]string{"flags": flagsString},
})
}
type LexAttrs struct {
Srcs bazel.LabelListAttribute
Lexopts bazel.StringListAttribute
}
type LexNames struct {
cSrcName bazel.LabelAttribute
srcName bazel.LabelAttribute
}
func bp2BuildLex(ctx android.Bp2buildMutatorContext, moduleName string, ca compilerAttributes) LexNames {
names := LexNames{}
if !ca.lSrcs.IsEmpty() {
names.cSrcName = createLexTargetModule(ctx, moduleName+"_genlex_l", ca.lSrcs, ca.lexopts)
}
if !ca.llSrcs.IsEmpty() {
names.srcName = createLexTargetModule(ctx, moduleName+"_genlex_ll", ca.llSrcs, ca.lexopts)
}
return names
}
func createLexTargetModule(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute, opts bazel.StringListAttribute) bazel.LabelAttribute {
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "genlex",
Bzl_load_location: "//build/bazel/rules/cc:flex.bzl",
},
android.CommonAttributes{Name: name},
&LexAttrs{
Srcs: srcs,
Lexopts: opts,
})
return bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
}
func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
headers := android.WritablePaths{headerFile, publicHeaderFile}
ctx.Build(pctx, android.BuildParams{
Rule: sysprop,
Description: "sysprop " + syspropFile.Rel(),
Output: cppFile,
ImplicitOutputs: headers,
Input: syspropFile,
Args: map[string]string{
"headerOutDir": filepath.Dir(headerFile.String()),
"publicOutDir": filepath.Dir(publicHeaderFile.String()),
"srcOutDir": filepath.Dir(cppFile.String()),
"includeName": syspropFile.Rel() + ".h",
},
})
return cppFile, headers.Paths()
}
func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
labels := bp2build.SyspropLibraryLabels{
SyspropLibraryLabel: moduleName + "_sysprop_library",
CcStaticLibraryLabel: moduleName + "_cc_sysprop_library_static",
}
bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, srcs)
bp2build.Bp2buildSyspropCc(ctx, labels, minSdkVersion)
return createLabelAttributeCorrespondingToSrcs(":"+labels.CcStaticLibraryLabel, srcs)
}
// Creates a LabelAttribute for a given label where the value is only set for
// the same config values that have values in a given LabelListAttribute
func createLabelAttributeCorrespondingToSrcs(baseLabelName string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
baseLabel := bazel.Label{Label: baseLabelName}
label := bazel.LabelAttribute{}
if !srcs.Value.IsNil() && !srcs.Value.IsEmpty() {
label.Value = &baseLabel
return &label
}
for axis, configToSrcs := range srcs.ConfigurableValues {
for config, val := range configToSrcs {
if !val.IsNil() && !val.IsEmpty() {
label.SetSelectValue(axis, config, baseLabel)
}
}
}
return &label
}
// Used to communicate information from the genSources method back to the library code that uses
// it.
type generatedSourceInfo struct {
// The headers created from .proto files
protoHeaders android.Paths
// The files that can be used as order only dependencies in order to ensure that the proto header
// files are up to date.
protoOrderOnlyDeps android.Paths
// The headers created from .aidl files
aidlHeaders android.Paths
// The files that can be used as order only dependencies in order to ensure that the aidl header
// files are up to date.
aidlOrderOnlyDeps android.Paths
// The headers created from .sysprop files
syspropHeaders android.Paths
// The files that can be used as order only dependencies in order to ensure that the sysprop
// header files are up to date.
syspropOrderOnlyDeps android.Paths
}
func genSources(
ctx android.ModuleContext,
aidlLibraryInfos []aidl_library.AidlLibraryInfo,
srcFiles android.Paths,
buildFlags builderFlags,
) (android.Paths, android.Paths, generatedSourceInfo) {
var info generatedSourceInfo
var deps android.Paths
var rsFiles android.Paths
// aidlRule supports compiling aidl files from srcs prop while aidlLibraryRule supports
// compiling aidl files from aidl_library modules specified in aidl.libs prop.
// The rules are separated so that they don't wipe out the other's outputDir
var aidlRule *android.RuleBuilder
var aidlLibraryRule *android.RuleBuilder
var yaccRule_ *android.RuleBuilder
yaccRule := func() *android.RuleBuilder {
if yaccRule_ == nil {
yaccRule_ = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "yacc"),
android.PathForModuleGen(ctx, "yacc.sbox.textproto"))
}
return yaccRule_
}
for i, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".y":
cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c")
srcFiles[i] = cFile
deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...)
case ".yy":
cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp")
srcFiles[i] = cppFile
deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...)
case ".l":
cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
srcFiles[i] = cFile
genLex(ctx, srcFile, cFile, buildFlags.lex)
case ".ll":
cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
srcFiles[i] = cppFile
genLex(ctx, srcFile, cppFile, buildFlags.lex)
case ".proto":
ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
srcFiles[i] = ccFile
info.protoHeaders = append(info.protoHeaders, headerFile)
// Use the generated header as an order only dep to ensure that it is up to date when needed.
info.protoOrderOnlyDeps = append(info.protoOrderOnlyDeps, headerFile)
case ".aidl":
if aidlRule == nil {
aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
cppFile, aidlHeaders := genAidl(
ctx,
aidlRule,
"aidl",
srcFile,
nil,
buildFlags.aidlFlags+" -I"+baseDir,
)
srcFiles[i] = cppFile
cpp output of an AIDL file is together with the headers For an AIDL file, five files are generated for the CPP backend: cpp output, depfile, and three headers. Previously, the cpp output and the dep file were created at <module_out>/gen/<abs_path_to_input_aidl>.cpp, while the headers were at <module_out>/gen/aidl/<package_name>/*.h. This not only looks inconsistent, but more critically makes it difficult for the aidl compiler to infer the path to the headers that the build system registered as implicit outputs. Inferring the implicit outputs by the aidl compiler is needed because otherwise users will see the error message from sbox just saying that some of the expected files are not created. This can happen when the input AIDL file is put directly into the srcs property without specifying the base directory, e.g. some/subdir/android/foo/IFoo.aidl where the pacakge is actually android.foo. In order to make it easy for developers to fix such an error, I0f23b6027ba3a4755cc2901f4a7f7fc70bffd0ef introduces a check in the aidl compiler which is triggered earlier than the sbox error. The compiler now enforces that the cpp output is at <out_dir>/<package_name>/<type>.app. When the check fails, it suggests to fix that by correctly feeding the AIDL file via filegroup and the path property. This change in Soong is required to satisfy aidl compiler when the base directory is correctly set. The cpp output is now at <module_out>/gen/aidl/<pacakge_name>/<type>.cpp. Bug: 184586092 Test: aidl_unittests Change-Id: I172180a40bded4f6c08679a2d862b086998be1e1
2021-04-07 14:49:34 +02:00
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
// TODO: Reduce the size of the ninja file by using one order only dep for the whole rule
info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...)
case ".rscript", ".fs":
cppFile := rsGeneratedCppFile(ctx, srcFile)
rsFiles = append(rsFiles, srcFiles[i])
srcFiles[i] = cppFile
case ".sysprop":
cppFile, headerFiles := genSysprop(ctx, srcFile)
srcFiles[i] = cppFile
info.syspropHeaders = append(info.syspropHeaders, headerFiles...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
info.syspropOrderOnlyDeps = append(info.syspropOrderOnlyDeps, headerFiles...)
}
}
for _, aidlLibraryInfo := range aidlLibraryInfos {
if aidlLibraryRule == nil {
aidlLibraryRule = android.NewRuleBuilder(pctx, ctx).Sbox(
android.PathForModuleGen(ctx, "aidl_library"),
android.PathForModuleGen(ctx, "aidl_library.sbox.textproto"),
).SandboxInputs()
}
for _, aidlSrc := range aidlLibraryInfo.Srcs {
cppFile, aidlHeaders := genAidl(
ctx,
aidlLibraryRule,
"aidl_library",
aidlSrc,
aidlLibraryInfo.Hdrs.ToList(),
buildFlags.aidlFlags,
)
srcFiles = append(srcFiles, cppFile)
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
// TODO: Reduce the size of the ninja file by using one order only dep for the whole rule
info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...)
}
}
if aidlRule != nil {
aidlRule.Build("aidl", "gen aidl")
}
if aidlLibraryRule != nil {
aidlLibraryRule.Build("aidl_library", "gen aidl_library")
}
if yaccRule_ != nil {
yaccRule_.Build("yacc", "gen yacc")
}
deps = append(deps, info.protoOrderOnlyDeps...)
deps = append(deps, info.aidlOrderOnlyDeps...)
deps = append(deps, info.syspropOrderOnlyDeps...)
if len(rsFiles) > 0 {
deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...)
}
return srcFiles, deps, info
}