Many places in the codebase have checks like this: if shipping level > X: do cool thing Y This is great because it reduces the cost to upgrade and test old Android devices or refactor their code. However, many targets, such as the NDK, the SDK, mainline modules, and so on do not set a shipping level, so they don't get to do the cool thing Y. In order to resolve this, we could modify every check to check the default case. However, this is an invasive change, and it is not maintainable. Instead, consider non-shipping products to always be in the future. In general, Android features are required to be backwards compatible, so this should always work for things like mainline. Also note, this means when someone adds a new feature Y like this, they'll clearly see the impact of it being added everywhere, rather than on such a small selection of newly shipping devices. This avoids a risk where a change needs to be run on mainline modules (or other targets) but is not tested in this configuration from the start. Future work: many `ifndef` checks can be cleaned up after this, or if this approach makes sense, they can be cleaned up in this CL. Bug: 339026799 Bug: 279808973 Bug: 333908433 Test: builds of: - errorprone-trunk_staging - mainline_modules_sdks-trunk_staging-userdebug - mainline_modules_x86_64-trunk_staging-userdebug - ndk - sdk-trunk_staging-userdebug Test: too large number gives: build/make/core/product_config.mk:598: error: integer greater than 10001 is not supported!. Change-Id: I17c34267f774ea8b9265e1d798a67af7838715c5
416 lines
16 KiB
Makefile
416 lines
16 KiB
Makefile
#
|
|
# Copyright (C) 2017 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.
|
|
#
|
|
|
|
###########################################################
|
|
# Basic math functions for non-negative integers <= 100
|
|
#
|
|
# (SDK versions for example)
|
|
###########################################################
|
|
__MATH_POS_NUMBERS := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
|
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
|
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
|
|
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
|
__MATH_NUMBERS := 0 $(__MATH_POS_NUMBERS)
|
|
__MATH_ONE_NUMBERS := 0 1 2 3 4 5 6 7 8 9
|
|
|
|
math-error = $(call pretty-error,$(1))
|
|
math-expect :=
|
|
math-expect-true :=
|
|
math-expect :=
|
|
math-expect-error :=
|
|
|
|
# Run the math tests with:
|
|
# make -f ${ANDROID_BUILD_TOP}/build/make/common/math.mk RUN_MATH_TESTS=true
|
|
# $(get_build_var CKATI) -f ${ANDROID_BUILD_TOP}//build/make/common/math.mk RUN_MATH_TESTS=true
|
|
ifdef RUN_MATH_TESTS
|
|
ifndef empty
|
|
empty :=
|
|
space := $(empty) $(empty)
|
|
endif
|
|
MATH_TEST_FAILURE :=
|
|
MATH_TEST_ERROR :=
|
|
math-error = $(if $(MATH_TEST_ERROR),,$(eval MATH_TEST_ERROR:=$(1)))
|
|
define math-expect
|
|
$(eval got:=$$$1) \
|
|
$(if $(subst $(got),,$(2))$(subst $(2),,$(got))$(MATH_TEST_ERROR), \
|
|
$(if $(MATH_TEST_ERROR),$(warning $(MATH_TEST_ERROR)),$(warning $$$1 '$(got)' != '$(2)')) \
|
|
$(eval MATH_TEST_FAILURE := true)) \
|
|
$(eval MATH_TEST_ERROR :=) \
|
|
$(eval got:=)
|
|
endef
|
|
math-expect-true = $(call math-expect,$(1),true)
|
|
math-expect-false = $(call math-expect,$(1),)
|
|
|
|
define math-expect-error
|
|
$(eval got:=$$$1) \
|
|
$(if $(subst $(MATH_TEST_ERROR),,$(2))$(subst $(2),,$(MATH_TEST_ERROR)), \
|
|
$(warning '$(MATH_TEST_ERROR)' != '$(2)') \
|
|
$(eval MATH_TEST_FAILURE := true)) \
|
|
$(eval MATH_TEST_ERROR :=) \
|
|
$(eval got:=)
|
|
endef
|
|
endif
|
|
|
|
# Returns true if $(1) is a non-negative integer <= 100, otherwise returns nothing.
|
|
define math_is_number_in_100
|
|
$(strip \
|
|
$(if $(1),,$(call math-error,Argument missing)) \
|
|
$(if $(word 2,$(1)),$(call math-error,Multiple words in a single argument: $(1))) \
|
|
$(if $(filter $(1),$(__MATH_NUMBERS)),true))
|
|
endef
|
|
|
|
# Same with math_is_number_in_100, but no limit.
|
|
define _math_ext_is_number
|
|
$(strip \
|
|
$(if $(1),,$(call math-error,Argument missing)) \
|
|
$(if $(word 2,$(1)),$(call math-error,Multiple words in a single argument: $(1))) \
|
|
$(eval should_empty:=$(1)) \
|
|
$(foreach num,$(__MATH_ONE_NUMBERS),\
|
|
$(eval should_empty:=$(subst $(num),$(empty),$(should_empty)))) \
|
|
$(if $(should_empty),,true))
|
|
endef
|
|
|
|
# Returns true if $(1) is a non-negative integer.
|
|
define math_is_number
|
|
$(strip $(if $(call math_is_number_in_100,$(1)),true,$(call _math_ext_is_number,$(1))))
|
|
endef
|
|
|
|
define math_is_zero
|
|
$(strip \
|
|
$(if $(word 2,$(1)),$(call math-error,Multiple words in a single argument: $(1))) \
|
|
$(if $(filter 0,$(1)),true))
|
|
endef
|
|
|
|
$(call math-expect-true,(call math_is_number,0))
|
|
$(call math-expect-true,(call math_is_number,2))
|
|
$(call math-expect-true,(call math_is_number,202412))
|
|
$(call math-expect-false,(call math_is_number,foo))
|
|
$(call math-expect-false,(call math_is_number,-1))
|
|
$(call math-expect-error,(call math_is_number,1 2),Multiple words in a single argument: 1 2)
|
|
$(call math-expect-error,(call math_is_number,no 2),Multiple words in a single argument: no 2)
|
|
|
|
$(call math-expect-true,(call math_is_zero,0))
|
|
$(call math-expect-false,(call math_is_zero,1))
|
|
$(call math-expect-false,(call math_is_zero,foo))
|
|
$(call math-expect-error,(call math_is_zero,1 2),Multiple words in a single argument: 1 2)
|
|
$(call math-expect-error,(call math_is_zero,no 2),Multiple words in a single argument: no 2)
|
|
|
|
define _math_check_valid
|
|
$(if $(call math_is_number_in_100,$(1)),,$(call math-error,Only non-negative integers <= 100 are supported (not $(1))))
|
|
endef
|
|
|
|
$(call math-expect,(call _math_check_valid,0))
|
|
$(call math-expect,(call _math_check_valid,1))
|
|
$(call math-expect,(call _math_check_valid,100))
|
|
$(call math-expect-error,(call _math_check_valid,-1),Only non-negative integers <= 100 are supported (not -1))
|
|
$(call math-expect-error,(call _math_check_valid,101),Only non-negative integers <= 100 are supported (not 101))
|
|
$(call math-expect-error,(call _math_check_valid,),Argument missing)
|
|
$(call math-expect-error,(call _math_check_valid,1 2),Multiple words in a single argument: 1 2)
|
|
|
|
# return a list containing integers ranging from [$(1),$(2)]
|
|
define int_range_list
|
|
$(strip \
|
|
$(call _math_check_valid,$(1))$(call _math_check_valid,$(2)) \
|
|
$(if $(call math_is_zero,$(1)),0)\
|
|
$(wordlist $(if $(call math_is_zero,$(1)),1,$(1)),$(2),$(__MATH_POS_NUMBERS)))
|
|
endef
|
|
|
|
$(call math-expect,(call int_range_list,0,1),0 1)
|
|
$(call math-expect,(call int_range_list,1,1),1)
|
|
$(call math-expect,(call int_range_list,1,2),1 2)
|
|
$(call math-expect,(call int_range_list,2,1),)
|
|
$(call math-expect-error,(call int_range_list,1,101),Only non-negative integers <= 100 are supported (not 101))
|
|
|
|
# Split an integer into a list of digits
|
|
define _math_number_to_list
|
|
$(strip \
|
|
$(if $(call _math_ext_is_number,$(1)),,\
|
|
$(call math-error,Only non-negative integers are supported (not $(1)))) \
|
|
$(eval num_list:=$(1)) \
|
|
$(foreach num,$(__MATH_ONE_NUMBERS),\
|
|
$(eval num_list:=$(subst $(num),$(space)$(num),$(num_list)))) \
|
|
$(if $(filter $(words $(num_list)),$(__MATH_ONE_NUMBERS)),,\
|
|
$(call math-error,Only non-negative integers with less than 9 digits are supported (not $(1)))) \
|
|
$(if $(filter 0,$(word 1,$(num_list))),\
|
|
$(call math-error,Only non-negative integers without leading zeros are supported (not $(1)))) \
|
|
$(num_list))
|
|
endef
|
|
|
|
$(call math-expect,(call _math_number_to_list,123),1 2 3)
|
|
$(call math-expect-error,(call _math_number_to_list,123 456),Multiple words in a single argument: 123 456)
|
|
$(call math-expect-error,(call _math_number_to_list,-123),Only non-negative integers are supported (not -123))
|
|
$(call math-expect-error,(call _math_number_to_list,002),Only non-negative integers without leading zeros are supported (not 002))
|
|
$(call math-expect-error,(call _math_number_to_list,1234567890),Only non-negative integers with less than 9 digits are supported (not 1234567890))
|
|
|
|
# Compare 1-digit integer $(1) and $(2).
|
|
# Returns 1 if $(1) > $(2), -1 if $(1) < $(2), nothing if equals.
|
|
define _math_1digit_comp
|
|
$(strip \
|
|
$(if $(filter $(1),$(2)),,\
|
|
$(if $(filter $(1),$(firstword $(filter $(1) $(2),$(__MATH_ONE_NUMBERS)))),-1,1)))
|
|
endef
|
|
|
|
$(call math-expect,(call _math_1digit_comp,1,1))
|
|
$(call math-expect,(call _math_1digit_comp,0,9),-1)
|
|
$(call math-expect,(call _math_1digit_comp,3,1),1)
|
|
|
|
# Compare the same $(3)-digit-length integers $(1) and $(2) that are split into a list of digits.
|
|
# Returns 1 if $(1) > $(2), -1 if $(1) < $(2), nothing if equals.
|
|
define _math_list_comp
|
|
$(strip \
|
|
$(eval ans:=) \
|
|
$(foreach num,$(call int_range_list,1,$(3)),\
|
|
$(if $(ans),,$(eval ans:=$(call _math_1digit_comp,$(word $(num),$(1)),$(word $(num),$(2)))))) \
|
|
$(ans))
|
|
endef
|
|
|
|
# Compare any two non-negative integers $(1) and $(2).
|
|
# Returns 1 if $(1) > $(2), -1 if $(1) < $(2), nothing if equals.
|
|
define _math_ext_comp
|
|
$(strip \
|
|
$(eval num_list1:=$(call _math_number_to_list,$(1))) \
|
|
$(eval len1:=$(words $(num_list1))) \
|
|
$(eval num_list2:=$(call _math_number_to_list,$(2))) \
|
|
$(eval len2:=$(words $(num_list2))) \
|
|
$(eval comp:=$(call _math_1digit_comp,$(len1),$(len2))) \
|
|
$(if $(comp),$(comp),$(call _math_list_comp,$(num_list1),$(num_list2),$(len1))))
|
|
endef
|
|
|
|
$(call math-expect,(call _math_ext_comp,5,10),-1)
|
|
$(call math-expect,(call _math_ext_comp,12345,12345))
|
|
$(call math-expect,(call _math_ext_comp,500,5),1)
|
|
$(call math-expect,(call _math_ext_comp,202404,202504),-1)
|
|
|
|
# Returns the greater of $1 or $2.
|
|
# If $1 or $2 is not a positive integer, then an error is generated.
|
|
define math_max
|
|
$(strip \
|
|
$(if $(filter truetrue,$(call math_is_number_in_100,$(1))$(call math_is_number_in_100,$(2))),\
|
|
$(lastword $(filter $(1) $(2),$(__MATH_NUMBERS))),\
|
|
$(if $(filter 1,$(call _math_ext_comp,$(1),$(2))),$(1),$(2))))
|
|
endef
|
|
|
|
# Returns the lesser of $1 or $2.
|
|
define math_min
|
|
$(strip \
|
|
$(if $(filter truetrue,$(call math_is_number_in_100,$(1))$(call math_is_number_in_100,$(2))),\
|
|
$(firstword $(filter $(1) $(2),$(__MATH_NUMBERS))),\
|
|
$(if $(filter -1,$(call _math_ext_comp,$(1),$(2))),$(1),$(2))))
|
|
endef
|
|
|
|
$(call math-expect-error,(call math_max),Argument missing)
|
|
$(call math-expect-error,(call math_max,1),Argument missing)
|
|
$(call math-expect-error,(call math_max,1 2,3),Multiple words in a single argument: 1 2)
|
|
$(call math-expect-error,(call math_min,1,2 3),Multiple words in a single argument: 2 3)
|
|
$(call math-expect,(call math_max,0,1),1)
|
|
$(call math-expect,(call math_max,1,0),1)
|
|
$(call math-expect,(call math_max,1,1),1)
|
|
$(call math-expect,(call math_max,5,42),42)
|
|
$(call math-expect,(call math_max,42,5),42)
|
|
$(call math-expect,(call math_min,0,1),0)
|
|
$(call math-expect,(call math_min,1,0),0)
|
|
$(call math-expect,(call math_min,1,1),1)
|
|
$(call math-expect,(call math_min,7,32),7)
|
|
$(call math-expect,(call math_min,32,7),7)
|
|
|
|
$(call math-expect,(call math_max,32759,7),32759)
|
|
$(call math-expect,(call math_max,7,32759),32759)
|
|
$(call math-expect,(call math_max,202404,202505),202505)
|
|
$(call math-expect,(call math_max,202404,202404),202404)
|
|
$(call math-expect,(call math_min,8908527,32),32)
|
|
$(call math-expect,(call math_min,32,8908527),32)
|
|
$(call math-expect,(call math_min,202404,202505),202404)
|
|
$(call math-expect,(call math_min,202404,202404),202404)
|
|
|
|
define math_gt_or_eq
|
|
$(if $(filter $(1),$(call math_max,$(1),$(2))),true)
|
|
endef
|
|
|
|
define math_gt
|
|
$(if $(call math_gt_or_eq,$(2),$(1)),,true)
|
|
endef
|
|
|
|
define math_lt_or_eq
|
|
$(if $(call math_gt_or_eq,$(2),$(1)),true)
|
|
endef
|
|
|
|
define math_lt
|
|
$(if $(call math_gt_or_eq,$(1),$(2)),,true)
|
|
endef
|
|
|
|
$(call math-expect-true,(call math_gt_or_eq, 2, 1))
|
|
$(call math-expect-true,(call math_gt_or_eq, 1, 1))
|
|
$(call math-expect-false,(call math_gt_or_eq, 1, 2))
|
|
$(call math-expect-true,(call math_gt, 4, 3))
|
|
$(call math-expect-false,(call math_gt, 5, 5))
|
|
$(call math-expect-false,(call math_gt, 6, 7))
|
|
$(call math-expect-true,(call math_lt_or_eq, 11, 11))
|
|
$(call math-expect-false,(call math_lt_or_eq, 25, 15))
|
|
$(call math-expect-true,(call math_lt_or_eq, 9, 16))
|
|
$(call math-expect-false,(call math_lt, 1, 0))
|
|
$(call math-expect-false,(call math_lt, 8, 8))
|
|
$(call math-expect-true,(call math_lt, 10, 11))
|
|
|
|
$(call math-expect-true,(call math_gt_or_eq, 2573904, 2573900))
|
|
$(call math-expect-true,(call math_gt_or_eq, 12345, 12345))
|
|
$(call math-expect-false,(call math_gt_or_eq, 56, 2780))
|
|
|
|
# $1 is the variable name to increment
|
|
define inc_and_print
|
|
$(strip $(eval $(1) := $($(1)) .)$(words $($(1))))
|
|
endef
|
|
|
|
ifdef RUN_MATH_TESTS
|
|
a :=
|
|
$(call math-expect,(call inc_and_print,a),1)
|
|
$(call math-expect,(call inc_and_print,a),2)
|
|
$(call math-expect,(call inc_and_print,a),3)
|
|
$(call math-expect,(call inc_and_print,a),4)
|
|
endif
|
|
|
|
# Returns the words in $2 that are numbers and are less than $1
|
|
define numbers_less_than
|
|
$(strip \
|
|
$(foreach n,$2, \
|
|
$(if $(call math_is_number,$(n)), \
|
|
$(if $(call math_lt,$(n),$(1)), \
|
|
$(n)))))
|
|
endef
|
|
|
|
$(call math-expect,(call numbers_less_than,0,0 1 2 3),)
|
|
$(call math-expect,(call numbers_less_than,1,0 2 1 3),0)
|
|
$(call math-expect,(call numbers_less_than,2,0 2 1 3),0 1)
|
|
$(call math-expect,(call numbers_less_than,3,0 2 1 3),0 2 1)
|
|
$(call math-expect,(call numbers_less_than,4,0 2 1 3),0 2 1 3)
|
|
$(call math-expect,(call numbers_less_than,3,0 2 1 3 2),0 2 1 2)
|
|
$(call math-expect,(call numbers_less_than,100,0 1000 50 101 100),0 50)
|
|
|
|
# Returns the words in $2 that are numbers and are greater or equal to $1
|
|
define numbers_greater_or_equal_to
|
|
$(strip \
|
|
$(foreach n,$2, \
|
|
$(if $(call math_is_number,$(n)), \
|
|
$(if $(call math_gt_or_eq,$(n),$(1)), \
|
|
$(n)))))
|
|
endef
|
|
|
|
$(call math-expect,(call numbers_greater_or_equal_to,4,0 1 2 3),)
|
|
$(call math-expect,(call numbers_greater_or_equal_to,3,0 2 1 3),3)
|
|
$(call math-expect,(call numbers_greater_or_equal_to,2,0 2 1 3),2 3)
|
|
$(call math-expect,(call numbers_greater_or_equal_to,1,0 2 1 3),2 1 3)
|
|
$(call math-expect,(call numbers_greater_or_equal_to,0,0 2 1 3),0 2 1 3)
|
|
$(call math-expect,(call numbers_greater_or_equal_to,1,0 2 1 3 2),2 1 3 2)
|
|
|
|
# 10,001 = 10 ** 4 + 1, contains 10,001 x's, so 1 more than 10,000 (future) API level
|
|
_INT_LIMIT_WORDS := x $(foreach a,0 1 2 3 4 5 6 7 8 9,$(foreach b,0 1 2 3 4 5 6 7 8 9,\
|
|
$(foreach c,0 1 2 3 4 5 6 7 8 9,x x x x x x x x x x)))
|
|
|
|
define _int_encode
|
|
$(if $(filter $(words x $(_INT_LIMIT_WORDS)),$(words $(wordlist 1,$(1),x $(_INT_LIMIT_WORDS)))),\
|
|
$(call math-error,integer greater than $(words $(_INT_LIMIT_WORDS)) is not supported!),\
|
|
$(wordlist 1,$(1),$(_INT_LIMIT_WORDS)))
|
|
endef
|
|
|
|
# _int_max returns the maximum of the two arguments
|
|
# input: two (x) lists; output: one (x) list
|
|
# integer cannot be passed in directly. It has to be converted using _int_encode.
|
|
define _int_max
|
|
$(subst xx,x,$(join $(1),$(2)))
|
|
endef
|
|
|
|
# first argument is greater than second argument
|
|
# output: non-empty if true
|
|
# integer cannot be passed in directly. It has to be converted using _int_encode.
|
|
define _int_greater-than
|
|
$(filter-out $(words $(2)),$(words $(call _int_max,$(1),$(2))))
|
|
endef
|
|
|
|
# first argument equals to second argument
|
|
# output: non-empty if true
|
|
# integer cannot be passed in directly. It has to be converted using _int_encode.
|
|
define _int_equal
|
|
$(filter $(words $(1)),$(words $(2)))
|
|
endef
|
|
|
|
# first argument is greater than or equal to second argument
|
|
# output: non-empty if true
|
|
# integer cannot be passed in directly. It has to be converted using _int_encode.
|
|
define _int_greater-or-equal
|
|
$(call _int_greater-than,$(1),$(2))$(call _int_equal,$(1),$(2))
|
|
endef
|
|
|
|
define int_plus
|
|
$(words $(call _int_encode,$(1)) $(call _int_encode,$(2)))
|
|
endef
|
|
|
|
$(call math-expect,(call int_plus,0,0),0)
|
|
$(call math-expect,(call int_plus,0,1),1)
|
|
$(call math-expect,(call int_plus,1,0),1)
|
|
$(call math-expect,(call int_plus,1,100),101)
|
|
$(call math-expect,(call int_plus,100,100),200)
|
|
|
|
define int_subtract
|
|
$(strip \
|
|
$(if $(call _int_greater-or-equal,$(call _int_encode,$(1)),$(call _int_encode,$(2))),\
|
|
$(words $(filter-out xx,$(join $(call _int_encode,$(1)),$(call _int_encode,$(2))))),\
|
|
$(call math-error,subtract underflow $(1) - $(2))))
|
|
endef
|
|
|
|
$(call math-expect,(call int_subtract,0,0),0)
|
|
$(call math-expect,(call int_subtract,1,0),1)
|
|
$(call math-expect,(call int_subtract,1,1),0)
|
|
$(call math-expect,(call int_subtract,100,1),99)
|
|
$(call math-expect,(call int_subtract,200,100),100)
|
|
$(call math-expect-error,(call int_subtract,0,1),subtract underflow 0 - 1)
|
|
|
|
define int_multiply
|
|
$(words $(foreach a,$(call _int_encode,$(1)),$(call _int_encode,$(2))))
|
|
endef
|
|
|
|
$(call math-expect,(call int_multiply,0,0),0)
|
|
$(call math-expect,(call int_multiply,1,0),0)
|
|
$(call math-expect,(call int_multiply,1,1),1)
|
|
$(call math-expect,(call int_multiply,100,1),100)
|
|
$(call math-expect,(call int_multiply,1,100),100)
|
|
$(call math-expect,(call int_multiply,4,100),400)
|
|
$(call math-expect,(call int_multiply,100,4),400)
|
|
|
|
define int_divide
|
|
$(if $(filter 0,$(2)),$(call math-error,division by zero is not allowed!),$(strip \
|
|
$(if $(call _int_greater-or-equal,$(call _int_encode,$(1)),$(call _int_encode,$(2))), \
|
|
$(call int_plus,$(call int_divide,$(call int_subtract,$(1),$(2)),$(2)),1),0)))
|
|
endef
|
|
|
|
$(call math-expect,(call int_divide,1,1),1)
|
|
$(call math-expect,(call int_divide,200,1),200)
|
|
$(call math-expect,(call int_divide,200,3),66)
|
|
$(call math-expect,(call int_divide,1,2),0)
|
|
$(call math-expect-error,(call int_divide,0,0),division by zero is not allowed!)
|
|
$(call math-expect-error,(call int_divide,1,0),division by zero is not allowed!)
|
|
|
|
ifdef RUN_MATH_TESTS
|
|
ifdef MATH_TEST_FAILURE
|
|
math-tests:
|
|
@echo FAIL
|
|
@false
|
|
else
|
|
math-tests:
|
|
@echo PASS
|
|
endif
|
|
.PHONY: math-tests
|
|
endif
|