From 45f623b73cbdc4a304579882aeb00163f28fd192 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Thu, 19 May 2022 17:32:51 +0200 Subject: [PATCH] [Tizen] Create TPK flashbundle with Tizen GN SDK (#18298) --- build_overrides/tizen.gni | 5 +- examples/build_overrides/tizen.gni | 5 +- examples/lighting-app/tizen/BUILD.gn | 12 +++ scripts/build/builders/tizen.py | 52 +-------- third_party/tizen/tizen_manifest_parser.py | 73 +++++++++++++ third_party/tizen/tizen_sdk.gni | 118 +++++++++++++++++++++ 6 files changed, 216 insertions(+), 49 deletions(-) create mode 100755 third_party/tizen/tizen_manifest_parser.py create mode 100644 third_party/tizen/tizen_sdk.gni diff --git a/build_overrides/tizen.gni b/build_overrides/tizen.gni index c98c7998f02fd5..34914ce0cc0427 100644 --- a/build_overrides/tizen.gni +++ b/build_overrides/tizen.gni @@ -13,6 +13,9 @@ # limitations under the License. declare_args() { - # Root directory for tizen. + # Root directory for Tizen. tizen_root = "//config/tizen/chip-gn/platform" + + # Root directory for Tizen SDK build support. + tizen_sdk_build_root = "//third_party/tizen" } diff --git a/examples/build_overrides/tizen.gni b/examples/build_overrides/tizen.gni index 29a2771956f249..110a27186b7e3f 100644 --- a/examples/build_overrides/tizen.gni +++ b/examples/build_overrides/tizen.gni @@ -13,6 +13,9 @@ # limitations under the License. declare_args() { - # Root directory for tizen. + # Root directory for Tizen. tizen_root = "//third_party/connectedhomeip/config/tizen/chip-gn/platform" + + # Root directory for Tizen SDK build support. + tizen_sdk_build_root = "//third_party/connectedhomeip/third_party/tizen" } diff --git a/examples/lighting-app/tizen/BUILD.gn b/examples/lighting-app/tizen/BUILD.gn index e43e377860c51b..b45574db92b349 100644 --- a/examples/lighting-app/tizen/BUILD.gn +++ b/examples/lighting-app/tizen/BUILD.gn @@ -13,9 +13,11 @@ # limitations under the License. import("//build_overrides/chip.gni") +import("//build_overrides/tizen.gni") import("${chip_root}/build/chip/tools.gni") import("${chip_root}/src/app/common_flags.gni") +import("${tizen_sdk_build_root}/tizen_sdk.gni") assert(chip_build_tools) @@ -41,10 +43,20 @@ executable("chip-lighting-app") { output_dir = root_out_dir } +tizen_sdk_package("chip-lighting-app:tpk") { + deps = [ ":chip-lighting-app" ] + manifest = rebase_path("tizen-manifest.xml") + sign_security_profile = "CHIP" +} + group("tizen") { deps = [ ":chip-lighting-app" ] } +group("tizen:tpk") { + deps = [ ":chip-lighting-app:tpk" ] +} + group("default") { deps = [ ":tizen" ] } diff --git a/scripts/build/builders/tizen.py b/scripts/build/builders/tizen.py index 077de00d20a19b..efaf444a8568a4 100644 --- a/scripts/build/builders/tizen.py +++ b/scripts/build/builders/tizen.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging import os -import shutil from enum import Enum, auto from xml.etree import ElementTree as ET @@ -41,9 +41,6 @@ def PackageName(self): def PackageVersion(self): return self.manifest.get('version') - def PackageExecName(self): - return self.manifest.find('{*}service-application').get('exec') - def parse_manifest(self, manifest: str): self.manifest = ET.parse(manifest).getroot() @@ -112,48 +109,9 @@ def GnBuildArgs(self): ] def _generate_flashbundle(self): - - self.tizen_tpk_dir = os.path.join(self.output_dir, "tpk") - self.tizen_out_dir = os.path.join(self.tizen_tpk_dir, "out") - - # Create dirrectory where the TPK package file will be created - os.makedirs(self.tizen_out_dir, exist_ok=True) - - # Create a dummy project definition file, so the Tizen Studio CLI - # will recognize given directory as a Tizen project. - prj_def_file = os.path.join(self.tizen_tpk_dir, "project_def.prop") - with open(prj_def_file, "w") as f: - f.writelines(l + "\n" for l in [ - "# Generated by the build script. DO NOT EDIT!", - "APPNAME = %s" % self.app.AppName(), - "type = app", - ]) - - # Create a dummy project file, so the Tizen Studio CLI will not - # complain about invalid XPath (this file is not used anyway...) - prj_file = os.path.join(self.tizen_tpk_dir, ".project") - with open(prj_file, "w") as f: - f.writelines(l + "\n" for l in [ - "", - "", - ]) - - # Copy Tizen manifest file into the dummy Tizen project. - shutil.copy( - os.path.join(self.root, "tizen-manifest.xml"), - self.tizen_tpk_dir) - - # Create link with the application executable in the TPK package - # directory. This linked file will be used by the Tizen Studio CLI - # when creating TPK package. - exec = os.path.join(self.tizen_out_dir, self.app.PackageExecName()) - if not os.path.exists(exec): - os.symlink(os.path.join(self.output_dir, self.app.AppName()), - exec) - - self._Execute([self.tizen_sdk_cli, 'package', '--type', 'tpk', - '--sign', 'CHIP', '--', self.tizen_out_dir], - title='Generating TPK file for ' + self.identifier) + logging.info('Packaging %s', self.output_dir) + cmd = ['ninja', '-C', self.output_dir, self.app.AppName() + ':tpk'] + self._Execute(cmd, title='Packaging ' + self.identifier) def build_outputs(self): return { @@ -166,5 +124,5 @@ def build_outputs(self): def flashbundle(self): tpk = f'{self.app.PackageName()}-{self.app.PackageVersion()}.tpk' return { - tpk: os.path.join(self.tizen_out_dir, tpk), + tpk: os.path.join(self.output_dir, 'package', 'out', tpk), } diff --git a/third_party/tizen/tizen_manifest_parser.py b/third_party/tizen/tizen_manifest_parser.py new file mode 100755 index 00000000000000..3266a4adcb858e --- /dev/null +++ b/third_party/tizen/tizen_manifest_parser.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# Copyright (c) 2022 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 argparse +import json +from xml.etree import ElementTree as ET + + +class TizenManifest: + + def __init__(self, manifest): + self.manifest = ET.parse(manifest).getroot() + + def _get_application(self, apptype): + return self.manifest.find("{*}" + apptype) + + def get_package_name(self): + return self.manifest.get("package") + + def get_package_version(self): + return self.manifest.get("version") + + def get_service_exec(self): + app = self._get_application("service-application") + return app.get("exec", "") if app else "" + + def get_ui_exec(self): + app = self._get_application("ui-application") + return app.get("exec", "") if app else "" + + def get_watch_exec(self): + app = self._get_application("watch-application") + return app.get("exec", "") if app else "" + + def get_widget_exec(self): + app = self._get_application("widget-application") + return app.get("exec", "") if app else "" + + +if __name__ == '__main__': + + parser = argparse.ArgumentParser( + description="Tool for extracting data from Tizen XML manifest file") + parser.add_argument('MANIFEST', help="Tizen manifest XML file") + + args = parser.parse_args() + manifest = TizenManifest(args.MANIFEST) + + print(json.dumps({ + 'package': { + 'name': manifest.get_package_name(), + 'version': manifest.get_package_version(), + }, + 'apps': { + 'service': manifest.get_service_exec(), + 'ui': manifest.get_ui_exec(), + 'watch': manifest.get_watch_exec(), + 'widget': manifest.get_widget_exec(), + } + })) diff --git a/third_party/tizen/tizen_sdk.gni b/third_party/tizen/tizen_sdk.gni new file mode 100644 index 00000000000000..dc17cf701fc762 --- /dev/null +++ b/third_party/tizen/tizen_sdk.gni @@ -0,0 +1,118 @@ +# Copyright (c) 2020 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/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/tizen.gni") + +import("${build_root}/config/tizen/config.gni") + +tizen_manifest_parser = rebase_path("tizen_manifest_parser.py") + +template("tizen_sdk") { + forward_variables_from(invoker, + [ + "project_build_dir", + "project_app_name", + ]) + + if (!defined(project_app_name)) { + project_app_name = "tizen-app" + } + + # Create a dummy project definition file, so the Tizen Studio CLI + # will recognize our build directory as a Tizen project. + write_file("${project_build_dir}/project_def.prop", + [ + "# Generated by the GN script. DO NOT EDIT!", + "APPNAME = " + project_app_name, + "type = app", + ]) + + # Create a dummy project file, so the Tizen Studio CLI will not + # complain about invalid XPath (this file is not used anyway...) + write_file("${project_build_dir}/.project", + [ + "", + "", + ]) + + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "outputs", + ]) + script = "${build_root}/gn_run_binary.py" + args = [ "${tizen_sdk_root}/tools/ide/bin/tizen" ] + invoker.args + } +} + +template("tizen_sdk_package") { + # Output directory where packaging will occur. We need a separate directory + # for this, because Tizen Studio CLI scans "res" (resources), "shared" and + # "lib" directories for items to pack. In our case it could include in the + # TPK package libraries available in ${root_build_dir}/lib directory. + tizen_package_dir = "${root_build_dir}/package" + tizen_package_out_dir = "${tizen_package_dir}/out" + + assert(defined(invoker.manifest), + "It is required to specify Tizen `manifest` XML file.") + assert(defined(invoker.sign_security_profile), + "It is required to specify a `sign_security_profile` which " + + "should be used for signing TPK package.") + + # Extract data from Tizen XML manifest. + manifest = exec_script(tizen_manifest_parser, [ invoker.manifest ], "json") + manifest_package = manifest["package"] + manifest_apps = manifest["apps"] + + # Copy Tizen manifest from the source directory. + copy("${target_name}:manifest") { + sources = [ invoker.manifest ] + outputs = [ "${tizen_package_dir}/{{source_file_part}}" ] + deps = invoker.deps + } + + # List of dependencies for Tizen Studio CLI packager. + dependencies = [ ":${target_name}:manifest" ] + + # Copy executable(s) to temporary output directory. This action is required, + # because Tizen Studio CLI expects particular directory layout - it is not + # possible to specify input files manually. + if (manifest_apps["service"] != "") { + dependencies += [ ":${target_name}:app:service" ] + copy("${target_name}:app:service") { + sources = [ root_build_dir + "/" + manifest_apps["service"] ] + outputs = [ "${tizen_package_out_dir}/{{source_file_part}}" ] + deps = invoker.deps + } + } + + tpk = manifest_package["name"] + "-" + manifest_package["version"] + ".tpk" + tizen_sdk(target_name) { + deps = invoker.deps + dependencies + outputs = [ "${tizen_package_out_dir}/" + tpk ] + project_build_dir = tizen_package_dir + args = [ + "package", + "--type", + "tpk", + "--sign", + invoker.sign_security_profile, + "--", + tizen_package_out_dir, + ] + } +}