1load("@bazel_skylib//rules:write_file.bzl", "write_file") 2load("@rules_cc//cc:defs.bzl", "cc_library") 3 4def _pico_generate_pio_header_impl(ctx): 5 generated_headers = [] 6 for f in ctx.files.srcs: 7 out = ctx.actions.declare_file( 8 "{}_pio_generated/{}.h".format(ctx.label.name, f.basename), 9 ) 10 generated_headers.append(out) 11 ctx.actions.run( 12 executable = ctx.executable._pioasm_tool, 13 arguments = [ 14 "-o", 15 "c-sdk", 16 f.path, 17 out.path, 18 ], 19 inputs = [f], 20 outputs = [out], 21 ) 22 23 cc_ctx = cc_common.create_compilation_context( 24 headers = depset(direct = generated_headers), 25 includes = depset(direct = [generated_headers[0].dirname]), 26 ) 27 return [ 28 DefaultInfo(files = depset(direct = generated_headers)), 29 CcInfo(compilation_context = cc_ctx), 30 ] 31 32pico_generate_pio_header = rule( 33 implementation = _pico_generate_pio_header_impl, 34 doc = """Generates a .h header file for each listed pio source. 35 36Each source file listed in `srcs` will be available as `[pio file name].h` on 37the include path if you depend on this rule from a `cc_library`. 38 39pico_generate_pio_header( 40 name = "my_fun_pio", 41 srcs = ["my_fun_pio.pio"], 42) 43 44# This library can #include "my_fun_pio.pio.h". 45cc_library( 46 name = "libfoo", 47 deps = [":my_fun_pio"], 48 srcs = ["libfoo.c"], 49) 50""", 51 attrs = { 52 "srcs": attr.label_list(mandatory = True, allow_files = True), 53 "_pioasm_tool": attr.label( 54 default = "@pico-sdk//tools/pioasm:pioasm", 55 cfg = "exec", 56 executable = True, 57 ), 58 }, 59 provides = [CcInfo], 60) 61 62# Because the syntax for target_compatible_with when used with config_setting 63# rules is both confusing and verbose, provide some helpers that make it much 64# easier and clearer to express compatibility. 65# 66# Context: https://github.com/bazelbuild/bazel/issues/12614 67 68def compatible_with_config(config_label): 69 """Expresses compatibility with a config_setting.""" 70 return select({ 71 config_label: [], 72 "//conditions:default": ["@platforms//:incompatible"], 73 }) 74 75def incompatible_with_config(config_label): 76 """Expresses incompatibility with a config_setting.""" 77 return select({ 78 config_label: ["@platforms//:incompatible"], 79 "//conditions:default": [], 80 }) 81 82def compatible_with_rp2(): 83 """Expresses a rule is compatible with the rp2 family.""" 84 return incompatible_with_config("//bazel/constraint:host") 85 86def compatible_with_pico_w(): 87 """Expresses a rule is compatible a Pico W.""" 88 return select({ 89 "@pico-sdk//bazel/constraint:cyw43_wireless": [], 90 "@pico-sdk//bazel/constraint:is_pico_w": [], 91 "@pico-sdk//bazel/constraint:is_pico2_w": [], 92 "//conditions:default": ["@platforms//:incompatible"], 93 }) 94 95def pico_board_config(name, platform_includes, **kwargs): 96 """A helper macro for declaring a Pico board to use with PICO_CONFIG_HEADER. 97 98 This generates pico_config_platform_headers.h using the list of 99 includes provided in `platform_includes`, and the final artifact is 100 a cc_library that you can configure //bazel/config:PICO_CONFIG_HEADER to 101 point to. 102 """ 103 _hdr_dir = "{}_generated_includes".format(name) 104 _hdr_path = "{}/pico_config_platform_headers.h".format(_hdr_dir) 105 write_file( 106 name = "{}_platform_headers_file".format(name), 107 out = _hdr_path, 108 content = ['#include "{}"'.format(inc) for inc in platform_includes], 109 ) 110 kwargs.setdefault("hdrs", []) 111 kwargs["hdrs"].append(_hdr_path) 112 kwargs.setdefault("includes", []) 113 kwargs["includes"].append(_hdr_dir) 114 cc_library( 115 name = name, 116 **kwargs 117 ) 118