2020-11-26 01:06:39 +01:00
|
|
|
package bp2build
|
|
|
|
|
|
|
|
import (
|
2022-01-07 15:55:29 +01:00
|
|
|
"encoding/json"
|
2023-04-11 22:48:17 +02:00
|
|
|
"fmt"
|
2020-11-26 01:06:39 +01:00
|
|
|
"reflect"
|
2023-04-12 19:27:45 +02:00
|
|
|
"strconv"
|
2020-11-26 01:06:39 +01:00
|
|
|
"strings"
|
|
|
|
|
2021-08-31 22:30:36 +02:00
|
|
|
"android/soong/android"
|
2023-08-04 22:52:14 +02:00
|
|
|
"android/soong/apex"
|
2023-01-19 17:02:47 +01:00
|
|
|
"android/soong/cc"
|
2022-03-25 17:33:26 +01:00
|
|
|
cc_config "android/soong/cc/config"
|
|
|
|
java_config "android/soong/java/config"
|
2023-08-23 19:49:13 +02:00
|
|
|
rust_config "android/soong/rust/config"
|
2023-08-04 22:52:14 +02:00
|
|
|
"android/soong/starlark_fmt"
|
2022-07-29 04:25:34 +02:00
|
|
|
|
2020-11-26 01:06:39 +01:00
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
)
|
|
|
|
|
|
|
|
type BazelFile struct {
|
|
|
|
Dir string
|
|
|
|
Basename string
|
|
|
|
Contents string
|
|
|
|
}
|
|
|
|
|
2023-09-12 19:07:07 +02:00
|
|
|
// createSoongInjectionDirFiles returns most of the files to write to the soong_injection directory.
|
|
|
|
// Some other files also come from CreateProductConfigFiles
|
|
|
|
func createSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
|
|
|
|
cfg := ctx.Config()
|
2021-05-06 15:31:18 +02:00
|
|
|
var files []BazelFile
|
|
|
|
|
2022-11-15 21:51:04 +01:00
|
|
|
files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
|
|
|
|
files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg)))
|
|
|
|
|
2021-06-17 07:43:19 +02:00
|
|
|
files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
|
2023-01-19 17:02:47 +01:00
|
|
|
files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg)))
|
|
|
|
files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg)))
|
2022-03-25 17:33:26 +01:00
|
|
|
|
|
|
|
files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
|
|
|
|
files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
|
2021-05-06 15:31:18 +02:00
|
|
|
|
2023-08-23 19:49:13 +02:00
|
|
|
files = append(files, newFile("rust_toolchain", GeneratedBuildFileName, "")) // Creates a //rust_toolchain package.
|
|
|
|
files = append(files, newFile("rust_toolchain", "constants.bzl", rust_config.BazelRustToolchainVars(cfg)))
|
|
|
|
|
2022-07-29 04:25:34 +02:00
|
|
|
files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
|
2023-02-09 02:43:09 +01:00
|
|
|
apexToolchainVars, err := apex.BazelApexToolchainVars()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars))
|
2022-07-29 04:25:34 +02:00
|
|
|
|
2023-08-25 23:42:42 +02:00
|
|
|
if buf, err := json.MarshalIndent(metrics.convertedModuleWithType, "", " "); err != nil {
|
|
|
|
return []BazelFile{}, err
|
|
|
|
} else {
|
|
|
|
files = append(files, newFile("metrics", "converted_modules.json", string(buf)))
|
|
|
|
}
|
2021-06-17 07:43:19 +02:00
|
|
|
|
2022-09-20 05:54:47 +02:00
|
|
|
convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2023-04-11 10:49:01 +02:00
|
|
|
files = append(files, newFile("metrics", GeneratedBuildFileName, "")) // Creates a //metrics package.
|
2022-09-20 05:54:47 +02:00
|
|
|
files = append(files, newFile("metrics", "converted_modules_path_map.json", string(convertedModulePathMap)))
|
2023-04-11 10:49:01 +02:00
|
|
|
files = append(files, newFile("metrics", "converted_modules_path_map.bzl", "modules = "+strings.ReplaceAll(string(convertedModulePathMap), "\\", "\\\\")))
|
2022-09-20 05:54:47 +02:00
|
|
|
|
2021-11-19 15:29:43 +01:00
|
|
|
files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
|
|
|
|
|
2022-02-16 15:02:48 +01:00
|
|
|
files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
|
|
|
|
|
2023-04-28 21:32:27 +02:00
|
|
|
apiLevelsMap, err := android.GetApiLevelsMap(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
apiLevelsContent, err := json.Marshal(apiLevelsMap)
|
2022-01-07 15:55:29 +01:00
|
|
|
if err != nil {
|
2023-02-09 02:43:09 +01:00
|
|
|
return nil, err
|
2022-01-07 15:55:29 +01:00
|
|
|
}
|
|
|
|
files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
|
2023-02-24 15:46:43 +01:00
|
|
|
// TODO(b/269691302) value of apiLevelsContent is product variable dependent and should be avoided for soong injection
|
2022-01-07 15:55:29 +01:00
|
|
|
files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
|
2023-04-11 22:48:17 +02:00
|
|
|
files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
|
2022-01-07 15:55:29 +01:00
|
|
|
|
2023-02-03 23:40:08 +01:00
|
|
|
files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
|
2022-12-14 20:32:05 +01:00
|
|
|
// TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested
|
|
|
|
files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n"))
|
|
|
|
files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n"))
|
|
|
|
|
2023-02-09 02:43:09 +01:00
|
|
|
return files, nil
|
2021-05-06 15:31:18 +02:00
|
|
|
}
|
|
|
|
|
2023-04-11 22:48:17 +02:00
|
|
|
func platformVersionContents(cfg android.Config) string {
|
|
|
|
// Despite these coming from cfg.productVariables, they are actually hardcoded in global
|
|
|
|
// makefiles, not set in individual product config makesfiles, so they're safe to just export
|
|
|
|
// and load() directly.
|
|
|
|
|
|
|
|
platformVersionActiveCodenames := make([]string, 0, len(cfg.PlatformVersionActiveCodenames()))
|
|
|
|
for _, codename := range cfg.PlatformVersionActiveCodenames() {
|
|
|
|
platformVersionActiveCodenames = append(platformVersionActiveCodenames, fmt.Sprintf("%q", codename))
|
|
|
|
}
|
|
|
|
|
2023-04-12 19:27:45 +02:00
|
|
|
platformSdkVersion := "None"
|
|
|
|
if cfg.RawPlatformSdkVersion() != nil {
|
|
|
|
platformSdkVersion = strconv.Itoa(*cfg.RawPlatformSdkVersion())
|
|
|
|
}
|
|
|
|
|
2023-04-11 22:48:17 +02:00
|
|
|
return fmt.Sprintf(`
|
|
|
|
platform_versions = struct(
|
|
|
|
platform_sdk_final = %s,
|
2023-04-12 19:27:45 +02:00
|
|
|
platform_sdk_version = %s,
|
2023-04-11 22:48:17 +02:00
|
|
|
platform_sdk_codename = %q,
|
|
|
|
platform_version_active_codenames = [%s],
|
|
|
|
)
|
2023-04-12 19:27:45 +02:00
|
|
|
`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
|
2023-04-11 22:48:17 +02:00
|
|
|
}
|
|
|
|
|
2023-08-04 22:52:14 +02:00
|
|
|
func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
|
2021-04-01 09:11:11 +02:00
|
|
|
var files []BazelFile
|
2020-11-26 01:06:39 +01:00
|
|
|
|
2021-01-25 04:55:54 +01:00
|
|
|
if mode == QueryView {
|
2021-04-01 09:11:11 +02:00
|
|
|
// Write top level WORKSPACE.
|
|
|
|
files = append(files, newFile("", "WORKSPACE", ""))
|
|
|
|
|
2021-03-10 08:05:59 +01:00
|
|
|
// Used to denote that the top level directory is a package.
|
|
|
|
files = append(files, newFile("", GeneratedBuildFileName, ""))
|
|
|
|
|
|
|
|
files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
|
|
|
|
|
2020-12-14 14:25:34 +01:00
|
|
|
// These files are only used for queryview.
|
|
|
|
files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
|
|
|
|
|
|
|
|
for bzlFileName, ruleShim := range ruleShims {
|
|
|
|
files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
|
|
|
|
}
|
|
|
|
files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
|
2020-11-26 01:06:39 +01:00
|
|
|
}
|
|
|
|
|
2022-08-24 00:29:05 +02:00
|
|
|
files = append(files, createBuildFiles(buildToTargets, mode)...)
|
2020-11-26 01:06:39 +01:00
|
|
|
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
2022-08-24 00:29:05 +02:00
|
|
|
func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
|
2020-11-26 01:06:39 +01:00
|
|
|
files := make([]BazelFile, 0, len(buildToTargets))
|
2023-03-01 01:02:16 +01:00
|
|
|
for _, dir := range android.SortedKeys(buildToTargets) {
|
2021-01-27 03:58:43 +01:00
|
|
|
targets := buildToTargets[dir]
|
2021-05-25 07:16:48 +02:00
|
|
|
targets.sort()
|
|
|
|
|
|
|
|
var content string
|
2023-06-20 23:46:57 +02:00
|
|
|
if mode == Bp2Build {
|
2021-05-25 07:16:48 +02:00
|
|
|
content = `# READ THIS FIRST:
|
|
|
|
# This file was automatically generated by bp2build for the Bazel migration project.
|
|
|
|
# Feel free to edit or test it, but do *not* check it into your version control system.
|
|
|
|
`
|
2021-02-05 15:38:15 +01:00
|
|
|
content += targets.LoadStatements()
|
2022-08-04 22:31:14 +02:00
|
|
|
content += "\n\n"
|
|
|
|
// Get package rule from the handcrafted BUILD file, otherwise emit the default one.
|
|
|
|
prText := "package(default_visibility = [\"//visibility:public\"])\n"
|
|
|
|
if pr := targets.packageRule(); pr != nil {
|
|
|
|
prText = pr.content
|
|
|
|
}
|
|
|
|
content += prText
|
2021-05-25 07:16:48 +02:00
|
|
|
} else if mode == QueryView {
|
|
|
|
content = soongModuleLoad
|
2020-12-14 14:25:34 +01:00
|
|
|
}
|
2021-01-27 03:58:43 +01:00
|
|
|
if content != "" {
|
|
|
|
// If there are load statements, add a couple of newlines.
|
2020-11-26 01:06:39 +01:00
|
|
|
content += "\n\n"
|
|
|
|
}
|
2021-01-27 03:58:43 +01:00
|
|
|
content += targets.String()
|
2021-02-17 19:22:03 +01:00
|
|
|
files = append(files, newFile(dir, GeneratedBuildFileName, content))
|
2020-11-26 01:06:39 +01:00
|
|
|
}
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
func newFile(dir, basename, content string) BazelFile {
|
|
|
|
return BazelFile{
|
|
|
|
Dir: dir,
|
|
|
|
Basename: basename,
|
|
|
|
Contents: content,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
bazelRulesSubDir = "build/bazel/queryview_rules"
|
|
|
|
|
|
|
|
// additional files:
|
|
|
|
// * workspace file
|
|
|
|
// * base BUILD file
|
|
|
|
// * rules BUILD file
|
|
|
|
// * rules providers.bzl file
|
|
|
|
// * rules soong_module.bzl file
|
|
|
|
numAdditionalFiles = 5
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// Certain module property names are blocklisted/ignored here, for the reasons commented.
|
|
|
|
ignoredPropNames = map[string]bool{
|
2022-09-08 16:43:42 +02:00
|
|
|
"name": true, // redundant, since this is explicitly generated for every target
|
|
|
|
"from": true, // reserved keyword
|
|
|
|
"in": true, // reserved keyword
|
|
|
|
"size": true, // reserved for tests
|
|
|
|
"arch": true, // interface prop type is not supported yet.
|
|
|
|
"multilib": true, // interface prop type is not supported yet.
|
|
|
|
"target": true, // interface prop type is not supported yet.
|
|
|
|
"visibility": true, // Bazel has native visibility semantics. Handle later.
|
|
|
|
"features": true, // There is already a built-in attribute 'features' which cannot be overridden.
|
|
|
|
"for": true, // reserved keyword, b/233579439
|
|
|
|
"versions_with_info": true, // TODO(b/245730552) struct properties not fully supported
|
2020-11-26 01:06:39 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func shouldGenerateAttribute(prop string) bool {
|
|
|
|
return !ignoredPropNames[prop]
|
|
|
|
}
|
|
|
|
|
|
|
|
func shouldSkipStructField(field reflect.StructField) bool {
|
2021-09-22 21:52:58 +02:00
|
|
|
if field.PkgPath != "" && !field.Anonymous {
|
2020-11-26 01:06:39 +01:00
|
|
|
// Skip unexported fields. Some properties are
|
|
|
|
// internal to Soong only, and these fields do not have PkgPath.
|
|
|
|
return true
|
|
|
|
}
|
2022-08-04 22:31:14 +02:00
|
|
|
// fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc.
|
2020-11-26 01:06:39 +01:00
|
|
|
// but cannot be set in a .bp file
|
|
|
|
if proptools.HasTag(field, "blueprint", "mutated") {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
|
|
|
|
// testonly = True, forcing other rules that depend on _test rules to also be
|
|
|
|
// marked as testonly = True. This semantic constraint is not present in Soong.
|
|
|
|
// To work around, rename "*_test" rules to "*_test_".
|
|
|
|
func canonicalizeModuleType(moduleName string) string {
|
|
|
|
if strings.HasSuffix(moduleName, "_test") {
|
|
|
|
return moduleName + "_"
|
|
|
|
}
|
|
|
|
|
|
|
|
return moduleName
|
|
|
|
}
|