diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index b001733aee104e..86380e7accf238 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -58,3 +58,7 @@ jobs: run: | ./scripts/run_in_build_env.sh \ "./scripts/build/build_examples.py --no-log-timestamps --platform android build" + - name: Run Android build rule tests + run: | + ./scripts/run_in_build_env.sh \ + "ninja -C out/android-arm64-chip_tool build/chip/java/tests:java_build_test.tests" diff --git a/BUILD.gn b/BUILD.gn index ec7eae35dd2a35..9103cb691ed36e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -92,6 +92,9 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { if (chip_build_tests) { deps += [ "//src:tests" ] + if (current_os == "android") { + deps += [ "${chip_root}/build/chip/java/tests:java_build_test" ] + } } if (chip_with_lwip) { diff --git a/build/chip/java/javac_runner.py b/build/chip/java/javac_runner.py index c6234cc2263a8c..0e03aa53e8aab9 100755 --- a/build/chip/java/javac_runner.py +++ b/build/chip/java/javac_runner.py @@ -19,6 +19,7 @@ """Wrapper script to run javac command as an action with gn.""" import argparse +import json import os import subprocess import sys @@ -78,6 +79,19 @@ def FindCommand(command): return None +def ReadBuildConfig(build_config): + with open(build_config, 'r') as file: + return json.load(file) + + +def ComputeClasspath(build_config_json): + unique_jars = build_config_json['deps_info']['deps_jars'] + if sys.platform == 'win32': + return ";".join(unique_jars) + else: + return ":".join(unique_jars) + + def main(): java_path = FindCommand('javac') if not java_path: @@ -95,13 +109,25 @@ def main(): dest='outfile', required=True, help='Output file containing a list of classes') + parser.add_argument( + '--build-config', + dest='build_config', + required=True, + help='Build config') parser.add_argument( 'rest', metavar='JAVAC_ARGS', nargs='*', help='Argumets to pass to javac') args = parser.parse_args() if not os.path.isdir(args.classdir): - os.makedirs(args.classdir) - retcode = subprocess.check_call([java_path] + args.rest) + os.makedirs(args.classdir, exist_ok=True) + + build_config_json = ReadBuildConfig(args.build_config) + classpath = ComputeClasspath(build_config_json) + java_args = [java_path] + if classpath: + java_args += ["-classpath", classpath] + + retcode = subprocess.check_call(java_args + args.rest) if retcode != EXIT_SUCCESS: return retcode diff --git a/build/chip/java/rules.gni b/build/chip/java/rules.gni index 6b39aa36cbe680..059e95c45e9153 100644 --- a/build/chip/java/rules.gni +++ b/build/chip/java/rules.gni @@ -18,12 +18,15 @@ import("${chip_root}/build/config/android/config.gni") javac_runner = "${chip_root}/build/chip/java/javac_runner.py" jar_runner = "${chip_root}/build/chip/java/jar_runner.py" +write_build_config = "${chip_root}/build/chip/java/write_build_config.py" assert(android_sdk_root != "", "android_sdk_root must be specified") # Declare a java library target # -# sources: List of .java files included in this library. +# sources: List of .java files included in this library. Mutually exclusive with jar_path. +# +# jar_path: A path to an existing JAR. Mutually exclusive with sources. # # output_name: File name for the output .jar (not including extension). # Defaults to the input .jar file name. @@ -39,76 +42,137 @@ template("java_library") { _jar_name += ".jar" } - # Additional flags - _javac_flags = [ - "-Werror", - "-Xlint:all", - ] - if (defined(invoker.javac_flags)) { - _javac_flags += invoker.javac_flags - } - _deps = [] if (defined(invoker.deps)) { _deps = invoker.deps } - _data_deps = [] - if (defined(invoker.data_deps)) { - _data_deps = invoker.data_deps + # What files will be compiled + _java_files = [] + if (defined(invoker.sources)) { + _java_files = invoker.sources } - # What files will be compiled - _java_files = invoker.sources + _is_prebuilt = defined(invoker.jar_path) + + _jar_output = "" + _target_dir_name = get_label_info(":$target_name", "dir") + if (_is_prebuilt) { + assert(_java_files == []) + _jar_output = "$root_out_dir/lib/$_target_dir_name/" + + get_path_info(invoker.jar_path, "name") + ".jar" + } else { + _jar_output = "$root_out_dir/lib/$_target_dir_name/$_jar_name" + } - # Generates a .java file containing all sources to be compiled - _java_sources_file = "$target_gen_dir/$target_name.sources" - if (defined(invoker.java_sources_file)) { - _java_sources_file = invoker.java_sources_file + # Generate a list containing the expected build_config filepath of every dependency. + _deps_configs = [] + foreach(_dep, _deps) { + _dep_gen_dir = get_label_info(_dep, "target_gen_dir") + _dep_name = get_label_info(_dep, "name") + _dep_config = "$_dep_gen_dir/$_dep_name.json" + _deps_configs += [ _dep_config ] } - write_file(_java_sources_file, rebase_path(_java_files, root_build_dir)) + _rebased_deps_configs = rebase_path(_deps_configs, root_build_dir) - # Compiles the given files into a directory and generates a 'class list' - _javac_target_name = target_name + "__javac" - _class_dir = rebase_path(target_out_dir, root_build_dir) + "/classes" - _class_list_file = "$target_gen_dir/$target_name.classlist" - action(_javac_target_name) { - sources = _java_files + # Create the name for this target's build_config. + _library_target_name = target_name + _build_config = "$target_gen_dir/$_library_target_name.json" + _rebased_build_config = rebase_path(_build_config, root_build_dir) - outputs = [ _class_list_file ] + # Write the build_config file for this target. + _config_target_name = target_name + "_config" + action(_config_target_name) { + script = write_build_config - script = javac_runner + deps = _deps + outputs = [ _build_config ] args = [ - "--classdir", - _class_dir, - "--outfile", - rebase_path(_class_list_file, root_build_dir), - "--", - "-d", - _class_dir, - "@" + rebase_path(_java_sources_file, root_build_dir), - ] + _javac_flags + "--jar-path", + rebase_path(_jar_output, root_build_dir), + "--build-config", + _rebased_build_config, + "--deps-configs=$_rebased_deps_configs", + ] } - # Bundles all files within the 'class directory' into a jar file - _jar_output = "$root_out_dir/lib/$_jar_name" - action(target_name) { - deps = [ ":$_javac_target_name" ] + _deps + # Building from sources - perform Java compilation and JAR creation. + if (!_is_prebuilt) { + # Additional flags + _javac_flags = [ + "-Werror", + "-Xlint:all", + ] + if (defined(invoker.javac_flags)) { + _javac_flags += invoker.javac_flags + } - data_deps = _data_deps + # Data deps + _data_deps = [] + if (defined(invoker.data_deps)) { + _data_deps = invoker.data_deps + } - outputs = [ _jar_output ] + # Generates a .java file containing all sources to be compiled + _java_sources_file = "$target_gen_dir/$target_name.sources" + if (defined(invoker.java_sources_file)) { + _java_sources_file = invoker.java_sources_file + } + write_file(_java_sources_file, rebase_path(_java_files, root_build_dir)) + + # Compiles the given files into a directory and generates a 'class list' + _javac_target_name = target_name + "__javac" + _class_dir = rebase_path(target_out_dir, root_build_dir) + "/classes" + _class_list_file = "$target_gen_dir/$target_name.classlist" + action(_javac_target_name) { + sources = _java_files + deps = [ ":$_config_target_name" ] + + outputs = [ _class_list_file ] + + script = javac_runner + + args = [ + "--classdir", + _class_dir, + "--outfile", + rebase_path(_class_list_file, root_build_dir), + "--build-config", + _rebased_build_config, + "--", + "-d", + _class_dir, + "@" + rebase_path(_java_sources_file, root_build_dir), + ] + _javac_flags + } - script = jar_runner + # Bundles all files within the 'class directory' into a jar file + action(target_name) { + deps = [ ":$_javac_target_name" ] + _deps - args = [ - "cf", - rebase_path(_jar_output, root_build_dir), - "-C", - _class_dir, - ".", - ] + data_deps = _data_deps + + outputs = [ _jar_output ] + + script = jar_runner + + args = [ + "cf", + rebase_path(_jar_output, root_build_dir), + "-C", + _class_dir, + ".", + ] + } + } else { + # Using pre-specified JAR instead of building from sources - simply copy the JAR to the output directory. + _original_jar_path = invoker.jar_path + copy(target_name) { + sources = [ _original_jar_path ] + outputs = [ _jar_output ] + deps = [ ":$_config_target_name" ] + _deps + } } } @@ -121,8 +185,6 @@ template("android_library") { } javac_flags += [ - "-classpath", - "${android_sdk_root}/platforms/android-${android_sdk_version}/android.jar", "-Xlint:-options", "-source", "8", @@ -131,3 +193,9 @@ template("android_library") { ] } } + +template("java_prebuilt") { + java_library(target_name) { + forward_variables_from(invoker, "*") + } +} diff --git a/build/chip/java/tests/BUILD.gn b/build/chip/java/tests/BUILD.gn new file mode 100644 index 00000000000000..a782edc7740d84 --- /dev/null +++ b/build/chip/java/tests/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# 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. + +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") +import("$dir_pw_build/python.gni") +import("${chip_root}/build/chip/java/rules.gni") + +pw_python_script("java_build_test") { + inputs = [ + "expected_output/child_library_2_expected.json", + "expected_output/grandchild_library_expected.json", + "expected_output/child_library_expected.json", + "expected_output/java_library_expected.json", + "expected_output/child_prebuilt_expected.json", + "expected_output/java_prebuilt_expected.json", + ] + other_deps = [ ":java_library" ] + tests = [ "test.py" ] +} + +java_library("java_library") { + sources = [ "IncludedInSources.java" ] + deps = [ + ":child_library", + ":child_library_2", + ":java_prebuilt", + ] +} + +java_library("child_library") { + sources = [ "IncludedInChildSources.java" ] +} + +java_library("child_library_2") { + sources = [ "IncludedInChildSources2.java" ] + + deps = [ ":grandchild_library" ] +} + +java_library("grandchild_library") { + sources = [ "IncludedInGrandchildSources.java" ] +} + +java_prebuilt("java_prebuilt") { + jar_path = "/tmp/chip_java_build_test/prebuilt_jar.jar" + deps = [ ":child_prebuilt" ] +} + +java_prebuilt("child_prebuilt") { + jar_path = "/tmp/chip_java_build_test/child_jar.jar" +} diff --git a/build/chip/java/tests/IncludedInChildJar.java b/build/chip/java/tests/IncludedInChildJar.java new file mode 100644 index 00000000000000..b1b09c33414d59 --- /dev/null +++ b/build/chip/java/tests/IncludedInChildJar.java @@ -0,0 +1,3 @@ +package build.chip.java.tests; + +public class IncludedInChildJar {} diff --git a/build/chip/java/tests/IncludedInChildSources.java b/build/chip/java/tests/IncludedInChildSources.java new file mode 100644 index 00000000000000..a74febaaf01e8a --- /dev/null +++ b/build/chip/java/tests/IncludedInChildSources.java @@ -0,0 +1,3 @@ +package build.chip.java.tests; + +public class IncludedInChildSources {} diff --git a/build/chip/java/tests/IncludedInChildSources2.java b/build/chip/java/tests/IncludedInChildSources2.java new file mode 100644 index 00000000000000..e20676490f483d --- /dev/null +++ b/build/chip/java/tests/IncludedInChildSources2.java @@ -0,0 +1,5 @@ +package build.chip.java.tests; + +public class IncludedInChildSources2 { + IncludedInGrandchildSources includedInGrandchildSources; +} diff --git a/build/chip/java/tests/IncludedInGrandchildSources.java b/build/chip/java/tests/IncludedInGrandchildSources.java new file mode 100644 index 00000000000000..fb7005efa42a5f --- /dev/null +++ b/build/chip/java/tests/IncludedInGrandchildSources.java @@ -0,0 +1,3 @@ +package build.chip.java.tests; + +public class IncludedInGrandchildSources {} diff --git a/build/chip/java/tests/IncludedInJar.java b/build/chip/java/tests/IncludedInJar.java new file mode 100644 index 00000000000000..0d51eaa08e2a85 --- /dev/null +++ b/build/chip/java/tests/IncludedInJar.java @@ -0,0 +1,5 @@ +package build.chip.java.tests; + +public class IncludedInJar { + IncludedInChildJar includedInChildJar; +} diff --git a/build/chip/java/tests/IncludedInSources.java b/build/chip/java/tests/IncludedInSources.java new file mode 100644 index 00000000000000..890cf286da4301 --- /dev/null +++ b/build/chip/java/tests/IncludedInSources.java @@ -0,0 +1,9 @@ +package build.chip.java.tests; + +public class IncludedInSources { + IncludedInChildSources includedInChildSources; + IncludedInChildSources2 includedInChildSources2; + IncludedInGrandchildSources includedInGrandchildSources; + + IncludedInJar includedInJar; +} diff --git a/build/chip/java/tests/empty_build_config.json b/build/chip/java/tests/empty_build_config.json new file mode 100644 index 00000000000000..b33e9367c7092c --- /dev/null +++ b/build/chip/java/tests/empty_build_config.json @@ -0,0 +1,8 @@ +{ + "deps_info": { + "name": "", + "jar_path": "", + "deps_configs": [], + "deps_jars": [] + } +} diff --git a/build/chip/java/tests/expected_output/child_library_2_expected.json b/build/chip/java/tests/expected_output/child_library_2_expected.json new file mode 100644 index 00000000000000..9563f85d494eab --- /dev/null +++ b/build/chip/java/tests/expected_output/child_library_2_expected.json @@ -0,0 +1,10 @@ +{ + "deps_info": { + "name": "child_library_2.json", + "jar_path": "python/lib/build/chip/java/tests/child_library_2.jar", + "deps_configs": [ + "python/gen/build/chip/java/tests/grandchild_library.json" + ], + "deps_jars": ["python/lib/build/chip/java/tests/grandchild_library.jar"] + } +} diff --git a/build/chip/java/tests/expected_output/child_library_expected.json b/build/chip/java/tests/expected_output/child_library_expected.json new file mode 100644 index 00000000000000..279542f6034170 --- /dev/null +++ b/build/chip/java/tests/expected_output/child_library_expected.json @@ -0,0 +1,8 @@ +{ + "deps_info": { + "name": "child_library.json", + "jar_path": "python/lib/build/chip/java/tests/child_library.jar", + "deps_configs": [], + "deps_jars": [] + } +} diff --git a/build/chip/java/tests/expected_output/child_prebuilt_expected.json b/build/chip/java/tests/expected_output/child_prebuilt_expected.json new file mode 100644 index 00000000000000..c276a7b4d06674 --- /dev/null +++ b/build/chip/java/tests/expected_output/child_prebuilt_expected.json @@ -0,0 +1,8 @@ +{ + "deps_info": { + "name": "child_prebuilt.json", + "jar_path": "python/lib/build/chip/java/tests/child_jar.jar", + "deps_configs": [], + "deps_jars": [] + } +} diff --git a/build/chip/java/tests/expected_output/grandchild_library_expected.json b/build/chip/java/tests/expected_output/grandchild_library_expected.json new file mode 100644 index 00000000000000..54c6c3336bcb61 --- /dev/null +++ b/build/chip/java/tests/expected_output/grandchild_library_expected.json @@ -0,0 +1,8 @@ +{ + "deps_info": { + "name": "grandchild_library.json", + "jar_path": "python/lib/build/chip/java/tests/grandchild_library.jar", + "deps_configs": [], + "deps_jars": [] + } +} diff --git a/build/chip/java/tests/expected_output/java_library_expected.json b/build/chip/java/tests/expected_output/java_library_expected.json new file mode 100644 index 00000000000000..2806ed6cad0049 --- /dev/null +++ b/build/chip/java/tests/expected_output/java_library_expected.json @@ -0,0 +1,18 @@ +{ + "deps_info": { + "name": "java_library.json", + "jar_path": "python/lib/build/chip/java/tests/java_library.jar", + "deps_configs": [ + "python/gen/build/chip/java/tests/child_library.json", + "python/gen/build/chip/java/tests/child_library_2.json", + "python/gen/build/chip/java/tests/java_prebuilt.json" + ], + "deps_jars": [ + "python/lib/build/chip/java/tests/child_library.jar", + "python/lib/build/chip/java/tests/child_library_2.jar", + "python/lib/build/chip/java/tests/grandchild_library.jar", + "python/lib/build/chip/java/tests/prebuilt_jar.jar", + "python/lib/build/chip/java/tests/child_jar.jar" + ] + } +} diff --git a/build/chip/java/tests/expected_output/java_prebuilt_expected.json b/build/chip/java/tests/expected_output/java_prebuilt_expected.json new file mode 100644 index 00000000000000..10ce6a558762ea --- /dev/null +++ b/build/chip/java/tests/expected_output/java_prebuilt_expected.json @@ -0,0 +1,10 @@ +{ + "deps_info": { + "name": "java_prebuilt.json", + "jar_path": "python/lib/build/chip/java/tests/prebuilt_jar.jar", + "deps_configs": [ + "python/gen/build/chip/java/tests/child_prebuilt.json" + ], + "deps_jars": ["python/lib/build/chip/java/tests/child_jar.jar"] + } +} diff --git a/build/chip/java/tests/generate_jars_for_test.py b/build/chip/java/tests/generate_jars_for_test.py new file mode 100644 index 00000000000000..0c6f954bbd012e --- /dev/null +++ b/build/chip/java/tests/generate_jars_for_test.py @@ -0,0 +1,50 @@ +import os +import subprocess +import sys + +"""Generate JARs used to test the java_prebuilt rule.""" + +chip_root = os.getenv('PW_PROJECT_ROOT') +test_dir = chip_root + '/build/chip/java/tests' +tmp_dir = '/tmp/chip_java_build_test' + + +def generateJar(source_file, output_name): + tmp_classes_dir = tmp_dir + '/classes' + os.makedirs(tmp_dir, exist_ok=True) + os.makedirs(tmp_dir + '/classes', exist_ok=True) + javac_runner_command = [ + 'python3', + chip_root + '/build/chip/java/javac_runner.py', + '--classdir', + tmp_classes_dir, + '--outfile', + tmp_dir + '/prebuilt_jar.classlist', + '--build-config', + test_dir + '/empty_build_config.json', + '--', + '-d', + tmp_classes_dir, + source_file, + ] + subprocess.check_call(javac_runner_command) + + jar_runner_command = [ + 'python3', + chip_root + '/build/chip/java/jar_runner.py', + 'cf', + tmp_dir + '/' + output_name, + '-C', + tmp_classes_dir, + '.', + ] + subprocess.check_call(jar_runner_command) + + +def main(): + generateJar(test_dir + '/IncludedInJar.java', 'prebuilt_jar.jar') + generateJar(test_dir + '/IncludedInChildJar.java', 'child_jar.jar') + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/chip/java/tests/test.py b/build/chip/java/tests/test.py new file mode 100755 index 00000000000000..4f8939284dcf87 --- /dev/null +++ b/build/chip/java/tests/test.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 Project CHIP Authors +# +# 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. + +""" +Test for GN Java build rules. This test should be executed using ninja, and +generate_jars_for_test.py should have been called before running this test. +""" + +import json +import os +from os import path +import subprocess +import unittest + + +class JavaBuildTest(unittest.TestCase): + chip_root = os.getenv('PW_PROJECT_ROOT') + local_test_dir = '/build/chip/java/tests' + test_dir = chip_root + local_test_dir + + jars_dir = 'python/lib' + local_test_dir + configs_dir = 'python/gen' + local_test_dir + + tmp_dir = '/tmp/chip_java_build_test' + + # Target names in the BUILD.gn + targets_to_check = [ + 'java_library', + 'child_library', + 'child_library_2', + 'grandchild_library', + ] + prebuilt_targets_to_check = [ + 'java_prebuilt', + 'child_prebuilt' + ] + + def testExpectedJarsCreated(self): + jars_dir = JavaBuildTest.jars_dir + for target in JavaBuildTest.targets_to_check: + self.assertTrue(path.exists(jars_dir + '/' + target + '.jar')) + + # Prebuilt jars should have been copied to the output directory. + self.assertTrue(path.exists(jars_dir + '/prebuilt_jar.jar')) + self.assertTrue(path.exists(jars_dir + '/child_jar.jar')) + + def testBuildConfigMatchesExpected(self): + self.maxDiff = None + configs_dir = JavaBuildTest.configs_dir + expected_dir = JavaBuildTest.test_dir + '/expected_output' + + for target in (JavaBuildTest.targets_to_check + JavaBuildTest.prebuilt_targets_to_check): + with open(expected_dir + '/' + target + '_expected.json', 'r') as expected_config, open(configs_dir + '/' + target + '.json', 'r') as actual_config: + expected_json = json.load(expected_config)['deps_info'] + actual_json = json.load(actual_config)['deps_info'] + + self.assertEqual(expected_json['name'], actual_json['name']) + self.assertEqual( + expected_json['jar_path'], actual_json['jar_path']) + self.assertCountEqual( + expected_json['deps_configs'], actual_json['deps_configs']) + self.assertCountEqual( + expected_json['deps_jars'], actual_json['deps_jars']) + + +if __name__ == '__main__': + unittest.main() diff --git a/build/chip/java/write_build_config.py b/build/chip/java/write_build_config.py new file mode 100755 index 00000000000000..8dedb190f3c4bd --- /dev/null +++ b/build/chip/java/write_build_config.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# Copyright (c) 2021 Project CHIP Authors +# +# 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. + +""" +Writes a JSON file containing build configuration information. + +See build/chip/java/tests/expected_output/* for example build configuration +files. +""" + +import json +import optparse +import os +import sys + + +def LoadBuildConfigs(paths): + build_configs = [] + for path in paths: + with open(path, 'r') as file: + build_configs.append(json.load(file)) + return build_configs + + +def ParseGnList(value): + if not value: + return [] + if value.startswith('[') and value.endswith(']'): + gn_list = value.strip("[]").replace( + "\"", "").replace(" ", "").split(",") + if not gn_list[0]: + return [] + else: + return gn_list + + +def GetAllDependentJars(deps_configs_data): + configs_to_process = deps_configs_data + deps_jars = set() + + while configs_to_process: + deps_config = configs_to_process.pop() + child_configs = LoadBuildConfigs( + deps_config['deps_info']['deps_configs']) + deps_jars.add(deps_config['deps_info']['jar_path']) + + configs_to_process += child_configs + + return deps_jars + + +def main(argv): + parser = optparse.OptionParser() + parser.add_option('--build-config', help='Path to build_config output') + parser.add_option('--deps-configs', + help='GN-list of dependent build_config files') + parser.add_option('--jar-path', help='Path to the .jar') + options, args = parser.parse_args(argv) + + deps_configs_list = ParseGnList(options.deps_configs) + deps_configs_data = LoadBuildConfigs(deps_configs_list) + + deps_jars_set = GetAllDependentJars(deps_configs_data) + + config = { + "deps_info": { + "name": os.path.basename(options.build_config), + "jar_path": options.jar_path, + # List of configs depended on by this config. Not recursive. + "deps_configs": deps_configs_list, + # List of all jars needed by all dependencies of this config (recursive). + "deps_jars": list(deps_jars_set) + } + } + + with open(options.build_config, 'w') as file: + json.dump(config, file) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/scripts/build/builders/android.py b/scripts/build/builders/android.py index 902970b45b7851..3d9b80d317053c 100644 --- a/scripts/build/builders/android.py +++ b/scripts/build/builders/android.py @@ -87,6 +87,10 @@ def validate_build_environment(self): % licenses) def generate(self): + self._Execute([ + 'python3', 'build/chip/java/tests/generate_jars_for_test.py' + ], title='Generating JARs for Java build rules test') + if not os.path.exists(self.output_dir): # NRF does a in-place update of SDK tools if not self._runner.dry_run: @@ -120,11 +124,6 @@ def _build(self): self._Execute(['ninja', '-C', self.output_dir], title='Building JNI ' + self.identifier) - # NOTE: the following IDE-specific build instructions are NOT used: - # - "rsync -a out/"android_$TARGET_CPU"/lib/*.jar src/android/CHIPTool/app/libs" - # => using the 'ninjaOutputDir' project property instead to take the jar files directly - # from the output - # JNILibs will be copied as long as they reside in src/main/jniLibs/ABI: # https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs # to avoid redefined in IDE mode, copy to another place and add that path in build.gradle @@ -133,6 +132,7 @@ def _build(self): # when using dry run. jnilibs_dir = os.path.join( self.root, 'src/android/CHIPTool/app/libs/jniLibs', self.board.AbiName()) + libs_dir = os.path.join(self.root, 'src/android/CHIPTool/app/libs') self._Execute(['mkdir', '-p', jnilibs_dir], title='Prepare Native libs ' + self.identifier) @@ -149,11 +149,18 @@ def _build(self): self._Execute(['cp', os.path.join(self.output_dir, 'lib', 'jni', self.board.AbiName( ), libName), os.path.join(jnilibs_dir, libName)]) + jars = { + 'CHIPController.jar': 'src/controller/java/CHIPController.jar', + 'SetupPayloadParser.jar': 'src/setup_payload/java/SetupPayloadParser.jar' + } + for jarName in jars.keys(): + self._Execute(['cp', os.path.join( + self.output_dir, 'lib', jars[jarName]), os.path.join(libs_dir, jarName)]) + # App compilation self._Execute([ '%s/src/android/CHIPTool/gradlew' % self.root, '-p', '%s/src/android/CHIPTool' % self.root, - '-PchipSdkJarDir=%s' % os.path.join(self.output_dir, 'lib'), '-PbuildDir=%s' % self.output_dir, 'assembleDebug' ], title='Building APP ' + self.identifier) @@ -161,9 +168,11 @@ def _build(self): def build_outputs(self): outputs = { 'CHIPController.jar': - os.path.join(self.output_dir, 'lib', 'CHIPController.jar'), + os.path.join(self.output_dir, 'lib', + 'src/controller/java/CHIPController.jar'), 'SetupPayloadParser.jar': - os.path.join(self.output_dir, 'lib', 'SetupPayloadParser.jar'), + os.path.join(self.output_dir, 'lib', + 'src/setup_payload/java/SetupPayloadParser.jar'), 'ChipTool-debug.apk': os.path.join(self.output_dir, 'outputs', 'apk', 'debug', 'app-debug.apk'), diff --git a/scripts/build/expected_all_platform_commands.txt b/scripts/build/expected_all_platform_commands.txt index 81f99f21b5832c..026bb08b8e4575 100644 --- a/scripts/build/expected_all_platform_commands.txt +++ b/scripts/build/expected_all_platform_commands.txt @@ -104,24 +104,36 @@ bash -c 'source "$ZEPHYR_BASE/zephyr-env.sh"; export GNUARMEMB_TOOLCHAIN_PATH="$PW_PIGWEED_CIPD_INSTALL_DIR"; west build --cmake-only -d {out}/nrf-nrf5340-pump_controller -b nrf5340dk_nrf5340_cpuapp {root}/examples/pump-controller-app/nrfconnect' +# Generating JARs for Java build rules test +python3 build/chip/java/tests/generate_jars_for_test.py + # Generating android-arm-chip_tool gn gen --check --fail-on-unused-args {out}/android-arm-chip_tool '--args=target_os="android" target_cpu="arm" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' # Accepting NDK licenses bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null' +# Generating JARs for Java build rules test +python3 build/chip/java/tests/generate_jars_for_test.py + # Generating android-arm64-chip_tool gn gen --check --fail-on-unused-args {out}/android-arm64-chip_tool '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' # Accepting NDK licenses bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null' +# Generating JARs for Java build rules test +python3 build/chip/java/tests/generate_jars_for_test.py + # Generating android-x64-chip_tool gn gen --check --fail-on-unused-args {out}/android-x64-chip_tool '--args=target_os="android" target_cpu="x64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' # Accepting NDK licenses bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null' +# Generating JARs for Java build rules test +python3 build/chip/java/tests/generate_jars_for_test.py + # Generating android-x86-chip_tool gn gen --check --fail-on-unused-args {out}/android-x86-chip_tool '--args=target_os="android" target_cpu="x86" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' @@ -225,8 +237,12 @@ cp {out}/android-arm-chip_tool/lib/jni/armeabi-v7a/libCHIPController.so {root}/s cp {out}/android-arm-chip_tool/lib/jni/armeabi-v7a/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/armeabi-v7a/libc++_shared.so +cp {out}/android-arm-chip_tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar + +cp {out}/android-arm-chip_tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar + # Building APP android-arm-chip_tool -{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PchipSdkJarDir={out}/android-arm-chip_tool/lib -PbuildDir={out}/android-arm-chip_tool assembleDebug +{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PbuildDir={out}/android-arm-chip_tool assembleDebug # Building JNI android-arm64-chip_tool ninja -C {out}/android-arm64-chip_tool @@ -240,8 +256,12 @@ cp {out}/android-arm64-chip_tool/lib/jni/arm64-v8a/libCHIPController.so {root}/s cp {out}/android-arm64-chip_tool/lib/jni/arm64-v8a/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/arm64-v8a/libc++_shared.so +cp {out}/android-arm64-chip_tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar + +cp {out}/android-arm64-chip_tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar + # Building APP android-arm64-chip_tool -{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PchipSdkJarDir={out}/android-arm64-chip_tool/lib -PbuildDir={out}/android-arm64-chip_tool assembleDebug +{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PbuildDir={out}/android-arm64-chip_tool assembleDebug # Building JNI android-x64-chip_tool ninja -C {out}/android-x64-chip_tool @@ -255,8 +275,12 @@ cp {out}/android-x64-chip_tool/lib/jni/x86_64/libCHIPController.so {root}/src/an cp {out}/android-x64-chip_tool/lib/jni/x86_64/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86_64/libc++_shared.so +cp {out}/android-x64-chip_tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar + +cp {out}/android-x64-chip_tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar + # Building APP android-x64-chip_tool -{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PchipSdkJarDir={out}/android-x64-chip_tool/lib -PbuildDir={out}/android-x64-chip_tool assembleDebug +{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PbuildDir={out}/android-x64-chip_tool assembleDebug # Building JNI android-x86-chip_tool ninja -C {out}/android-x86-chip_tool @@ -270,8 +294,12 @@ cp {out}/android-x86-chip_tool/lib/jni/x86/libCHIPController.so {root}/src/andro cp {out}/android-x86-chip_tool/lib/jni/x86/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86/libc++_shared.so +cp {out}/android-x86-chip_tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar + +cp {out}/android-x86-chip_tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar + # Building APP android-x86-chip_tool -{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PchipSdkJarDir={out}/android-x86-chip_tool/lib -PbuildDir={out}/android-x86-chip_tool assembleDebug +{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PbuildDir={out}/android-x86-chip_tool assembleDebug # Building infineon-p6board-lock ninja -C {out}/infineon-p6board-lock diff --git a/src/android/CHIPTool/app/build.gradle b/src/android/CHIPTool/app/build.gradle index a160748c7f105e..ee401987ae4600 100644 --- a/src/android/CHIPTool/app/build.gradle +++ b/src/android/CHIPTool/app/build.gradle @@ -80,12 +80,6 @@ dependencies { if (matterBuildSrcDir.isEmpty()) { // local in-source-tree copy of the dependencies. Useful for IDE compilation implementation fileTree(dir: "libs", include: ["*.jar", "*.so"]) - - // build time dependencies - if (project.hasProperty("chipSdkJarDir")) { - println "Compiling using custom sdk jar file directory: ${chipSdkJarDir}" - implementation fileTree(dir: "${chipSdkJarDir}", include: ["*.jar", "*.so"]) - } } else { implementation project(':chip-library') } diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index fc2fca12f78d60..d8ece0fed9593c 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -60,6 +60,8 @@ shared_library("jni") { android_library("java") { output_name = "CHIPController.jar" + deps = [ ":android" ] + data_deps = [ ":jni", "${chip_root}/build/chip/java:shared_cpplib", @@ -86,3 +88,7 @@ android_library("java") { # TODO: add classpath support (we likely need to add something like # ..../platforms/android-21/android.jar to access BLE items) } + +java_prebuilt("android") { + jar_path = "${android_sdk_root}/platforms/android-21/android.jar" +}