| # Copyright 2024 The Pigweed 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 |
| # |
| # https://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. |
| |
| load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") |
| load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") |
| load("@pigweed//pw_build:binary_tools.bzl", "run_action_on_executable") |
| load("@pigweed//pw_build/bazel_internal:pigweed_internal.bzl", "compile_cc") |
| load("@rules_cc//cc:action_names.bzl", "CPP_LINK_EXECUTABLE_ACTION_NAME", "C_COMPILE_ACTION_NAME") |
| |
| def _get_inputs(ctx): |
| all_input_files = [ctx.file.overlay] |
| for label in ctx.attr.references: |
| if type(label) == "Target" and label.files.to_list(): |
| all_input_files.extend(label.files.to_list()) |
| else: |
| fail("Unsupported target kind in references:", label) |
| return depset(all_input_files) |
| |
| def _package_exec_path(ctx): |
| workspace_name = ctx.label.workspace_name |
| if workspace_name == "": |
| return "." |
| return "external/" + workspace_name + "/" + ctx.label.package |
| |
| def _dts_library_impl(ctx): |
| sources = [ctx.file.overlay] |
| include_paths = ctx.attr.includes |
| output_header = ctx.actions.declare_file(ctx.label.name + ".dts") |
| cc_toolchain = find_cpp_toolchain(ctx) |
| workspace_root = ctx.label.workspace_root |
| zephyr_root = Label("@zephyr//:west.yml").workspace_root |
| feature_configuration = cc_common.configure_features( |
| ctx = ctx, |
| cc_toolchain = cc_toolchain, |
| requested_features = ctx.features, |
| unsupported_features = ctx.disabled_features, |
| ) |
| cxx_compiler_path = cc_common.get_tool_for_action( |
| feature_configuration = feature_configuration, |
| action_name = C_COMPILE_ACTION_NAME, |
| ) |
| |
| print("Declaring file: ", output_header.path) |
| print("workspace_name: ", ctx.label.workspace_root) |
| for dep in ctx.attr.deps: |
| if hasattr(dep, "files"): |
| sources.extend(dep.files) |
| else: |
| fail("Dependency", dep, "does not contain files.") |
| |
| args = [ |
| "-x", |
| "assembler-with-cpp", |
| "-nostdinc", |
| ] |
| source_count = 0 |
| for src in sources: |
| if source_count != 0: |
| args.append("-include") |
| args.append(src.path) |
| source_count += 1 |
| |
| root_path = _package_exec_path(ctx) |
| # TODO revisit this, cc_library doesn't allow labels in the include paths, |
| # it's possible we should use the deps and inherit includes depending on |
| # the providers. |
| for path in include_paths: |
| if path.startswith("@"): |
| label = Label(path) |
| flag = "-I" + label.workspace_root + "/" + label.package |
| else: |
| flag = "-I" + root_path + "/" + path |
| print(" flag=%s" % (flag)) |
| args.append(flag) |
| args.extend([ |
| "-I", |
| "-D__DTS__", |
| "-E", |
| "-o", |
| output_header.path, |
| ]) |
| print("Running: ", cxx_compiler_path, " ".join(args)) |
| |
| ctx.actions.run( |
| inputs = _get_inputs(ctx), |
| outputs = [output_header], |
| arguments = args, |
| executable = cxx_compiler_path, |
| tools = cc_toolchain.all_files, |
| mnemonic = "DtsPreCompile", |
| ) |
| return [ |
| DefaultInfo(files = depset([output_header])), |
| ] |
| |
| dts_library = rule( |
| implementation = _dts_library_impl, |
| attrs = { |
| "deps": attr.label_list(allow_files = False), |
| "includes": attr.string_list(), |
| "overlay": attr.label(mandatory = True, allow_single_file = True), |
| "references": attr.label_list(allow_files = True), |
| "_cc_toolchain": attr.label( |
| default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), |
| ), |
| }, |
| toolchains = use_cpp_toolchain(), |
| fragments = ["cpp"], |
| ) |
| |
| def _dts_cc_library_impl(ctx): |
| output_dts = ctx.actions.declare_file("zephyr.dts") |
| output_edt_pickle = ctx.actions.declare_file("edt.pickle") |
| output_header_name = "zephyr/devicetree_generated.h" |
| output_header = ctx.actions.declare_file(output_header_name) |
| dts_file = ctx.attr.dts_lib[DefaultInfo].files.to_list()[0] |
| bindings_files = [] |
| bindings_dirs = [] |
| |
| for bindings_file_provider in ctx.attr.bindings: |
| provider = bindings_file_provider[DefaultInfo].files.to_list() |
| bindings_files.extend(provider) |
| bindings_dirs += [f.dirname for f in provider] |
| |
| gen_defines_target = ctx.attr._gen_defines[DefaultInfo] |
| gen_edt_target = ctx.attr._gen_edt[DefaultInfo] |
| inputs = gen_defines_target.files.to_list() + gen_edt_target.files.to_list() + [dts_file] + bindings_files |
| |
| ctx.actions.run( |
| inputs = inputs, |
| outputs = [output_edt_pickle, output_dts], |
| executable = gen_edt_target.files_to_run.executable, |
| arguments = [ |
| "--edt-pickle-out", |
| output_edt_pickle.path, |
| "--dts", |
| dts_file.path, |
| "--bindings-dirs", |
| ] + depset(bindings_dirs).to_list() + [ |
| # "--bindings-dirs", |
| # "external/zephyr/dts/bindings", |
| "--dts-out", |
| output_dts.path, |
| "--dtc-flags", |
| "Wno-simple_bus_reg", |
| ], |
| mnemonic = "DtsGenEdtPickle", |
| progress_message = "Generating EDT pickle", |
| ) |
| |
| args = [ |
| "--header-out", |
| output_header.path, |
| "--edt-pickle", |
| output_edt_pickle.path, |
| ] |
| ctx.actions.run( |
| inputs = inputs + [output_edt_pickle], |
| outputs = [output_header], |
| executable = gen_defines_target.files_to_run.executable, |
| arguments = args, |
| mnemonic = "DtsGenDefines", |
| progress_message = "Running DTS definition generator", |
| ) |
| return [ |
| DefaultInfo( |
| files = depset([output_header]), |
| ), |
| CcInfo( |
| compilation_context = cc_common.create_compilation_context( |
| includes = depset([output_header.path[:-len(output_header_name)]]), |
| headers = depset([output_header]), |
| ), |
| ), |
| ] |
| |
| dts_cc_library = rule( |
| implementation = _dts_cc_library_impl, |
| attrs = { |
| "dts_lib": attr.label(allow_files = False), |
| "bindings": attr.label_list(allow_files = True), |
| "_gen_defines": attr.label( |
| default = "//scripts/dts:gen_defines", |
| executable = True, |
| cfg = "exec", |
| ), |
| "_gen_edt": attr.label( |
| default = "//scripts/dts:gen_edt", |
| executable = True, |
| cfg = "exec", |
| ), |
| }, |
| provides = [CcInfo], |
| ) |
| |
| def _syscall_library_files_impl(ctx): |
| print(",".join([str(f.path) for f in ctx.files.hdrs])) |
| syscalls_json = ctx.actions.declare_file("syscalls.json") |
| struct_tags_json = ctx.actions.declare_file("struct_tags.json") |
| syscall_file_list = ctx.actions.declare_file("syscalls_file_list.txt") |
| |
| # Generated sources |
| syscall_dispatcher_c = ctx.actions.declare_file("include/generated/zephyr/syscall_dispatch.c") |
| syscall_list_h = ctx.actions.declare_file("include/generated/zephyr/syscall_list.h") |
| syscall_export_llext_c = ctx.actions.declare_file("include/generated/zephyr/syscall_export_llext.c") |
| |
| # TODO This file is always generated but only compiled if CONFIG_LLEXT=y |
| syscall_weakdefs_llext_c = ctx.actions.declare_file("syscall_weakdefs_llext.c") |
| |
| ctx.actions.write( |
| output = syscall_file_list, |
| content = ";".join([f.path for f in ctx.files.hdrs]), |
| ) |
| |
| scan_dirs = depset([f.dirname for f in ctx.files.hdrs]) |
| scan_list = [] |
| include_list = [] |
| for d in scan_dirs.to_list(): |
| scan_list += ["--scan", d] |
| include_list += ["--include", d] |
| |
| ctx.actions.run( |
| inputs = ctx.files.hdrs + [syscall_file_list], |
| outputs = [syscalls_json, struct_tags_json], |
| executable = ctx.attr._parse_syscalls[DefaultInfo].files_to_run.executable, |
| arguments = scan_list + include_list + [ |
| "--json-file", |
| syscalls_json.path, |
| "--tag-struct-file", |
| struct_tags_json.path, |
| "--file-list", |
| syscall_file_list.path, |
| ], |
| mnemonic = "ParseSyscalls", |
| progress_message = "Parsing syscalls", |
| ) |
| |
| syscall_headers = [ |
| ctx.actions.declare_file("include/generated/zephyr/syscalls/" + f.basename) |
| for f in ctx.files.hdrs |
| ] |
| base_output_dir = syscall_headers[0].path |
| base_output_dir = base_output_dir[:-len(ctx.files.hdrs[0].basename)] |
| syscall_include_path = base_output_dir[:-len("zephyr/syscalls/")] |
| print("base_output_dir = " + base_output_dir) |
| print("syscall_include_path = " + syscall_include_path) |
| |
| ctx.actions.run( |
| inputs = [syscalls_json], |
| outputs = [ |
| syscall_dispatcher_c, |
| syscall_list_h, |
| syscall_export_llext_c, |
| syscall_weakdefs_llext_c, |
| ] + syscall_headers, |
| executable = ctx.attr._gen_syscalls[DefaultInfo].files_to_run.executable, |
| arguments = [ |
| "--json-file", |
| syscalls_json.path, |
| "--base-output", |
| base_output_dir, |
| "--syscall-dispatch", |
| syscall_dispatcher_c.path, |
| "--syscall-exports-llext", |
| syscall_export_llext_c.path, |
| "--syscall-weakdefs-llext", |
| syscall_weakdefs_llext_c.path, |
| "--syscall-list", |
| syscall_list_h.path, |
| ], |
| mnemonic = "GenSyscalls", |
| progress_message = "Generating syscalls", |
| ) |
| return [ |
| DefaultInfo( |
| files = depset([ |
| syscall_file_list, |
| syscalls_json, |
| struct_tags_json, |
| syscall_dispatcher_c, |
| syscall_list_h, |
| syscall_export_llext_c, |
| ] + syscall_headers), |
| ), |
| ] |
| |
| syscall_library_files = rule( |
| implementation = _syscall_library_files_impl, |
| attrs = { |
| "hdrs": attr.label_list(allow_files = True), |
| "_parse_syscalls": attr.label( |
| default = "//scripts/build:parse_syscalls", |
| executable = True, |
| cfg = "exec", |
| ), |
| "_gen_syscalls": attr.label( |
| default = "//scripts/build:gen_syscalls", |
| executable = True, |
| cfg = "exec", |
| ), |
| }, |
| output_to_genfiles = True, |
| ) |
| |
| def _syscall_library_impl(ctx): |
| print(",".join([str(f.path) for f in ctx.files.hdrs])) |
| syscalls_json = ctx.actions.declare_file("syscalls.json") |
| struct_tags_json = ctx.actions.declare_file("struct_tags.json") |
| |
| # include/generated/zephyr/ |
| syscall_dispatcher_c = ctx.actions.declare_file("syscall_dispatch.c") |
| syscall_list_h = ctx.actions.declare_file("include/generated/zephyr/syscall_list.h") |
| syscall_export_llext_c = ctx.actions.declare_file("syscall_export_llext.c") |
| syscall_file_list = ctx.actions.declare_file("syscalls_file_list.txt") |
| # output_file = ctx.actions.declare_file(ctx.label.name + ".a") |
| |
| ctx.actions.write( |
| output = syscall_file_list, |
| content = ";".join([f.path for f in ctx.files.hdrs]), |
| ) |
| |
| scan_dirs = depset([f.dirname for f in ctx.files.hdrs]) |
| scan_list = [] |
| include_list = [] |
| for d in scan_dirs.to_list(): |
| scan_list += ["--scan", d] |
| include_list += ["--include", d] |
| |
| print("Running:\n" + " ".join(scan_list + include_list + [ |
| "--json-file", |
| syscalls_json.path, |
| "--tag-struct-file", |
| struct_tags_json.path, |
| "--file-list", |
| syscall_file_list.path, |
| ])) |
| ctx.actions.run( |
| inputs = ctx.files.hdrs + [syscall_file_list], |
| outputs = [syscalls_json, struct_tags_json], |
| executable = ctx.attr._parse_syscalls[DefaultInfo].files_to_run.executable, |
| arguments = scan_list + include_list + [ |
| "--json-file", |
| syscalls_json.path, |
| "--tag-struct-file", |
| struct_tags_json.path, |
| "--file-list", |
| syscall_file_list.path, |
| ], |
| mnemonic = "ParseSyscalls", |
| progress_message = "Parsing syscalls", |
| ) |
| |
| syscall_headers = [ |
| ctx.actions.declare_file("include/generated/zephyr/syscalls/" + f.basename) |
| for f in ctx.files.hdrs |
| ] |
| base_output_dir = syscall_headers[0].path |
| base_output_dir = base_output_dir[:-len(ctx.files.hdrs[0].basename)] |
| syscall_include_path = base_output_dir[:-len("zephyr/syscalls/")] |
| print("base_output_dir = " + base_output_dir) |
| print("syscall_include_path = " + syscall_include_path) |
| |
| ctx.actions.run( |
| inputs = [syscalls_json], |
| outputs = [ |
| syscall_dispatcher_c, |
| syscall_list_h, |
| syscall_export_llext_c, |
| ] + syscall_headers, |
| executable = ctx.attr._gen_syscalls[DefaultInfo].files_to_run.executable, |
| arguments = [ |
| "--json-file", |
| syscalls_json.path, |
| "--base-output", |
| base_output_dir, |
| "--syscall-dispatch", |
| syscall_dispatcher_c.path, |
| "--syscall-export-llext", |
| syscall_export_llext_c.path, |
| "--syscall-list", |
| syscall_list_h.path, |
| ], |
| mnemonic = "GenSyscalls", |
| progress_message = "Generating syscalls", |
| ) |
| return compile_cc( |
| ctx = ctx, |
| srcs = [syscall_dispatcher_c], |
| hdrs = [syscall_list_h, syscall_export_llext_c] + syscall_headers, |
| deps = ctx.attr.deps, |
| includes = [syscall_include_path], |
| ) + [ |
| DefaultInfo( |
| files = depset([syscall_list_h]), |
| ), |
| ] |
| |
| syscall_library = rule( |
| implementation = _syscall_library_impl, |
| attrs = { |
| "hdrs": attr.label_list(allow_files = True), |
| "deps": attr.label_list(allow_files = False), |
| "_parse_syscalls": attr.label( |
| default = "//scripts/build:parse_syscalls", |
| executable = True, |
| cfg = "exec", |
| ), |
| "_gen_syscalls": attr.label( |
| default = "//scripts/build:gen_syscalls", |
| executable = True, |
| cfg = "exec", |
| ), |
| "_cc_toolchain": attr.label( |
| default = Label("@rules_cc//cc:current_cc_toolchain"), |
| ), |
| }, |
| toolchains = use_cpp_toolchain(), |
| fragments = ["cpp"], |
| output_to_genfiles = True, |
| provides = [CcInfo], |
| ) |
| |
| def _zephyr_final_binary_impl(ctx): |
| cc_toolchain = find_cpp_toolchain(ctx) |
| feature_configuration = cc_common.configure_features( |
| ctx = ctx, |
| cc_toolchain = cc_toolchain, |
| requested_features = ctx.features, |
| unsupported_features = ctx.disabled_features, |
| ) |
| cxx_linker_path = cc_common.get_tool_for_action( |
| feature_configuration = feature_configuration, |
| action_name = CPP_LINK_EXECUTABLE_ACTION_NAME, |
| ) |
| |
| output_elf = ctx.actions.declare_file(ctx.label.name) |
| |
| ctx.actions.run( |
| inputs = depset( |
| direct = [ctx.executable.pre0_elf, ctx.file.lds], |
| transitive = [cc_toolchain.all_files], |
| ), |
| outputs = [output_elf], |
| arguments = [ |
| "-T", |
| ctx.file.lds.path, |
| ctx.executable.pre0_elf.path, |
| "-o", |
| output_elf.path, |
| ], |
| executable = cxx_linker_path, |
| tools = cc_toolchain.all_files, |
| mnemonic = "Linking", |
| ) |
| return [ |
| DefaultInfo( |
| files = depset([output_elf, ctx.executable.pre0_elf]), |
| executable = output_elf, |
| ), |
| ] |
| |
| zephyr_final_binary = rule( |
| implementation = _zephyr_final_binary_impl, |
| attrs = { |
| "lds": attr.label( |
| mandatory = True, |
| allow_single_file = True, |
| ), |
| "pre0_elf": attr.label( |
| mandatory = True, |
| executable = True, |
| cfg = "target", |
| ), |
| "_cc_toolchain": attr.label( |
| default = Label("@rules_cc//cc:current_cc_toolchain"), |
| ), |
| }, |
| executable = True, |
| toolchains = use_cpp_toolchain(), |
| fragments = ["cpp"], |
| ) |
| |
| def _zephyr_offset_header_impl(ctx): |
| cc_info = ctx.attr.lib[DefaultInfo] |
| library_archive = cc_info.files.to_list()[0] |
| linker_output = ctx.actions.declare_file("offsets.o") |
| output_file = ctx.actions.declare_file(ctx.attr.output) |
| |
| run_action_on_executable( |
| ctx = ctx, |
| action_name = ACTION_NAMES.cpp_link_static_library, |
| action_args = "x {input} --output={output_dir} offsets.o".format( |
| input = str(library_archive.path), |
| output_dir = str(linker_output.dirname), |
| ), |
| inputs = [library_archive], |
| output = linker_output, |
| additional_outputs = [], |
| output_executable = False, |
| ) |
| |
| ctx.actions.run( |
| outputs = [output_file], |
| inputs = [linker_output], |
| executable = ctx.executable.tool, |
| arguments = [ |
| "-i", |
| linker_output.path, |
| "-o", |
| output_file.path, |
| ], |
| ) |
| return [DefaultInfo(files = depset([output_file]))] |
| |
| zephyr_offset_header = rule( |
| implementation = _zephyr_offset_header_impl, |
| attrs = { |
| "lib": attr.label(mandatory = True, allow_files = False, providers = [CcInfo]), |
| "tool": attr.label(executable = True, allow_files = False, mandatory = True, cfg = "exec"), |
| "output": attr.string(mandatory = True), |
| }, |
| toolchains = use_cpp_toolchain(), |
| fragments = ["cpp"], |
| ) |