From 980ef49b0c61bd720c1412aebb151d2b9d8d4e7b Mon Sep 17 00:00:00 2001 From: Nikola Radakovic Date: Wed, 18 Mar 2026 14:20:33 +0100 Subject: [PATCH 1/2] Temp commit - Adding pkg_rules support --- MODULE.bazel | 1 + MODULE.bazel.lock | 4 +- rules/qnx/common/pkg.bzl | 109 +++++++++++++++++++++++++++++++++ rules/qnx/common/qnx_image.bzl | 96 +++++++++++++++++++++++++++++ rules/qnx/ifs.bzl | 90 +++++++-------------------- 5 files changed, 232 insertions(+), 68 deletions(-) create mode 100644 rules/qnx/common/pkg.bzl create mode 100644 rules/qnx/common/qnx_image.bzl diff --git a/MODULE.bazel b/MODULE.bazel index 16d44c2..5718365 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -45,3 +45,4 @@ bazel_dep(name = "tar.bzl", version = "0.7.0") bazel_dep(name = "score_tooling", version = "1.1.2") bazel_dep(name = "aspect_rules_lint", version = "2.3.0") bazel_dep(name = "buildifier_prebuilt", version = "8.5.1") +bazel_dep(name = "rules_pkg", version = "1.2.0") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 9f41a94..c8141b9 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -219,7 +219,8 @@ "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.1.0/MODULE.bazel": "9db8031e71b6ef32d1846106e10dd0ee2deac042bd9a2de22b4761b0c3036453", - "https://bcr.bazel.build/modules/rules_pkg/1.1.0/source.json": "fef768df13a92ce6067e1cd0cdc47560dace01354f1d921cfb1d632511f7d608", + "https://bcr.bazel.build/modules/rules_pkg/1.2.0/MODULE.bazel": "c7db3c2b407e673c7a39e3625dc05dc9f12d6682cbd82a3a5924a13b491eda7e", + "https://bcr.bazel.build/modules/rules_pkg/1.2.0/source.json": "9062e00845bf91a4247465d371baa837adf9b6ff44c542f73ba084f07667e1dc", "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc2/MODULE.bazel": "e17f94f8a347e2c808517b65d74988839d2d62daceb50073e44060193b785eb1", @@ -457,6 +458,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/0.7.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.0.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.1.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.2.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/4.0.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_proto/6.0.0-rc2/MODULE.bazel": "not found", diff --git a/rules/qnx/common/pkg.bzl b/rules/qnx/common/pkg.bzl new file mode 100644 index 0000000..a3bc096 --- /dev/null +++ b/rules/qnx/common/pkg.bzl @@ -0,0 +1,109 @@ +""" +Supports QNX FS image generation from rules_pkg providers. Filters rules_pkg +targets from srcs and generates QNX build file entries from their contents. +""" + +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@rules_pkg//pkg:providers.bzl", "PackageDirsInfo", "PackageFilegroupInfo", "PackageFilesInfo", "PackageSymlinkInfo") + +_DEFAULT_FILE_MODE = "0644" +_DEFAULT_DIR_MODE = "0755" +_DEFAULT_LINK_MODE = "0777" +_DEFAULT_UID = 0 +_DEFAULT_GID = 0 +_FIXED_MTIME = "2021-03-22-20:20:00" + +def _get_pkg_attr(attributes, field, default): + """Get a single field from a pkg_attributes dict, defaulting if absent or None.""" + if attributes == None: + return default + value = attributes.get(field) + if value == None: + return default + return value + +def qnx_build_inputs_from_pkg(ctx, pkg_srcs, per_file_attrs = None): + """Generate QNX build file and collect contents from rules_pkg sources. + + Args: + ctx: Rule context. + pkg_srcs: List of targets providing rules_pkg providers. + per_file_attrs: Optional list of extra attributes for file entries + (e.g. ["-optional"]). + Returns: + fs_contents: List of Files to include in the image. + build_file: Generated QNX build file. + """ + content = "[mtime={}]\n".format(_FIXED_MTIME) + fs_contents = [] + extra_attrs_str = "" + if per_file_attrs: + extra_attrs_str = " ".join(per_file_attrs) + " " + + for src in pkg_srcs: + # Normalize to lists of (provider, label) tuples regardless of source type + if PackageFilegroupInfo in src: + pfgi = src[PackageFilegroupInfo] + files_list = pfgi.pkg_files + dirs_list = pfgi.pkg_dirs + symlinks_list = pfgi.pkg_symlinks + elif ( + PackageFilesInfo in src or + PackageDirsInfo in src or + PackageSymlinkInfo in src + ): + # src.label is included in the manually-constructed tuples to match the (provider, label) structure from PackageFilegroupInfo. + files_list = [(src[PackageFilesInfo], src.label)] if PackageFilesInfo in src else [] + dirs_list = [(src[PackageDirsInfo], src.label)] if PackageDirsInfo in src else [] + symlinks_list = [(src[PackageSymlinkInfo], src.label)] if PackageSymlinkInfo in src else [] + else: + fail("Target {} does not provide any rules_pkg provider".format(src.label)) + + # Process directories + for pdi, _label in dirs_list: + mode = _get_pkg_attr(pdi.attributes, "mode", _DEFAULT_DIR_MODE) + uid = _get_pkg_attr(pdi.attributes, "uid", _DEFAULT_UID) + gid = _get_pkg_attr(pdi.attributes, "gid", _DEFAULT_GID) + for dir_path in pdi.dirs: + dir_path = paths.normalize(dir_path) + content += "[type=dir uid={} gid={} perms={}] /{}\n".format( + uid, + gid, + mode, + dir_path, + ) + + # Process files + for pfi, _label in files_list: + mode = _get_pkg_attr(pfi.attributes, "mode", _DEFAULT_FILE_MODE) + uid = _get_pkg_attr(pfi.attributes, "uid", _DEFAULT_UID) + gid = _get_pkg_attr(pfi.attributes, "gid", _DEFAULT_GID) + for dest, src_file in sorted(pfi.dest_src_map.items()): + content += "[{}uid={} gid={} perms={}] /{}={}\n".format( + extra_attrs_str, + uid, + gid, + mode, + dest, + src_file.path, + ) + fs_contents.append(src_file) + + # Process symlinks + for psi, _label in symlinks_list: + mode = _get_pkg_attr(psi.attributes, "mode", _DEFAULT_LINK_MODE) + uid = _get_pkg_attr(psi.attributes, "uid", _DEFAULT_UID) + gid = _get_pkg_attr(psi.attributes, "gid", _DEFAULT_GID) + dest = paths.normalize(psi.destination) + content += "[type=link uid={} gid={} perms={}] /{}={}\n".format( + uid, + gid, + mode, + dest, + psi.target, + ) + + build_file = ctx.actions.declare_file("{}_pkg_content.build".format(ctx.attr.name)) + ctx.actions.write(build_file, content) + + return fs_contents, build_file diff --git a/rules/qnx/common/qnx_image.bzl b/rules/qnx/common/qnx_image.bzl new file mode 100644 index 0000000..debeea7 --- /dev/null +++ b/rules/qnx/common/qnx_image.bzl @@ -0,0 +1,96 @@ +load(":common/pkg.bzl", "qnx_build_inputs_from_pkg") + +def _gen_main_build_file( + ctx, + extra_build_files, + global_attrs = None): + """ + Generates the main build file used to create a qnx6fs image. + + Args: + ctx: Context. + extra_build_files: extra build files to be appended + global_attrs: + Global options, apply to both the image and extra build files. + Accepts a list of a mix of strings or dicts, to represent static + options (e.g. -optional) or mapped values (e.g. block_size=4096) + + Returns: + main_{}.build + """ + file_name = "main_{}.build".format(ctx.attr.name) + main_build_file = ctx.actions.declare_file(file_name) + + content = "" + if global_attrs: + for attr in global_attrs: + if type(attr) == "string": + content += "[{}]\n".format(attr) + elif type(attr) == "dict": + for key, value in attr.items(): + content += "[{}={}]\n".format(key, value) + else: + fail("Unsupported attribute type '{}', must be string or dict".format(type(attr))) + + for build_file in extra_build_files: + content += "[+include] {}\n".format(build_file.path) + + ctx.actions.write(main_build_file, content) + + return main_build_file + +def gen_image_definition( + ctx, + srcs, + global_attrs = None, + extra_build_file = None, + extra_build_files = [], + repo_mapping = {}, + repo_mapping_srcs = None): + """ + Process inputs for QNX image definition, return contents and builds files. + + Args: + ctx: Rule context. + srcs: Input srcs for FS, can be mix of DUI, rules_pkg, and regular. + global_attrs: Attributes set globally on main build file. + extra_build_file: Additional build file to be included. + extra_build_files: Additional build files to be included after the + extra_build_file. + repo_mapping: Map of Bazel location expressions to hardcoded variable + names in extra build file. + repo_mapping_srcs: Bazel targets referenced in the location expressions + of repo_mapping. + Returns: + main_build_file: Main entrypoint QNX build file. + build_files: QNX build files inluded in the main. + fs_contents: Files to be included in the QNX image. + expanded_repo_map: Expanded Bazel locations with paths of files to be + included. + """ + + build_files = [] + fs_contents = [] + + # Add extra build files + build_files.append(extra_build_file) + build_files.extend(extra_build_files) + + # # Rules_pkg contents + pkg_contents, pkg_build_file = qnx_build_inputs_from_pkg( + ctx, + srcs, + per_file_attrs = None, + ) + + build_files.append(pkg_build_file) + fs_contents.extend(pkg_contents) + + # Generate main build file which imports others + main_build_file = _gen_main_build_file( + ctx, + build_files, + global_attrs, + ) + + return main_build_file, build_files, fs_contents diff --git a/rules/qnx/ifs.bzl b/rules/qnx/ifs.bzl index eb30cf1..613cbdc 100644 --- a/rules/qnx/ifs.bzl +++ b/rules/qnx/ifs.bzl @@ -20,31 +20,10 @@ other build files or perform other operations like packaging any file into the created IFS. """ -QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:ifs_toolchain_type" -TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type" - -# todo: Consider to contribute this to "@tar.bzl" -def _untar(ctx, tarball, output_folder): - tarball_as_list = tarball.files.to_list() - if len(tarball_as_list) > 1: - fail("Provided more then one tar-ball for one key.") - tarball = tarball_as_list[0] - bsdtar = ctx.toolchains[TAR_TOOLCHAIN] - - args = ctx.actions.args() - args.add("-x") - args.add("-C").add(output_folder.path) - args.add("-f").add(tarball.path) +load("@rules_pkg//pkg:providers.bzl", "PackageDirsInfo", "PackageFilegroupInfo", "PackageFilesInfo", "PackageSymlinkInfo") +load(":common/qnx_image.bzl", "gen_image_definition") - ctx.actions.run( - outputs = [output_folder], - inputs = [tarball], - arguments = [args], - executable = bsdtar.tarinfo.binary, - toolchain = TAR_TOOLCHAIN, - mnemonic = "Untar", - progress_message = "untar %{input}", - ) +QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:ifs_toolchain_type" def _qnx_ifs_impl(ctx): """ Implementation function of qnx_ifs rule. @@ -61,53 +40,37 @@ def _qnx_ifs_impl(ctx): fail("qnx_ifs.out must be a filename without path components, got: {}".format(out_name)) out_ifs = ctx.actions.declare_file(out_name) - ifs_tool_info = ctx.toolchains[QNX_FS_TOOLCHAIN].ifs_toolchain_info - main_build_file = ctx.file.build_file + main_build_file, build_files, fs_contents = gen_image_definition( + ctx, + srcs = ctx.attr.all_files, + extra_build_file = ctx.file.build_file, + extra_build_files = ctx.files.extra_build_files, + ) inputs.append(main_build_file) - inputs.extend(ctx.files.srcs) + inputs.extend(build_files) + inputs.extend(fs_contents) args = ctx.actions.args() - # Add -r roots BEFORE the build file, resolved relative to the main build file’s dir - for r in ctx.attr.search_roots: - # Normalize relative to the main build file’s directory - root_path = main_build_file.dirname + ("/" + r if not r.startswith("/") else r) - args.add("-r") - args.add(root_path) + args.add_all( + ctx.files.search_paths, + before_each = "-r", + ) args.add_all([ - main_build_file.path, + main_build_file_2.path, out_ifs.path, ]) - #Add env variables for bazel labels/targets - env_to_append = {} - env_to_append = env_to_append | ifs_tool_info.env - - for key, item in ctx.attr.ext_repo_mapping.items(): - env_to_append.update({key: ctx.expand_location(item)}) - - env_to_append.update({"MAIN_BUILD_FILE_DIR": main_build_file.dirname}) - - # Unpack tarballs and add locations as env variables - for key, tarball in ctx.attr.tars.items(): - unpacked_tarball = ctx.actions.declare_directory("{}_{}".format(ctx.attr.name, key)) - _untar(ctx, tarball, unpacked_tarball) - - env_to_append.update({key: unpacked_tarball.path}) - inputs.append(unpacked_tarball) - - print(env_to_append) - ctx.actions.run( outputs = [out_ifs], inputs = inputs, arguments = [args], executable = ifs_tool_info.executable, - env = env_to_append, + env = ifs_tool_info.env, tools = ifs_tool_info.tools, ) @@ -119,6 +82,9 @@ qnx_ifs = rule( implementation = _qnx_ifs_impl, toolchains = [QNX_FS_TOOLCHAIN, TAR_TOOLCHAIN], attrs = { + "all_files": attr.label_list( + mandatory = True, + ), "build_file": attr.label( allow_single_file = True, doc = "Single label that points to the main build file (entrypoint)", @@ -128,20 +94,10 @@ qnx_ifs = rule( default = "ifs", doc = "Extension for the generated IFS image. Manipulating this extensions is a workaround for IPNext startup code limitation, when interpreting ifs images. This attribute will either disappear or will be replaced by toolchain configuration in order to keep output files consistent.", ), - "srcs": attr.label_list( + "extra_build_files": attr.label_list( allow_files = True, - doc = "List of labels that are used by the `build_file`", - allow_empty = True, - ), - "ext_repo_mapping": attr.string_dict( - allow_empty = True, - default = {}, - doc = "We are using dict to map env. variables with of external repository", - ), - "tars": attr.string_keyed_label_dict( - allow_files = [".tar"], - doc = "A map of tar-balls that can be added to the IFS image. The key will be available als variable in the `IFS Build File`, to determine where it should be packaged. e.g. `FOO: '//:my_tar'` can be packaged as /SOME_DIR=${FOO}.", - allow_empty = True, + default = [], + doc = "Additional build files to be included after the main build_file.", ), "out": attr.string( default = "", From 215e11064cdf97e7549701828a35d0bd4945ac3e Mon Sep 17 00:00:00 2001 From: Nikola Radakovic Date: Mon, 23 Mar 2026 16:33:51 +0000 Subject: [PATCH 2/2] Refactor all IFS rules --- rules/qnx/common/attrs.bzl | 69 ++++++++++++++++++ rules/qnx/common/common.bzl | 120 +++++++++++++++++++++++++++++++ rules/qnx/common/pkg.bzl | 15 +++- rules/qnx/common/qnx_image.bzl | 23 +++--- rules/qnx/fatfs.bzl | 126 ++++----------------------------- rules/qnx/ifs.bzl | 82 +++++---------------- rules/qnx/qnx6fs.bzl | 115 +++--------------------------- toolchains/qnx/toolchains.bzl | 4 +- 8 files changed, 265 insertions(+), 289 deletions(-) create mode 100644 rules/qnx/common/attrs.bzl create mode 100644 rules/qnx/common/common.bzl diff --git a/rules/qnx/common/attrs.bzl b/rules/qnx/common/attrs.bzl new file mode 100644 index 0000000..255f973 --- /dev/null +++ b/rules/qnx/common/attrs.bzl @@ -0,0 +1,69 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +""" +Common attribute definitions for QNX image generation Bazel rules. + +This module defines a shared attribute dictionary (`COMMON_RULES_ATTRS`) used +across rules responsible for generating QNX IFS images. These attributes +standardize how input files, build definitions, and output artifacts are +specified and handled within the rule implementations. + +Attributes: + all_files (label_list, mandatory): + Collection of input targets contributing to the filesystem image. + This may include DUI files, `rules_pkg` outputs, and regular files. + + build_file (label, mandatory): + Label pointing to the main QNX build file (entry point). Must resolve + to a single file. + + extension (string, default = "ifs"): + File extension for the generated IFS image. This exists primarily as a + workaround for limitations in IPNext startup code when interpreting IFS + images. This attribute is expected to be deprecated or replaced by a + toolchain-based configuration in the future to ensure consistency. + + extra_build_files (label_list, default = []): + Additional build files to be included after the main `build_file`. + These are appended in order and allow modularization of build logic. + + out (string, default = ""): + Optional explicit name for the output file (must not include path + components). If not provided, the output filename is derived as: + `.`. +""" + +COMMON_RULES_ATTRS = { + "all_files": attr.label_list( + mandatory = True, + ), + "build_file": attr.label( + allow_single_file = True, + doc = "Single label that points to the main build file (entrypoint)", + mandatory = True, + ), + "extension": attr.string( + default = "ifs", + doc = "Extension for the generated IFS image. Manipulating this extensions is a workaround for IPNext startup code limitation, when interpreting ifs images. This attribute will either disappear or will be replaced by toolchain configuration in order to keep output files consistent.", + ), + "extra_build_files": attr.label_list( + allow_files = True, + default = [], + doc = "Additional build files to be included after the main build_file.", + ), + "out": attr.string( + default = "", + doc = "Optional explicit output filename (no path). If empty, uses name + '.' + extension.", + ), +} diff --git a/rules/qnx/common/common.bzl b/rules/qnx/common/common.bzl new file mode 100644 index 0000000..5c9755e --- /dev/null +++ b/rules/qnx/common/common.bzl @@ -0,0 +1,120 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +""" TODO: Write docstrings +""" + +def prep_output(ctx): + """ + Determines and declares the output file for the QNX image build action. + + This function resolves the output filename based on rule attributes. If + `ctx.attr.out` is explicitly provided, it is used directly; otherwise, the + filename is derived from the rule name and the specified extension. The + function validates that the resulting filename does not contain any path + components, ensuring it represents a single artifact in the current package. + It then declares the output file via `ctx.actions.declare_file`. + + Args: + ctx: The rule context (`RuleContext`) provided by Bazel. It is expected + to expose the following attributes: + - ctx.attr.out: Optional explicit output filename. + - ctx.attr.name: Name of the rule, used as a fallback prefix. + - ctx.attr.extension: File extension used when `out` is not provided. + + Returns: + File: A declared output `File` object representing the generated QNX + image artifact. + + Raises: + Fail: If the resolved output name contains path separators (i.e., is not + a simple filename). + """ + out_name = ctx.attr.out if ctx.attr.out else "{}.{}".format(ctx.attr.name, ctx.attr.extension) + if "/" in out_name: + fail("qnx_ifs.out must be a filename without path components, got: {}".format(out_name)) + + return ctx.actions.declare_file(out_name) + +def prep_inputs(ctx): + """ + Prepares and aggregates input files required for QNX image generation. + + This function invokes `gen_image_definition` to resolve the QNX image + definition artifacts, including the main build file, any included build + files, and filesystem contents. It then appends these artifacts to the + `inputs` collection, which is intended to be consumed by a downstream + Bazel action. Additionally, it returns the path to the main build file, + which typically serves as the entry point for the image generation process. + + Args: + ctx: The rule context (`RuleContext`) provided by Bazel. It is expected + to expose the following attributes: + - ctx.attr.all_files: Combined set of source inputs (e.g., DUI, + rules_pkg outputs, and regular files). + - ctx.file.build_file: Optional main build file. + - ctx.files.extra_build_files: Additional build files to be included. + + Returns: + A tuple containing: + - main_build_file.path (str): Filesystem path to the main QNX build + file used as the entry point. + - inputs (list[File]): List of input `File` objects including the + main build file, additional build files, and filesystem contents. + """ + main_build_file, build_files, fs_contents = gen_image_definition( + ctx, + srcs = ctx.attr.all_files, + extra_build_file = ctx.file.build_file, + extra_build_files = ctx.files.extra_build_files, + ) + + inputs.append(main_build_file) + inputs.extend(build_files) + inputs.extend(fs_contents) + + return main_build_file.path, inputs + +def gen_image(ctx, inputs, outputs, arguments, image_tc_type): + """ + Executes an image generation action by invoking a selected tool. + + This function registers a `ctx.actions.run` action that uses the specified + executable and environment from `tool_info` to transform `inputs` into + `outputs`. It then returns a `DefaultInfo` provider exposing the generated + output files. + + Args: + ctx: The rule context (`RuleContext`) provided by Bazel. Used to declare + and register build actions. + inputs: A sequence or depset of input `File` objects required by the + action. + outputs: A list of output `File` objects that will be generated by the + action. + arguments: A list of command-line arguments passed to the executable. + image_tc_type: . + + Returns: + A list containing a single `DefaultInfo` provider, where `files` is a + depset of the generated output files. + """ + tool_info = ctx.toolchains[image_tc_type].imagefs_toolchain_info + ctx.actions.run( + outputs = outputs, + inputs = inputs, + arguments = arguments, + executable = tool_info.executable, + env = tool_info.env, + tools = tool_info.tools, + ) + return [DefaultInfo(files = depset(outputs))] diff --git a/rules/qnx/common/pkg.bzl b/rules/qnx/common/pkg.bzl index a3bc096..657723b 100644 --- a/rules/qnx/common/pkg.bzl +++ b/rules/qnx/common/pkg.bzl @@ -1,5 +1,18 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + """ -Supports QNX FS image generation from rules_pkg providers. Filters rules_pkg +Supports QNX zzzzzzzzzzzzzzzzzzzzzzzzzzzzFS image generation from rules_pkg providers. Filters rules_pkg targets from srcs and generates QNX build file entries from their contents. """ diff --git a/rules/qnx/common/qnx_image.bzl b/rules/qnx/common/qnx_image.bzl index debeea7..ad2e143 100644 --- a/rules/qnx/common/qnx_image.bzl +++ b/rules/qnx/common/qnx_image.bzl @@ -1,3 +1,16 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + load(":common/pkg.bzl", "qnx_build_inputs_from_pkg") def _gen_main_build_file( @@ -44,9 +57,7 @@ def gen_image_definition( srcs, global_attrs = None, extra_build_file = None, - extra_build_files = [], - repo_mapping = {}, - repo_mapping_srcs = None): + extra_build_files = []): """ Process inputs for QNX image definition, return contents and builds files. @@ -57,10 +68,6 @@ def gen_image_definition( extra_build_file: Additional build file to be included. extra_build_files: Additional build files to be included after the extra_build_file. - repo_mapping: Map of Bazel location expressions to hardcoded variable - names in extra build file. - repo_mapping_srcs: Bazel targets referenced in the location expressions - of repo_mapping. Returns: main_build_file: Main entrypoint QNX build file. build_files: QNX build files inluded in the main. @@ -77,7 +84,7 @@ def gen_image_definition( build_files.extend(extra_build_files) # # Rules_pkg contents - pkg_contents, pkg_build_file = qnx_build_inputs_from_pkg( + pkg_contents, pkg_build_file = _qnx_build_inputs_from_pkg( ctx, srcs, per_file_attrs = None, diff --git a/rules/qnx/fatfs.bzl b/rules/qnx/fatfs.bzl index 2a5edf9..49187c5 100644 --- a/rules/qnx/fatfs.bzl +++ b/rules/qnx/fatfs.bzl @@ -18,131 +18,35 @@ The user provides a main build file and supporting files. The main build file is used as the entrypoint for mkfatfsimg to create the FAT filesystem image. """ -QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:fatfs_toolchain_type" -TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type" - -# todo: Consider to contribute this to "@tar.bzl" -def _untar(ctx, tarball, output_folder): - tarball_as_list = tarball.files.to_list() - if len(tarball_as_list) > 1: - fail("Provided more then one tar-ball for one key.") - tarball = tarball_as_list[0] - bsdtar = ctx.toolchains[TAR_TOOLCHAIN] +load(":common/common.bzl", "gen_image", "prep_inputs", "prep_output", _common_rule_attrs = "COMMON_RULES_ATTRS") - args = ctx.actions.args() - args.add("-x") - args.add("-C").add(output_folder.path) - args.add("-f").add(tarball.path) - - ctx.actions.run( - outputs = [output_folder], - inputs = [tarball], - arguments = [args], - executable = bsdtar.tarinfo.binary, - toolchain = TAR_TOOLCHAIN, - mnemonic = "Untar", - progress_message = "untar %{input}", - ) +QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:fatfs_toolchain_type" def _fatfs_impl(ctx): - """ Implementation function of fatfs rule. + """ Implementation function of _fatfs rule. - This function uses mkfatfsimg to create a FAT filesystem image - from the provided build file. + This function will merge all .build files into main .build file and + produce flashable QNX image. """ - inputs = [] - - # Choose output filename - out_name = ctx.attr.out if ctx.attr.out else "{}.{}".format(ctx.attr.name, ctx.attr.extension) - if "/" in out_name: - fail("fatfs.out must be a filename without path components, got: {}".format(out_name)) - - out_img = ctx.actions.declare_file(out_name) - - fatfs_tool_info = ctx.toolchains[QNX_FS_TOOLCHAIN].ifs_toolchain_info - - main_build_file = ctx.file.build_file - - inputs.append(main_build_file) - inputs.extend(ctx.files.srcs) + out_image = prep_output(ctx) + main_build_file_string_path, inputs = prep_inputs(ctx) args = ctx.actions.args() - args.add_all([ "-n", - main_build_file.path, - out_img.path, + main_build_file_string_path, + out_image.path, ]) - #Add env variables for bazel labels/targets - env_to_append = {} - env_to_append = env_to_append | fatfs_tool_info.env - - for key, item in ctx.attr.ext_repo_mapping.items(): - env_to_append.update({key: ctx.expand_location(item)}) - - for key, item in ctx.attr.ext_repo_dir_mapping.items(): - expanded = ctx.expand_location(item) - dir_path = expanded.rsplit("/", 1)[0] if "/" in expanded else expanded - env_to_append.update({key: dir_path}) - - # Unpack tarballs and add locations as env variables - for key, tarball in ctx.attr.tars.items(): - unpacked_tarball = ctx.actions.declare_directory("{}_{}".format(ctx.attr.name, key)) - _untar(ctx, tarball, unpacked_tarball) - - env_to_append.update({key: unpacked_tarball.path}) - inputs.append(unpacked_tarball) - - ctx.actions.run( - outputs = [out_img], + return gen_image( inputs = inputs, + outputs = [out_image], arguments = [args], - executable = fatfs_tool_info.executable, - env = env_to_append, - tools = fatfs_tool_info.tools, + image_tc_type = QNX_FS_TOOLCHAIN, ) - return [ - DefaultInfo(files = depset([out_img])), - ] - -fatfs = rule( +qnx6fs = rule( implementation = _fatfs_impl, - toolchains = [QNX_FS_TOOLCHAIN, TAR_TOOLCHAIN], - attrs = { - "build_file": attr.label( - allow_single_file = True, - doc = "Single label that points to the main build file (entrypoint)", - mandatory = True, - ), - "extension": attr.string( - default = "img", - doc = "Extension for the generated FAT filesystem image.", - ), - "srcs": attr.label_list( - allow_files = True, - doc = "List of labels that are used by the `build_file`", - allow_empty = True, - ), - "ext_repo_mapping": attr.string_dict( - allow_empty = True, - default = {}, - doc = "We are using dict to map env. variables with of external repository", - ), - "ext_repo_dir_mapping": attr.string_dict( - allow_empty = True, - default = {}, - doc = "Like ext_repo_mapping, but resolves to the parent directory of the located file. Use a single-file target as an anchor to obtain the directory path.", - ), - "tars": attr.string_keyed_label_dict( - allow_files = [".tar"], - doc = "A map of tar-balls that can be added to the FAT filesystem image. The key will be available as a variable in the build file, to determine where it should be packaged. e.g. `FOO: '//:my_tar'` can be packaged as /SOME_DIR=${FOO}.", - allow_empty = True, - ), - "out": attr.string( - default = "", - doc = "Optional explicit output filename (no path). If empty, uses name + '.' + extension.", - ), - }, + toolchains = [QNX_FS_TOOLCHAIN], + attrs = _common_rule_attrs, ) diff --git a/rules/qnx/ifs.bzl b/rules/qnx/ifs.bzl index 613cbdc..3e70429 100644 --- a/rules/qnx/ifs.bzl +++ b/rules/qnx/ifs.bzl @@ -20,92 +20,48 @@ other build files or perform other operations like packaging any file into the created IFS. """ -load("@rules_pkg//pkg:providers.bzl", "PackageDirsInfo", "PackageFilegroupInfo", "PackageFilesInfo", "PackageSymlinkInfo") -load(":common/qnx_image.bzl", "gen_image_definition") +load(":common/common.bzl", "gen_image", "prep_inputs", "prep_output", _common_rule_attrs = "COMMON_RULES_ATTRS") QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:ifs_toolchain_type" +_attrs_ifs_rules = {} +_attrs_ifs_rules.update(_common_rule_attrs) +_attrs_ifs_rules.update({ + "search_roots": attr.string_list( + default = [], + doc = "List of paths for mkifs -r, each relative to the main build file's directory (or absolute).", + ), +}) + def _qnx_ifs_impl(ctx): """ Implementation function of qnx_ifs rule. This function will merge all .build files into main .build file and produce flashable QNX image. """ - inputs = [] - extra_build_files = [] - - # Choose output filename - out_name = ctx.attr.out if ctx.attr.out else "{}.{}".format(ctx.attr.name, ctx.attr.extension) - if "/" in out_name: - fail("qnx_ifs.out must be a filename without path components, got: {}".format(out_name)) - - out_ifs = ctx.actions.declare_file(out_name) - ifs_tool_info = ctx.toolchains[QNX_FS_TOOLCHAIN].ifs_toolchain_info - - main_build_file, build_files, fs_contents = gen_image_definition( - ctx, - srcs = ctx.attr.all_files, - extra_build_file = ctx.file.build_file, - extra_build_files = ctx.files.extra_build_files, - ) - inputs.append(main_build_file) - inputs.extend(build_files) - inputs.extend(fs_contents) + out_image = prep_output(ctx) + main_build_file_string_path, inputs = prep_inputs(ctx) args = ctx.actions.args() - args.add_all( ctx.files.search_paths, before_each = "-r", ) - args.add_all([ - main_build_file_2.path, - out_ifs.path, + main_build_file_string_path, + out_image.path, ]) - ctx.actions.run( - outputs = [out_ifs], + return gen_image( inputs = inputs, + outputs = [out_image], arguments = [args], - executable = ifs_tool_info.executable, - env = ifs_tool_info.env, - tools = ifs_tool_info.tools, + image_tc_type = QNX_FS_TOOLCHAIN, ) - return [ - DefaultInfo(files = depset([out_ifs])), - ] - qnx_ifs = rule( implementation = _qnx_ifs_impl, - toolchains = [QNX_FS_TOOLCHAIN, TAR_TOOLCHAIN], - attrs = { - "all_files": attr.label_list( - mandatory = True, - ), - "build_file": attr.label( - allow_single_file = True, - doc = "Single label that points to the main build file (entrypoint)", - mandatory = True, - ), - "extension": attr.string( - default = "ifs", - doc = "Extension for the generated IFS image. Manipulating this extensions is a workaround for IPNext startup code limitation, when interpreting ifs images. This attribute will either disappear or will be replaced by toolchain configuration in order to keep output files consistent.", - ), - "extra_build_files": attr.label_list( - allow_files = True, - default = [], - doc = "Additional build files to be included after the main build_file.", - ), - "out": attr.string( - default = "", - doc = "Optional explicit output filename (no path). If empty, uses name + '.' + extension.", - ), - "search_roots": attr.string_list( - default = [], - doc = "List of paths for mkifs -r, each relative to the main build file's directory (or absolute).", - ), - }, + toolchains = [QNX_FS_TOOLCHAIN], + attrs = _attrs_ifs_rules, ) diff --git a/rules/qnx/qnx6fs.bzl b/rules/qnx/qnx6fs.bzl index 7031368..7c2f415 100644 --- a/rules/qnx/qnx6fs.bzl +++ b/rules/qnx/qnx6fs.bzl @@ -11,31 +11,9 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:qnx6fs_toolchain_type" -TAR_TOOLCHAIN = "@tar.bzl//tar/toolchain:type" - -# todo: Consider to contribute this to "@tar.bzl" -def _untar(ctx, tarball, output_folder): - tarball_as_list = tarball.files.to_list() - if len(tarball_as_list) > 1: - fail("Provided more then one tar-ball for one key.") - tarball = tarball_as_list[0] - bsdtar = ctx.toolchains[TAR_TOOLCHAIN] +load(":common/common.bzl", "gen_image", "prep_inputs", "prep_output", _common_rule_attrs = "COMMON_RULES_ATTRS") - args = ctx.actions.args() - args.add("-x") - args.add("-C").add(output_folder.path) - args.add("-f").add(tarball.path) - - ctx.actions.run( - outputs = [output_folder], - inputs = [tarball], - arguments = [args], - executable = bsdtar.tarinfo.binary, - toolchain = TAR_TOOLCHAIN, - mnemonic = "Untar", - progress_message = "untar %{input}", - ) +QNX_FS_TOOLCHAIN = "@score_rules_imagefs//toolchains/qnx:qnx6fs_toolchain_type" def _qnx6fs_impl(ctx): """ Implementation function of qnx_ifs rule. @@ -43,96 +21,25 @@ def _qnx6fs_impl(ctx): This function will merge all .build files into main .build file and produce flashable QNX image. """ - inputs = [] - extra_build_files = [] - - # Choose output filename - out_name = ctx.attr.out if ctx.attr.out else "{}.{}".format(ctx.attr.name, ctx.attr.extension) - if "/" in out_name: - fail("qnx6fs.out must be a filename without path components, got: {}".format(out_name)) - - out_img = ctx.actions.declare_file(out_name) - - qnx6fs_tool_info = ctx.toolchains[QNX_FS_TOOLCHAIN].ifs_toolchain_info - - main_build_file = ctx.file.build_file - - inputs.append(main_build_file) - inputs.extend(ctx.files.srcs) + out_image = prep_output(ctx) + main_build_file_string_path, inputs = prep_inputs(ctx) args = ctx.actions.args() - args.add_all([ "-n", - main_build_file.path, - out_img.path, + main_build_file_string_path, + out_image.path, ]) - #Add env variables for bazel labels/targets - env_to_append = {} - env_to_append = env_to_append | qnx6fs_tool_info.env - - for key, item in ctx.attr.ext_repo_mapping.items(): - env_to_append.update({key: ctx.expand_location(item)}) - - # Unpack tarballs and add locations as env variables - for key, tarball in ctx.attr.tars.items(): - unpacked_tarball = ctx.actions.declare_directory("{}_{}".format(ctx.attr.name, key)) - _untar(ctx, tarball, unpacked_tarball) - - env_to_append.update({key: unpacked_tarball.path}) - inputs.append(unpacked_tarball) - - print(env_to_append) - - ctx.actions.run( - outputs = [out_img], + return gen_image( inputs = inputs, + outputs = [out_image], arguments = [args], - executable = qnx6fs_tool_info.executable, - env = env_to_append, - tools = qnx6fs_tool_info.tools, + image_tc_type = QNX_FS_TOOLCHAIN, ) - return [ - DefaultInfo(files = depset([out_img])), - ] - qnx6fs = rule( implementation = _qnx6fs_impl, - toolchains = [QNX_FS_TOOLCHAIN, TAR_TOOLCHAIN], - attrs = { - "build_file": attr.label( - allow_single_file = True, - doc = "Single label that points to the main build file (entrypoint)", - mandatory = True, - ), - "extension": attr.string( - default = "img", - doc = "Extension for the generated IFS image. Manipulating this extensions is a workaround for IPNext startup code limitation, when interpreting ifs images. This attribute will either disappear or will be replaced by toolchain configuration in order to keep output files consistent.", - ), - "srcs": attr.label_list( - allow_files = True, - doc = "List of labels that are used by the `build_file`", - allow_empty = True, - ), - "ext_repo_mapping": attr.string_dict( - allow_empty = True, - default = {}, - doc = "We are using dict to map env. variables with of external repository", - ), - "tars": attr.string_keyed_label_dict( - allow_files = [".tar"], - doc = "A map of tar-balls that can be added to the IFS image. The key will be available als variable in the `IFS Build File`, to determine where it should be packaged. e.g. `FOO: '//:my_tar'` can be packaged as /SOME_DIR=${FOO}.", - allow_empty = True, - ), - "out": attr.string( - default = "", - doc = "Optional explicit output filename (no path). If empty, uses name + '.' + extension.", - ), - "search_roots": attr.string_list( - default = [], - doc = "List of paths for mkifs -r, each relative to the main build file's directory (or absolute).", - ), - }, + toolchains = [QNX_FS_TOOLCHAIN], + attrs = _common_rule_attrs, ) diff --git a/toolchains/qnx/toolchains.bzl b/toolchains/qnx/toolchains.bzl index a11e9dc..a0682cd 100644 --- a/toolchains/qnx/toolchains.bzl +++ b/toolchains/qnx/toolchains.bzl @@ -14,7 +14,7 @@ """ Toolchain provider implementation for QNX filesystem image rules. """ -IFSToolchainInfo = provider( +ImageFSToolchainInfo = provider( doc = "Executable for generating QNX filesystems.", fields = ["executable", "tools", "env"], ) @@ -39,7 +39,7 @@ def _impl(ctx): return [ platform_common.ToolchainInfo( - ifs_toolchain_info = IFSToolchainInfo( + imagefs_toolchain_info = ImageFSToolchainInfo( executable = ctx.executable.executable, tools = depset(ctx.files.host + ctx.files.target, transitive = [ctx.attr.executable.default_runfiles.files]), env = env,