Merge "16k: Add 16K variant kernel/ramdisk build targets"
diff --git a/core/Makefile b/core/Makefile
index 987721f..6ff7031 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -7339,17 +7339,9 @@
haiku: $(SOONG_FUZZ_PACKAGING_ARCH_MODULES) $(ALL_FUZZ_TARGETS)
$(call dist-for-goals,haiku,$(SOONG_FUZZ_PACKAGING_ARCH_MODULES))
$(call dist-for-goals,haiku,$(PRODUCT_OUT)/module-info.json)
-
-.PHONY: haiku-java-device
-haiku-java-device: $(SOONG_JAVA_FUZZ_DEVICE_PACKAGING_ARCH_MODULES) $(ALL_JAVA_FUZZ_DEVICE_TARGETS)
-$(call dist-for-goals,haiku-java-device,$(SOONG_JAVA_FUZZ_DEVICE_PACKAGING_ARCH_MODULES))
-$(call dist-for-goals,haiku-java-device,$(PRODUCT_OUT)/module-info.json)
-
-.PHONY: haiku-java-host
-haiku-java-host: $(SOONG_JAVA_FUZZ_HOST_PACKAGING_ARCH_MODULES) $(ALL_JAVA_FUZZ_HOST_TARGETS)
-$(call dist-for-goals,haiku-java-host,$(SOONG_JAVA_FUZZ_HOST_PACKAGING_ARCH_MODULES))
-$(call dist-for-goals,haiku-java-host,$(PRODUCT_OUT)/module-info.json)
-
+.PHONY: haiku-java
+haiku-java: $(SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES) $(ALL_JAVA_FUZZ_TARGETS)
+$(call dist-for-goals,haiku-java,$(SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES))
.PHONY: haiku-rust
haiku-rust: $(SOONG_RUST_FUZZ_PACKAGING_ARCH_MODULES) $(ALL_RUST_FUZZ_TARGETS)
$(call dist-for-goals,haiku-rust,$(SOONG_RUST_FUZZ_PACKAGING_ARCH_MODULES))
diff --git a/core/envsetup.mk b/core/envsetup.mk
index 8887ddc..860ce79 100644
--- a/core/envsetup.mk
+++ b/core/envsetup.mk
@@ -30,13 +30,14 @@
# In order to avoid running starlark every time the stamp file is checked, we use
# $(KATI_shell_no_rerun). Then, to make sure that we actually do rerun kati when
# modifying the starlark files, we add the starlark files to the kati stamp file with
-# $(KATI_extra_file_deps).
+# $(KATI_extra_file_deps). This behavior can be modified by passing a list of starlark files
+# to exclude from the dependency list as $(2)
define run-starlark
$(eval _starlark_results := $(OUT_DIR)/starlark_results/$(subst /,_,$(1)).mk)
$(KATI_shell_no_rerun mkdir -p $(OUT_DIR)/starlark_results && $(OUT_DIR)/rbcrun --mode=make $(1) >$(_starlark_results) && touch -t 200001010000 $(_starlark_results))
$(if $(filter-out 0,$(.SHELLSTATUS)),$(error Starlark failed to run))
$(eval include $(_starlark_results))
-$(KATI_extra_file_deps $(LOADED_STARLARK_FILES))
+$(KATI_extra_file_deps $(filter-out $(2),$(LOADED_STARLARK_FILES)))
$(eval LOADED_STARLARK_FILES :=)
$(eval _starlark_results :=)
endef
diff --git a/core/main.mk b/core/main.mk
index 0c1fe45..a747967 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -2165,10 +2165,11 @@
$(shell rm $(PRODUCT_OUT)/sbom-metadata.csv >/dev/null 2>&1)
$(PRODUCT_OUT)/sbom-metadata.csv: $(installed_files)
rm -f $@
- @echo installed_file$(comma)module_path$(comma)soong_module_type$(comma)is_prebuilt_make_module$(comma)product_copy_files$(comma)kernel_module_copy_files$(comma)is_platform_generated >> $@
+ @echo installed_file$(comma)module_path$(comma)soong_module_type$(comma)is_prebuilt_make_module$(comma)product_copy_files$(comma)kernel_module_copy_files$(comma)is_platform_generated,build_output_path >> $@
$(foreach f,$(installed_files),\
$(eval _module_name := $(ALL_INSTALLED_FILES.$f)) \
$(eval _path_on_device := $(patsubst $(PRODUCT_OUT)/%,%,$f)) \
+ $(eval _build_output_path := $(PRODUCT_OUT)/$(_path_on_device)) \
$(eval _module_path := $(strip $(sort $(ALL_MODULES.$(_module_name).PATH)))) \
$(eval _soong_module_type := $(strip $(sort $(ALL_MODULES.$(_module_name).SOONG_MODULE_TYPE)))) \
$(eval _is_prebuilt_make_module := $(ALL_MODULES.$(_module_name).IS_PREBUILT_MAKE_MODULE)) \
@@ -2186,9 +2187,9 @@
$(eval _is_linker_config := $(if $(findstring $f,$(SYSTEM_LINKER_CONFIG) $(vendor_linker_config_file)),Y)) \
$(eval _is_partition_compat_symlink := $(if $(findstring $f,$(PARTITION_COMPAT_SYMLINKS)),Y)) \
$(eval _is_platform_generated := $(_is_build_prop)$(_is_notice_file)$(_is_dexpreopt_image_profile)$(_is_product_system_other_avbkey)$(_is_event_log_tags_file)$(_is_system_other_odex_marker)$(_is_kernel_modules_blocklist)$(_is_fsverity_build_manifest_apk)$(_is_linker_config)$(_is_partition_compat_symlink)) \
- @echo /$(_path_on_device)$(comma)$(_module_path)$(comma)$(_soong_module_type)$(comma)$(_is_prebuilt_make_module)$(comma)$(_product_copy_files)$(comma)$(_kernel_module_copy_files)$(comma)$(_is_platform_generated) >> $@ $(newline) \
+ @echo /$(_path_on_device)$(comma)$(_module_path)$(comma)$(_soong_module_type)$(comma)$(_is_prebuilt_make_module)$(comma)$(_product_copy_files)$(comma)$(_kernel_module_copy_files)$(comma)$(_is_platform_generated)$(comma)$(_build_output_path) >> $@ $(newline) \
$(if $(_post_installed_dexpreopt_zip), \
- for i in $$(zipinfo -1 $(_post_installed_dexpreopt_zip)); do echo /$$i$(comma)$(_module_path)$(comma)$(_soong_module_type)$(comma)$(_is_prebuilt_make_module)$(comma)$(_product_copy_files)$(comma)$(_kernel_module_copy_files)$(comma)$(_is_platform_generated) >> $@ ; done $(newline) \
+ for i in $$(zipinfo -1 $(_post_installed_dexpreopt_zip)); do echo /$$i$(comma)$(_module_path)$(comma)$(_soong_module_type)$(comma)$(_is_prebuilt_make_module)$(comma)$(_product_copy_files)$(comma)$(_kernel_module_copy_files)$(comma)$(_is_platform_generated)$(comma)$(PRODUCT_OUT)/$$i >> $@ ; done $(newline) \
) \
)
@@ -2198,14 +2199,14 @@
$(PRODUCT_OUT)/sbom.spdx.json: $(PRODUCT_OUT)/sbom.spdx
$(PRODUCT_OUT)/sbom.spdx: $(PRODUCT_OUT)/sbom-metadata.csv $(GEN_SBOM)
rm -rf $@
- $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --product_out_dir=$(PRODUCT_OUT) --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr="$(PRODUCT_MANUFACTURER)" --json
+ $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --json
$(call dist-for-goals,droid,$(PRODUCT_OUT)/sbom.spdx.json:sbom/sbom.spdx.json)
else
apps_only_sbom_files := $(sort $(patsubst %,%.spdx.json,$(filter %.apk,$(apps_only_installed_files))))
$(apps_only_sbom_files): $(PRODUCT_OUT)/sbom-metadata.csv $(GEN_SBOM)
rm -rf $@
- $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --product_out_dir=$(PRODUCT_OUT) --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr="$(PRODUCT_MANUFACTURER)" --unbundled
+ $(GEN_SBOM) --output_file $@ --metadata $(PRODUCT_OUT)/sbom-metadata.csv --build_version $(BUILD_FINGERPRINT_FROM_FILE) --product_mfr "$(PRODUCT_MANUFACTURER)" --unbundled_apk
sbom: $(apps_only_sbom_files)
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 2d0a569..7cfab5b 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -111,24 +111,26 @@
# Determine whether auto-RRO is enabled for this package.
enforce_rro_enabled :=
-ifneq (,$(filter *, $(PRODUCT_ENFORCE_RRO_TARGETS)))
- # * means all system and system_ext APKs, so enable conditionally based on module path.
+ifeq (,$(filter tests,$(LOCAL_MODULE_TAGS)))
+ ifneq (,$(filter *, $(PRODUCT_ENFORCE_RRO_TARGETS)))
+ # * means all system and system_ext APKs, so enable conditionally based on module path.
- # Note that base_rules.mk has not yet been included, so it's likely that only
- # one of LOCAL_MODULE_PATH and the LOCAL_X_MODULE flags has been set.
- ifeq (,$(LOCAL_MODULE_PATH))
- non_rro_target_module := $(filter true,\
- $(LOCAL_ODM_MODULE) \
- $(LOCAL_OEM_MODULE) \
- $(LOCAL_PRODUCT_MODULE) \
- $(LOCAL_PROPRIETARY_MODULE) \
- $(LOCAL_VENDOR_MODULE))
- enforce_rro_enabled := $(if $(non_rro_target_module),,true)
- else ifneq ($(filter $(TARGET_OUT)/%,$(LOCAL_MODULE_PATH)),)
+ # Note that base_rules.mk has not yet been included, so it's likely that only
+ # one of LOCAL_MODULE_PATH and the LOCAL_X_MODULE flags has been set.
+ ifeq (,$(LOCAL_MODULE_PATH))
+ non_rro_target_module := $(filter true,\
+ $(LOCAL_ODM_MODULE) \
+ $(LOCAL_OEM_MODULE) \
+ $(LOCAL_PRODUCT_MODULE) \
+ $(LOCAL_PROPRIETARY_MODULE) \
+ $(LOCAL_VENDOR_MODULE))
+ enforce_rro_enabled := $(if $(non_rro_target_module),,true)
+ else ifneq ($(filter $(TARGET_OUT)/%,$(LOCAL_MODULE_PATH)),)
+ enforce_rro_enabled := true
+ endif
+ else ifneq (,$(filter $(LOCAL_PACKAGE_NAME), $(PRODUCT_ENFORCE_RRO_TARGETS)))
enforce_rro_enabled := true
endif
-else ifneq (,$(filter $(LOCAL_PACKAGE_NAME), $(PRODUCT_ENFORCE_RRO_TARGETS)))
- enforce_rro_enabled := true
endif
product_package_overlays := $(strip \
diff --git a/core/release_config.bzl b/core/release_config.bzl
new file mode 100644
index 0000000..e73c90f
--- /dev/null
+++ b/core/release_config.bzl
@@ -0,0 +1,90 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# 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.
+
+# Partitions that get build system flag summaries
+_flag_partitions = [
+ "product",
+ "system",
+ "system_ext",
+ "vendor",
+]
+
+def _combine_dicts_no_duplicate_keys(dicts):
+ result = {}
+ for d in dicts:
+ for k, v in d.items():
+ if k in result:
+ fail("Duplicate key: " + k)
+ result[k] = v
+ return result
+
+def release_config(target_release, flag_definitions, config_maps, fail_if_no_release_config = True):
+ result = {
+ "_ALL_RELEASE_FLAGS": [flag.name for flag in flag_definitions],
+ }
+ all_flags = {}
+ for flag in flag_definitions:
+ if sorted(dir(flag)) != ["default", "name", "partitions"]:
+ fail("Flag structs must contain 3 fields: name, partitions, and default")
+ if not flag.partitions:
+ fail("At least 1 partition is required")
+ for partition in flag.partitions:
+ if partition == "all":
+ if len(flag.partitions) > 1:
+ fail("\"all\" can't be combined with other partitions: " + str(flag.partitions))
+ elif partition not in _flag_partitions:
+ fail("Invalid partition: " + flag.partition + ", allowed partitions: " + str(_flag_partitions))
+ if not flag.name.startswith("RELEASE_"):
+ fail("Release flag names must start with RELEASE_")
+ if " " in flag.name or "\t" in flag.name or "\n" in flag.name:
+ fail("Flag names must not contain whitespace.")
+ if flag.name in all_flags:
+ fail("Duplicate declaration of flag " + flag.name)
+ all_flags[flag.name] = True
+
+ default = flag.default
+ if type(default) == "bool":
+ default = "true" if default else ""
+
+ result["_ALL_RELEASE_FLAGS." + flag.name + ".PARTITIONS"] = flag.partitions
+ result["_ALL_RELEASE_FLAGS." + flag.name + ".DEFAULT"] = default
+ result["_ALL_RELEASE_FLAGS." + flag.name + ".VALUE"] = default
+
+ # If TARGET_RELEASE is set, fail if there is no matching release config
+ # If it isn't set, no release config files will be included and all flags
+ # will get their default values.
+ if target_release:
+ config_map = _combine_dicts_no_duplicate_keys(config_maps)
+ if target_release not in config_map:
+ fail("No release config found for TARGET_RELEASE: " + target_release + ". Available releases are: " + str(config_map.keys()))
+ release_config = config_map[target_release]
+ if sorted(dir(release_config)) != ["flags", "release_version"]:
+ fail("A release config must be a struct with a flags and release_version fields")
+ result["_RELEASE_VERSION"] = release_config.release_version
+ for flag in release_config.flags:
+ if sorted(dir(release_config)) != ["name", "value"]:
+ fail("A flag be a struct with name and value fields")
+ if flag.name not in all_flags:
+ fail("Undeclared build flag: " + flag.name)
+ value = flag.value
+ if type(value) == "bool":
+ value = "true" if value else ""
+ result["_ALL_RELEASE_FLAGS." + flag.name + ".VALUE"] = value
+ elif fail_if_no_release_config:
+ fail("FAIL_IF_NO_RELEASE_CONFIG was set and TARGET_RELEASE was not")
+ else:
+ # No TARGET_RELEASE means release version 0
+ result["_RELEASE_VERSION"] = 0
+
+ return result
diff --git a/core/release_config.mk b/core/release_config.mk
index fdfc6a0..621c7d1 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -12,78 +12,45 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Partitions that get build system flag summaries
-_FLAG_PARTITIONS := system vendor system_ext product
-
-# All possible release flags. Defined in the build_flags.mk files
-# throughout the tree
-_ALL_RELEASE_FLAGS :=
-
-# -----------------------------------------------------------------
-# Choose the flag files
-# Do this first, because we're going to unset TARGET_RELEASE before
-# including anyone, so they don't start making conditionals based on it.
-
# If this is a google source tree, restrict it to only the one file
# which has OWNERS control. If it isn't let others define their own.
# TODO: Remove wildcard for build/release one when all branch manifests
# have updated.
-config_map_files := $(wildcard build/release/release_config_map.mk) \
- $(if $(wildcard vendor/google/release/release_config_map.mk), \
- vendor/google/release/release_config_map.mk, \
+flag_declaration_files := $(wildcard build/release/build_flags.bzl) \
+ $(if $(wildcard vendor/google/release/build_flags.bzl), \
+ vendor/google/release/build_flags.bzl, \
$(sort \
- $(wildcard device/*/release/release_config_map.mk) \
- $(wildcard device/*/*/release/release_config_map.mk) \
- $(wildcard vendor/*/release/release_config_map.mk) \
- $(wildcard vendor/*/*/release/release_config_map.mk) \
+ $(wildcard device/*/release/build_flags.bzl) \
+ $(wildcard device/*/*/release/build_flags.bzl) \
+ $(wildcard vendor/*/release/build_flags.bzl) \
+ $(wildcard vendor/*/*/release/build_flags.bzl) \
+ ) \
+ )
+config_map_files := $(wildcard build/release/release_config_map.bzl) \
+ $(if $(wildcard vendor/google/release/release_config_map.bzl), \
+ vendor/google/release/release_config_map.bzl, \
+ $(sort \
+ $(wildcard device/*/release/release_config_map.bzl) \
+ $(wildcard device/*/*/release/release_config_map.bzl) \
+ $(wildcard vendor/*/release/release_config_map.bzl) \
+ $(wildcard vendor/*/*/release/release_config_map.bzl) \
) \
)
-# $1 config name
-# $2 release config files
-define declare-release-config
- $(eval # No duplicates)
- $(if $(filter $(_all_release_configs), $(strip $(1))), \
- $(error declare-release-config: config $(strip $(1)) declared in: $(_included) Previously declared here: $(_all_release_configs.$(strip $(1)).DECLARED_IN)) \
- )
- $(eval # Must have release config files)
- $(if $(strip $(2)),, \
- $(error declare-release-config: config $(strip $(1)) must have release config files) \
- )
- $(eval _all_release_configs := $(sort $(_all_release_configs) $(strip $(1))))
- $(eval _all_release_configs.$(strip $(1)).DECLARED_IN := $(_included))
- $(eval _all_release_configs.$(strip $(1)).FILES := $(strip $(2)))
-endef
-
-# Include the config map files
-$(foreach f, $(config_map_files), \
- $(eval _included := $(f)) \
- $(eval include $(f)) \
-)
-
-# If TARGET_RELEASE is set, fail if there is no matching release config
-# If it isn't set, no release config files will be included and all flags
-# will get their default values.
-ifneq ($(TARGET_RELEASE),)
-ifeq ($(filter $(_all_release_configs), $(TARGET_RELEASE)),)
- $(error No release config found for TARGET_RELEASE: $(TARGET_RELEASE). Available releases are: $(_all_release_configs))
-else
- # Choose flag files
- # Don't sort this, use it in the order they gave us.
- _release_config_files := $(_all_release_configs.$(TARGET_RELEASE).FILES)
-endif
-else
-# Useful for finding scripts etc that aren't passing or setting TARGET_RELEASE
-ifneq ($(FAIL_IF_NO_RELEASE_CONFIG),)
- $(error FAIL_IF_NO_RELEASE_CONFIG was set and TARGET_RELEASE was not)
-endif
-_release_config_files :=
-endif
-
-# Unset variables so they can't use it
-define declare-release-config
-$(error declare-release-config can only be called from inside release_config_map.mk files)
-endef
+# Because starlark can't find files with $(wildcard), write an entrypoint starlark script that
+# contains the result of the above wildcards for the starlark code to use.
+filename_to_starlark=$(subst /,_,$(subst .,_,$(1)))
+_c:=load("//build/make/core/release_config.bzl", "release_config")
+_c+=$(foreach f,$(flag_declaration_files),$(newline)load("//$(f)", flags_$(call filename_to_starlark,$(f)) = "flags"))
+_c+=$(foreach f,$(config_map_files),$(newline)load("//$(f)", config_maps_$(call filename_to_starlark,$(f)) = "config_maps"))
+_c+=$(newline)all_flags = [] $(foreach f,$(flag_declaration_files),+ flags_$(call filename_to_starlark,$(f)))
+_c+=$(newline)all_config_maps = [$(foreach f,$(config_map_files),config_maps_$(call filename_to_starlark,$(f))$(comma))]
+_c+=$(newline)target_release = "$(TARGET_RELEASE)"
+_c+=$(newline)fail_if_no_release_config = True if "$(FAIL_IF_NO_RELEASE_CONFIG)" else False
+_c+=$(newline)variables_to_export_to_make = release_config(target_release, all_flags, all_config_maps, fail_if_no_release_config)
+$(file >$(OUT_DIR)/release_config_entrypoint.bzl,$(_c))
+_c:=
+filename_to_starlark:=
# TODO: Remove this check after enough people have sourced lunch that we don't
# need to worry about it trying to do get_build_vars TARGET_RELEASE. Maybe after ~9/2023
@@ -96,127 +63,7 @@
endif
.KATI_READONLY := TARGET_RELEASE
-$(foreach config, $(_all_release_configs), \
- $(eval _all_release_configs.$(config).DECLARED_IN:= ) \
- $(eval _all_release_configs.$(config).FILES:= ) \
-)
-_all_release_configs:=
-config_map_files:=
-
-# -----------------------------------------------------------------
-# Declare the flags
-
-# $1 partition(s)
-# $2 flag name. Must start with RELEASE_
-# $3 default. True or false
-define declare-build-flag
- $(if $(filter-out all $(_FLAG_PARTITIONS), $(strip $(1))), \
- $(error declare-build-flag: invalid partitions: $(strip $(1))) \
- )
- $(if $(and $(filter all,$(strip $(1))),$(filter-out all, $(strip $(1)))), \
- $(error declare-build-flag: "all" can't be combined with other partitions: $(strip $(1))), \
- $(eval declare-build-flag.partition := $(_FLAG_PARTITIONS)) \
- )
- $(if $(filter-out RELEASE_%, $(strip $(2))), \
- $(error declare-build-flag: Release flag names must start with RELEASE_: $(strip $(2))) \
- )
- $(eval _ALL_RELEASE_FLAGS += $(strip $(2)))
- $(foreach partition, $(declare-build-flag.partition), \
- $(eval _ALL_RELEASE_FLAGS.PARTITIONS.$(partition) := $(sort \
- $(_ALL_RELEASE_FLAGS.PARTITIONS.$(partition)) $(strip $(2)))) \
- )
- $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).PARTITIONS := $(declare-build-flag.partition))
- $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).DEFAULT := $(strip $(3)))
- $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).DECLARED_IN := $(_included))
- $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).VALUE := $(strip $(3)))
- $(eval _ALL_RELEASE_FLAGS.$(strip $(2)).SET_IN := $(_included))
- $(eval declare-build-flag.partition:=)
-endef
-
-
-# Choose the files
-# If this is a google source tree, restrict it to only the one file
-# which has OWNERS control. If it isn't let others define their own.
-flag_declaration_files := $(wildcard build/release/build_flags.mk) \
- $(if $(wildcard vendor/google/release/build_flags.mk), \
- vendor/google/release/build_flags.mk, \
- $(sort \
- $(wildcard device/*/release/build_flags.mk) \
- $(wildcard device/*/*/release/build_flags.mk) \
- $(wildcard vendor/*/release/build_flags.mk) \
- $(wildcard vendor/*/*/release/build_flags.mk) \
- ) \
- )
-
-# Include the files
-$(foreach f, $(flag_declaration_files), \
- $(eval _included := $(f)) \
- $(eval include $(f)) \
-)
-
-# Don't let anyone declare build flags after here
-define declare-build-flag
-$(error declare-build-flag can only be called from inside flag definition files.)
-endef
-
-# No more flags from here on
-.KATI_READONLY := _ALL_RELEASE_FLAGS
-
-# -----------------------------------------------------------------
-# Set the flags
-
-# $(1): Flag name. Must start with RELEASE_ and have been defined by declare-build-flag
-# $(2): Value. True or false
-define set-build-flag
- $(if $(filter-out $(_ALL_RELEASE_FLAGS), $(strip $(1))), \
- $(error set-build-flag: Undeclared build flag: $(strip $(1))) \
- )
- $(eval _ALL_RELEASE_FLAGS.$(strip $(1)).VALUE := $(strip $(2)))
- $(eval _ALL_RELEASE_FLAGS.$(strip $(1)).SET_IN := $(_included))
-endef
-
-# This writes directly to a file so that the version never exists in make for
-# people to write conditionals upon.
-define set-release-version
- $(eval _RELEASE_VERSION := $(strip $(1)))
-endef
-
-# Include the files (if there are any)
-ifneq ($(strip $(_release_config_files)),)
- $(foreach f, $(_release_config_files), \
- $(eval _included := $(f)) \
- $(eval include $(f)) \
- )
-else
- # No TARGET_RELEASE means release version 0
- $(call set-release-version, 0)
-endif
-
-
-ifeq ($(_RELEASE_VERSION)),)
- $(error No release config file called set-release-version. Included files were: $(_release_config_files))
-endif
-
-# Don't let anyone declare build flags after here
-define set-build-flag
-$(error set-build-flag can only be called from inside release config files.)
-endef
-
-# Don't let anyone set the release version after here
-define set-release-version
-$(error set-release-version can only be called from inside release config files.)
-endef
-
-# Set the flag values, and don't allow any one to modify them.
-$(foreach flag, $(_ALL_RELEASE_FLAGS), \
- $(eval $(flag) := $(_ALL_RELEASE_FLAGS.$(flag).VALUE)) \
- $(eval .KATI_READONLY := $(flag)) \
-)
-
-
-# -----------------------------------------------------------------
-# Clear out vars
-flag_declaration_files:=
-flag_files:=
-_included:=
-_release_config_files:=
+# Exclude the entrypoint file as a dependency (by passing it as the 2nd argument) so that we don't
+# rerun kati every build. Kati will replay the $(file) command that generates it every build,
+# updating its timestamp.
+$(call run-starlark,$(OUT_DIR)/release_config_entrypoint.bzl,$(OUT_DIR)/release_config_entrypoint.bzl)
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index dd550b5..ccc5449 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -239,26 +239,28 @@
include $(BUILD_SYSTEM)/link_type.mk
endif # !LOCAL_IS_HOST_MODULE
-ifdef LOCAL_SOONG_DEVICE_RRO_DIRS
- $(call append_enforce_rro_sources, \
- $(my_register_name), \
- false, \
- $(LOCAL_FULL_MANIFEST_FILE), \
- $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
- $(LOCAL_SOONG_DEVICE_RRO_DIRS), \
- vendor \
- )
-endif
+ifeq (,$(filter tests,$(LOCAL_MODULE_TAGS)))
+ ifdef LOCAL_SOONG_DEVICE_RRO_DIRS
+ $(call append_enforce_rro_sources, \
+ $(my_register_name), \
+ false, \
+ $(LOCAL_FULL_MANIFEST_FILE), \
+ $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
+ $(LOCAL_SOONG_DEVICE_RRO_DIRS), \
+ vendor \
+ )
+ endif
-ifdef LOCAL_SOONG_PRODUCT_RRO_DIRS
- $(call append_enforce_rro_sources, \
- $(my_register_name), \
- false, \
- $(LOCAL_FULL_MANIFEST_FILE), \
- $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
- $(LOCAL_SOONG_PRODUCT_RRO_DIRS), \
- product \
- )
+ ifdef LOCAL_SOONG_PRODUCT_RRO_DIRS
+ $(call append_enforce_rro_sources, \
+ $(my_register_name), \
+ false, \
+ $(LOCAL_FULL_MANIFEST_FILE), \
+ $(if $(LOCAL_EXPORT_PACKAGE_RESOURCES),true,false), \
+ $(LOCAL_SOONG_PRODUCT_RRO_DIRS), \
+ product \
+ )
+ endif
endif
ifdef LOCAL_PREBUILT_COVERAGE_ARCHIVE
@@ -273,4 +275,4 @@
###########################################################
## SBOM generation
###########################################################
-include $(BUILD_SBOM_GEN)
\ No newline at end of file
+include $(BUILD_SBOM_GEN)
diff --git a/envsetup.sh b/envsetup.sh
index ef48249..d292dbb 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -312,7 +312,7 @@
# would prevent exporting type info from those packages.
#
# http://b/266688086
- export ANDROID_PYTHONPATH=$T/development/python-packages/adb:$T/development/python-packages:
+ export ANDROID_PYTHONPATH=$T/development/python-packages/adb:$T/development/python-packages/gdbrunner:$T/development/python-packages:
if [ -n $VENDOR_PYTHONPATH ]; then
ANDROID_PYTHONPATH=$ANDROID_PYTHONPATH$VENDOR_PYTHONPATH
fi
diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs
new file mode 100644
index 0000000..cb266f1
--- /dev/null
+++ b/tools/aconfig/src/codegen_cpp.rs
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+use anyhow::Result;
+use serde::Serialize;
+use tinytemplate::TinyTemplate;
+
+use crate::aconfig::{FlagState, Permission};
+use crate::cache::{Cache, Item};
+use crate::commands::OutputFile;
+
+pub fn generate_cpp_code(cache: &Cache) -> Result<OutputFile> {
+ let class_elements: Vec<ClassElement> = cache.iter().map(create_class_element).collect();
+ let readwrite = class_elements.iter().any(|item| item.readwrite);
+ let namespace = cache.namespace().to_lowercase();
+ let context = Context { namespace: namespace.clone(), readwrite, class_elements };
+ let mut template = TinyTemplate::new();
+ template.add_template("cpp_code_gen", include_str!("../templates/cpp.template"))?;
+ let contents = template.render("cpp_code_gen", &context)?;
+ let path = ["aconfig", &(namespace + ".h")].iter().collect();
+ Ok(OutputFile { contents: contents.into(), path })
+}
+
+#[derive(Serialize)]
+struct Context {
+ pub namespace: String,
+ pub readwrite: bool,
+ pub class_elements: Vec<ClassElement>,
+}
+
+#[derive(Serialize)]
+struct ClassElement {
+ pub readwrite: bool,
+ pub default_value: String,
+ pub flag_name: String,
+}
+
+fn create_class_element(item: &Item) -> ClassElement {
+ ClassElement {
+ readwrite: item.permission == Permission::ReadWrite,
+ default_value: if item.state == FlagState::Enabled {
+ "true".to_string()
+ } else {
+ "false".to_string()
+ },
+ flag_name: item.name.clone(),
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::aconfig::{FlagDeclaration, FlagState, FlagValue, Permission};
+ use crate::commands::Source;
+
+ #[test]
+ fn test_cpp_codegen_build_time_flag_only() {
+ let namespace = "my_namespace";
+ let mut cache = Cache::new(namespace.to_string()).unwrap();
+ cache
+ .add_flag_declaration(
+ Source::File("aconfig_one.txt".to_string()),
+ FlagDeclaration {
+ name: "my_flag_one".to_string(),
+ description: "buildtime disable".to_string(),
+ },
+ )
+ .unwrap();
+ cache
+ .add_flag_value(
+ Source::Memory,
+ FlagValue {
+ namespace: namespace.to_string(),
+ name: "my_flag_one".to_string(),
+ state: FlagState::Disabled,
+ permission: Permission::ReadOnly,
+ },
+ )
+ .unwrap();
+ cache
+ .add_flag_declaration(
+ Source::File("aconfig_two.txt".to_string()),
+ FlagDeclaration {
+ name: "my_flag_two".to_string(),
+ description: "buildtime enable".to_string(),
+ },
+ )
+ .unwrap();
+ cache
+ .add_flag_value(
+ Source::Memory,
+ FlagValue {
+ namespace: namespace.to_string(),
+ name: "my_flag_two".to_string(),
+ state: FlagState::Enabled,
+ permission: Permission::ReadOnly,
+ },
+ )
+ .unwrap();
+ let expect_content = r#"#ifndef my_namespace_HEADER_H
+ #define my_namespace_HEADER_H
+ #include "my_namespace.h"
+
+ namespace my_namespace {
+
+ class my_flag_one {
+ public:
+ virtual const bool value() {
+ return false;
+ }
+ }
+
+ class my_flag_two {
+ public:
+ virtual const bool value() {
+ return true;
+ }
+ }
+
+ }
+ #endif
+ "#;
+ let file = generate_cpp_code(&cache).unwrap();
+ assert_eq!("aconfig/my_namespace.h", file.path.to_str().unwrap());
+ assert_eq!(
+ expect_content.replace(' ', ""),
+ String::from_utf8(file.contents).unwrap().replace(' ', "")
+ );
+ }
+
+ #[test]
+ fn test_cpp_codegen_runtime_flag() {
+ let namespace = "my_namespace";
+ let mut cache = Cache::new(namespace.to_string()).unwrap();
+ cache
+ .add_flag_declaration(
+ Source::File("aconfig_one.txt".to_string()),
+ FlagDeclaration {
+ name: "my_flag_one".to_string(),
+ description: "buildtime disable".to_string(),
+ },
+ )
+ .unwrap();
+ cache
+ .add_flag_declaration(
+ Source::File("aconfig_two.txt".to_string()),
+ FlagDeclaration {
+ name: "my_flag_two".to_string(),
+ description: "runtime enable".to_string(),
+ },
+ )
+ .unwrap();
+ cache
+ .add_flag_value(
+ Source::Memory,
+ FlagValue {
+ namespace: namespace.to_string(),
+ name: "my_flag_two".to_string(),
+ state: FlagState::Enabled,
+ permission: Permission::ReadWrite,
+ },
+ )
+ .unwrap();
+ let expect_content = r#"#ifndef my_namespace_HEADER_H
+ #define my_namespace_HEADER_H
+ #include "my_namespace.h"
+
+ #include <server_configurable_flags/get_flags.h>
+ using namespace server_configurable_flags;
+
+ namespace my_namespace {
+
+ class my_flag_one {
+ public:
+ virtual const bool value() {
+ return GetServerConfigurableFlag(
+ "my_namespace",
+ "my_flag_one",
+ "false") == "true";
+ }
+ }
+
+ class my_flag_two {
+ public:
+ virtual const bool value() {
+ return GetServerConfigurableFlag(
+ "my_namespace",
+ "my_flag_two",
+ "true") == "true";
+ }
+ }
+
+ }
+ #endif
+ "#;
+ let file = generate_cpp_code(&cache).unwrap();
+ assert_eq!("aconfig/my_namespace.h", file.path.to_str().unwrap());
+ assert_eq!(
+ expect_content.replace(' ', ""),
+ String::from_utf8(file.contents).unwrap().replace(' ', "")
+ );
+ }
+}
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index 324f7d5..0bdb0b5 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -24,6 +24,7 @@
use crate::aconfig::{FlagDeclarations, FlagValue};
use crate::cache::Cache;
+use crate::codegen_cpp::generate_cpp_code;
use crate::codegen_java::generate_java_code;
use crate::protos::ProtoParsedFlags;
@@ -91,10 +92,14 @@
Ok(cache)
}
-pub fn generate_code(cache: &Cache) -> Result<OutputFile> {
+pub fn create_java_lib(cache: &Cache) -> Result<OutputFile> {
generate_java_code(cache)
}
+pub fn create_cpp_lib(cache: &Cache) -> Result<OutputFile> {
+ generate_cpp_code(cache)
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum DumpFormat {
Text,
diff --git a/tools/aconfig/src/main.rs b/tools/aconfig/src/main.rs
index e1e9166..6db5948 100644
--- a/tools/aconfig/src/main.rs
+++ b/tools/aconfig/src/main.rs
@@ -26,6 +26,7 @@
mod aconfig;
mod cache;
+mod codegen_cpp;
mod codegen_java;
mod commands;
mod protos;
@@ -49,6 +50,11 @@
.arg(Arg::new("out").long("out").required(true)),
)
.subcommand(
+ Command::new("create-cpp-lib")
+ .arg(Arg::new("cache").long("cache").required(true))
+ .arg(Arg::new("out").long("out").required(true)),
+ )
+ .subcommand(
Command::new("dump")
.arg(Arg::new("cache").long("cache").required(true))
.arg(
@@ -112,7 +118,15 @@
let file = fs::File::open(path)?;
let cache = Cache::read_from_reader(file)?;
let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
- let generated_file = commands::generate_code(&cache)?;
+ let generated_file = commands::create_java_lib(&cache)?;
+ write_output_file_realtive_to_dir(&dir, &generated_file)?;
+ }
+ Some(("create-cpp-lib", sub_matches)) => {
+ let path = get_required_arg::<String>(sub_matches, "cache")?;
+ let file = fs::File::open(path)?;
+ let cache = Cache::read_from_reader(file)?;
+ let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
+ let generated_file = commands::create_cpp_lib(&cache)?;
write_output_file_realtive_to_dir(&dir, &generated_file)?;
}
Some(("dump", sub_matches)) => {
diff --git a/tools/aconfig/templates/cpp.template b/tools/aconfig/templates/cpp.template
new file mode 100644
index 0000000..ae8b59f
--- /dev/null
+++ b/tools/aconfig/templates/cpp.template
@@ -0,0 +1,25 @@
+#ifndef {namespace}_HEADER_H
+#define {namespace}_HEADER_H
+#include "{namespace}.h"
+{{ if readwrite }}
+#include <server_configurable_flags/get_flags.h>
+using namespace server_configurable_flags;
+{{ endif }}
+namespace {namespace} \{
+ {{ for item in class_elements}}
+ class {item.flag_name} \{
+ public:
+ virtual const bool value() \{
+ {{ if item.readwrite- }}
+ return GetServerConfigurableFlag(
+ "{namespace}",
+ "{item.flag_name}",
+ "{item.default_value}") == "true";
+ {{ -else- }}
+ return {item.default_value};
+ {{ -endif }}
+ }
+ }
+ {{ endfor }}
+}
+#endif
diff --git a/tools/sbom/generate-sbom.py b/tools/sbom/generate-sbom.py
index 56509c9..2415f7e 100755
--- a/tools/sbom/generate-sbom.py
+++ b/tools/sbom/generate-sbom.py
@@ -19,7 +19,6 @@
Usage example:
generate-sbom.py --output_file out/target/product/vsoc_x86_64/sbom.spdx \
--metadata out/target/product/vsoc_x86_64/sbom-metadata.csv \
- --product_out_dir=out/target/product/vsoc_x86_64 \
--build_version $(cat out/target/product/vsoc_x86_64/build_fingerprint.txt) \
--product_mfr=Google
"""
@@ -89,11 +88,11 @@
parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Print more information.')
parser.add_argument('--output_file', required=True, help='The generated SBOM file in SPDX format.')
parser.add_argument('--metadata', required=True, help='The SBOM metadata file path.')
- parser.add_argument('--product_out_dir', required=True, help='The parent directory of all the installed files.')
parser.add_argument('--build_version', required=True, help='The build version.')
parser.add_argument('--product_mfr', required=True, help='The product manufacturer.')
parser.add_argument('--json', action='store_true', default=False, help='Generated SBOM file in SPDX JSON format')
- parser.add_argument('--unbundled', action='store_true', default=False, help='Generate SBOM file for unbundled module')
+ parser.add_argument('--unbundled_apk', action='store_true', default=False, help='Generate SBOM for unbundled APKs')
+ parser.add_argument('--unbundled_apex', action='store_true', default=False, help='Generate SBOM for unbundled APEXs')
return parser.parse_args()
@@ -127,7 +126,6 @@
def checksum(file_path):
- file_path = args.product_out_dir + '/' + file_path
h = hashlib.sha1()
if os.path.islink(file_path):
h.update(os.readlink(file_path).encode('utf-8'))
@@ -265,8 +263,8 @@
def get_sbom_fragments(installed_file_metadata, metadata_file_path):
"""Return SPDX fragment of source/prebuilt packages, which usually contains a SOURCE/PREBUILT
- package, a UPSTREAM package if it's a source package and a external SBOM document reference if
- it's a prebuilt package with sbom_ref defined in its METADATA file.
+ package, a UPSTREAM package and an external SBOM document reference if sbom_ref defined in its
+ METADATA file.
See go/android-spdx and go/android-sbom-gen for more details.
"""
@@ -303,25 +301,33 @@
prebuilt_package = sbom_data.Package(id=prebuilt_package_id,
name=name,
download_location=sbom_data.VALUE_NONE,
- version=args.build_version,
+ version=version if version else args.build_version,
supplier='Organization: ' + args.product_mfr)
- packages.append(prebuilt_package)
- if metadata_file_path:
- metadata_proto = metadata_file_protos[metadata_file_path]
- if metadata_proto.third_party.WhichOneof('sbom') == 'sbom_ref':
- sbom_url = metadata_proto.third_party.sbom_ref.url
- sbom_checksum = metadata_proto.third_party.sbom_ref.checksum
- upstream_element_id = metadata_proto.third_party.sbom_ref.element_id
- if sbom_url and sbom_checksum and upstream_element_id:
- doc_ref_id = f'DocumentRef-{PKG_UPSTREAM}-{encode_for_spdxid(name)}'
- external_doc_ref = sbom_data.DocumentExternalReference(id=doc_ref_id,
- uri=sbom_url,
- checksum=sbom_checksum)
- relationships.append(
- sbom_data.Relationship(id1=prebuilt_package_id,
- relationship=sbom_data.RelationshipType.VARIANT_OF,
- id2=doc_ref_id + ':' + upstream_element_id))
+ upstream_package_id = new_package_id(name, PKG_UPSTREAM)
+ upstream_package = sbom_data.Package(id=upstream_package_id, name=name, version = version,
+ supplier=('Organization: ' + homepage) if homepage else sbom_data.VALUE_NOASSERTION,
+ download_location=download_location)
+ packages += [prebuilt_package, upstream_package]
+ relationships.append(sbom_data.Relationship(id1=prebuilt_package_id,
+ relationship=sbom_data.RelationshipType.VARIANT_OF,
+ id2=upstream_package_id))
+
+ if metadata_file_path:
+ metadata_proto = metadata_file_protos[metadata_file_path]
+ if metadata_proto.third_party.WhichOneof('sbom') == 'sbom_ref':
+ sbom_url = metadata_proto.third_party.sbom_ref.url
+ sbom_checksum = metadata_proto.third_party.sbom_ref.checksum
+ upstream_element_id = metadata_proto.third_party.sbom_ref.element_id
+ if sbom_url and sbom_checksum and upstream_element_id:
+ doc_ref_id = f'DocumentRef-{PKG_UPSTREAM}-{encode_for_spdxid(name)}'
+ external_doc_ref = sbom_data.DocumentExternalReference(id=doc_ref_id,
+ uri=sbom_url,
+ checksum=sbom_checksum)
+ relationships.append(
+ sbom_data.Relationship(id1=upstream_package_id,
+ relationship=sbom_data.RelationshipType.VARIANT_OF,
+ id2=doc_ref_id + ':' + upstream_element_id))
return external_doc_ref, packages, relationships
@@ -334,9 +340,8 @@
return h.hexdigest()
-def save_report(report):
- prefix, _ = os.path.splitext(args.output_file)
- with open(prefix + '-gen-report.txt', 'w', encoding='utf-8') as report_file:
+def save_report(report_file_path, report):
+ with open(report_file_path, 'w', encoding='utf-8') as report_file:
for type, issues in report.items():
report_file.write(type + '\n')
for issue in issues:
@@ -394,7 +399,7 @@
installed_file_metadata['installed_file'], installed_file_metadata['module_path']))
-def generate_sbom_for_unbundled():
+def generate_sbom_for_unbundled_apk():
with open(args.metadata, newline='') as sbom_metadata_file:
reader = csv.DictReader(sbom_metadata_file)
doc = sbom_data.Document(name=args.build_version,
@@ -402,7 +407,7 @@
creators=['Organization: ' + args.product_mfr])
for installed_file_metadata in reader:
installed_file = installed_file_metadata['installed_file']
- if args.output_file != args.product_out_dir + installed_file + '.spdx.json':
+ if args.output_file != installed_file_metadata['build_output_path'] + '.spdx.json':
continue
module_path = installed_file_metadata['module_path']
@@ -412,7 +417,9 @@
version=args.build_version,
supplier='Organization: ' + args.product_mfr)
file_id = new_file_id(installed_file)
- file = sbom_data.File(id=file_id, name=installed_file, checksum=checksum(installed_file))
+ file = sbom_data.File(id=file_id,
+ name=installed_file,
+ checksum=checksum(installed_file_metadata['build_output_path']))
relationship = sbom_data.Relationship(id1=file_id,
relationship=sbom_data.RelationshipType.GENERATED_FROM,
id2=package_id)
@@ -435,24 +442,25 @@
args = get_args()
log('Args:', vars(args))
- if args.unbundled:
- generate_sbom_for_unbundled()
+ if args.unbundled_apk:
+ generate_sbom_for_unbundled_apk()
return
global metadata_file_protos
metadata_file_protos = {}
- doc = sbom_data.Document(name=args.build_version,
- namespace=f'https://www.google.com/sbom/spdx/android/{args.build_version}',
- creators=['Organization: ' + args.product_mfr])
-
product_package = sbom_data.Package(id=sbom_data.SPDXID_PRODUCT,
name=sbom_data.PACKAGE_NAME_PRODUCT,
download_location=sbom_data.VALUE_NONE,
version=args.build_version,
supplier='Organization: ' + args.product_mfr,
files_analyzed=True)
- doc.packages.append(product_package)
+
+ doc = sbom_data.Document(name=args.build_version,
+ namespace=f'https://www.google.com/sbom/spdx/android/{args.build_version}',
+ creators=['Organization: ' + args.product_mfr])
+ if not args.unbundled_apex:
+ doc.packages.append(product_package)
doc.packages.append(sbom_data.Package(id=sbom_data.SPDXID_PLATFORM,
name=sbom_data.PACKAGE_NAME_PLATFORM,
@@ -478,18 +486,21 @@
module_path = installed_file_metadata['module_path']
product_copy_files = installed_file_metadata['product_copy_files']
kernel_module_copy_files = installed_file_metadata['kernel_module_copy_files']
+ build_output_path = installed_file_metadata['build_output_path']
if not installed_file_has_metadata(installed_file_metadata, report):
continue
- file_path = args.product_out_dir + '/' + installed_file
- if not (os.path.islink(file_path) or os.path.isfile(file_path)):
+ if not (os.path.islink(build_output_path) or os.path.isfile(build_output_path)):
report[ISSUE_INSTALLED_FILE_NOT_EXIST].append(installed_file)
continue
file_id = new_file_id(installed_file)
doc.files.append(
- sbom_data.File(id=file_id, name=installed_file, checksum=checksum(installed_file)))
- product_package.file_ids.append(file_id)
+ sbom_data.File(id=file_id, name=installed_file, checksum=checksum(build_output_path)))
+ if not args.unbundled_apex:
+ product_package.file_ids.append(file_id)
+ elif len(doc.files) > 1:
+ doc.add_relationship(sbom_data.Relationship(doc.files[0].id, sbom_data.RelationshipType.CONTAINS, file_id))
if is_source_package(installed_file_metadata) or is_prebuilt_package(installed_file_metadata):
metadata_file_path = get_metadata_file_path(installed_file_metadata)
@@ -533,16 +544,31 @@
relationship=sbom_data.RelationshipType.GENERATED_FROM,
id2=sbom_data.SPDXID_PLATFORM))
- product_package.verification_code = generate_package_verification_code(doc.files)
+ if not args.unbundled_apex:
+ product_package.verification_code = generate_package_verification_code(doc.files)
+
+ if args.unbundled_apex:
+ doc.describes = doc.files[0].id
# Save SBOM records to output file
doc.created = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
- with open(args.output_file, 'w', encoding="utf-8") as file:
- sbom_writers.TagValueWriter.write(doc, file)
+ prefix = args.output_file
+ if prefix.endswith('.spdx'):
+ prefix = prefix.removesuffix('.spdx')
+ elif prefix.endswith('.spdx.json'):
+ prefix = prefix.removesuffix('.spdx.json')
+
+ output_file = prefix + '.spdx'
+ if args.unbundled_apex:
+ output_file = prefix + '-fragment.spdx'
+ with open(output_file, 'w', encoding="utf-8") as file:
+ sbom_writers.TagValueWriter.write(doc, file, fragment=args.unbundled_apex)
if args.json:
- with open(args.output_file+'.json', 'w', encoding="utf-8") as file:
+ with open(prefix + '.spdx.json', 'w', encoding="utf-8") as file:
sbom_writers.JSONWriter.write(doc, file)
+ save_report(prefix + '-gen-report.txt', report)
+
if __name__ == '__main__':
main()
diff --git a/tools/sbom/sbom_data.py b/tools/sbom/sbom_data.py
index d2ef48d..14c4eb2 100644
--- a/tools/sbom/sbom_data.py
+++ b/tools/sbom/sbom_data.py
@@ -80,6 +80,7 @@
DESCRIBES = 'DESCRIBES'
VARIANT_OF = 'VARIANT_OF'
GENERATED_FROM = 'GENERATED_FROM'
+ CONTAINS = 'CONTAINS'
@dataclass
diff --git a/tools/sbom/sbom_writers.py b/tools/sbom/sbom_writers.py
index b1c66c5..85dee9d 100644
--- a/tools/sbom/sbom_writers.py
+++ b/tools/sbom/sbom_writers.py
@@ -110,24 +110,26 @@
return tagvalues
@staticmethod
- def marshal_described_element(sbom_doc):
+ def marshal_described_element(sbom_doc, fragment):
if not sbom_doc.describes:
return None
product_package = [p for p in sbom_doc.packages if p.id == sbom_doc.describes]
if product_package:
tagvalues = TagValueWriter.marshal_package(product_package[0])
- tagvalues.append(
- f'{Tags.RELATIONSHIP}: {sbom_doc.id} {sbom_data.RelationshipType.DESCRIBES} {sbom_doc.describes}')
+ if not fragment:
+ tagvalues.append(
+ f'{Tags.RELATIONSHIP}: {sbom_doc.id} {sbom_data.RelationshipType.DESCRIBES} {sbom_doc.describes}')
tagvalues.append('')
return tagvalues
file = [f for f in sbom_doc.files if f.id == sbom_doc.describes]
if file:
- tagvalues = [
- f'{Tags.RELATIONSHIP}: {sbom_doc.id} {sbom_data.RelationshipType.DESCRIBES} {sbom_doc.describes}'
- ]
+ tagvalues = TagValueWriter.marshal_file(file[0])
+ if not fragment:
+ tagvalues.append(
+ f'{Tags.RELATIONSHIP}: {sbom_doc.id} {sbom_data.RelationshipType.DESCRIBES} {sbom_doc.describes}')
return tagvalues
@@ -180,6 +182,8 @@
def marshal_files(sbom_doc):
tagvalues = []
for file in sbom_doc.files:
+ if file.id == sbom_doc.describes:
+ continue
tagvalues += TagValueWriter.marshal_file(file)
return tagvalues
@@ -204,9 +208,9 @@
content = []
if not fragment:
content += TagValueWriter.marshal_doc_headers(sbom_doc)
- described_element = TagValueWriter.marshal_described_element(sbom_doc)
- if described_element:
- content += described_element
+ described_element = TagValueWriter.marshal_described_element(sbom_doc, fragment)
+ if described_element:
+ content += described_element
content += TagValueWriter.marshal_files(sbom_doc)
tagvalues, marshaled_relationships = TagValueWriter.marshal_packages(sbom_doc)
content += tagvalues