load("@bazel_skylib//rules:write_file.bzl", "write_file") load("@rules_cc//cc:defs.bzl", "cc_library") def _pico_generate_pio_header_impl(ctx): generated_headers = [] for f in ctx.files.srcs: out = ctx.actions.declare_file( "{}_pio_generated/{}.h".format(ctx.label.name, f.basename), ) generated_headers.append(out) ctx.actions.run( executable = ctx.executable._pioasm_tool, arguments = [ "-o", "c-sdk", f.path, out.path, ], inputs = [f], outputs = [out], ) cc_ctx = cc_common.create_compilation_context( headers = depset(direct = generated_headers), includes = depset(direct = [generated_headers[0].dirname]), ) return [ DefaultInfo(files = depset(direct = generated_headers)), CcInfo(compilation_context = cc_ctx), ] pico_generate_pio_header = rule( implementation = _pico_generate_pio_header_impl, doc = """Generates a .h header file for each listed pio source. Each source file listed in `srcs` will be available as `[pio file name].h` on the include path if you depend on this rule from a `cc_library`. pico_generate_pio_header( name = "my_fun_pio", srcs = ["my_fun_pio.pio"], ) # This library can #include "my_fun_pio.pio.h". cc_library( name = "libfoo", deps = [":my_fun_pio"], srcs = ["libfoo.c"], ) """, attrs = { "srcs": attr.label_list(mandatory = True, allow_files = True), "_pioasm_tool": attr.label( default = "@pico-sdk//tools/pioasm:pioasm", cfg = "exec", executable = True, ), }, provides = [CcInfo], ) # Because the syntax for target_compatible_with when used with config_setting # rules is both confusing and verbose, provide some helpers that make it much # easier and clearer to express compatibility. # # Context: https://github.com/bazelbuild/bazel/issues/12614 def compatible_with_config(config_label): """Expresses compatibility with a config_setting.""" return select({ config_label: [], "//conditions:default": ["@platforms//:incompatible"], }) def incompatible_with_config(config_label): """Expresses incompatibility with a config_setting.""" return select({ config_label: ["@platforms//:incompatible"], "//conditions:default": [], }) def compatible_with_rp2(): """Expresses a rule is compatible with the rp2 family.""" return incompatible_with_config("//bazel/constraint:host") def compatible_with_pico_w(): """Expresses a rule is compatible a Pico W.""" return select({ "@pico-sdk//bazel/constraint:cyw43_wireless": [], "@pico-sdk//bazel/constraint:is_pico_w": [], "//conditions:default": ["@platforms//:incompatible"], }) def pico_board_config(name, platform_includes, **kwargs): """A helper macro for declaring a Pico board to use with PICO_CONFIG_HEADER. This generates pico_config_platform_headers.h using the list of includes provided in `platform_includes`, and the final artifact is a cc_library that you can configure //bazel/config:PICO_CONFIG_HEADER to point to. """ _hdr_dir = "{}_generated_includes".format(name) _hdr_path = "{}/pico_config_platform_headers.h".format(_hdr_dir) write_file( name = "{}_platform_headers_file".format(name), out = _hdr_path, content = ['#include "{}"'.format(inc) for inc in platform_includes], ) kwargs.setdefault("hdrs", []) kwargs["hdrs"].append(_hdr_path) kwargs.setdefault("includes", []) kwargs["includes"].append(_hdr_dir) cc_library( name = name, **kwargs )