Skip to content

Commit

Permalink
Initial Pico/2 W Bazel support (#2049)
Browse files Browse the repository at this point in the history
* Initial Pico 2 W Bazel support

Improves compatibility with Pico W and Pico 2 W by fixing issues that
prevented correct linking of wireless libraries.

* Improve correctness and configurability

* Require newer rules_python

* Require rules_python@0.36.0

* Fix missing compatibility expressions

* Minor tweaks

* Minor cleanup

* Update suggested version in Bazel README

* More README tweaks

* Improve Bazel btstack build correctness
  • Loading branch information
armandomontanez authored Nov 21, 2024
1 parent 08ea1d8 commit 338f99f
Show file tree
Hide file tree
Showing 21 changed files with 535 additions and 87 deletions.
18 changes: 17 additions & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module(

bazel_dep(name = "platforms", version = "0.0.9")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "rules_python", version = "0.22.1")
bazel_dep(name = "rules_python", version = "0.36.0")
bazel_dep(name = "picotool", version = "2.0.0")
bazel_dep(name = "rules_cc", version = "0.0.10")

Expand Down Expand Up @@ -132,3 +132,19 @@ register_toolchains(
# Require users to opt-in to the Pico SDK's toolchains.
dev_dependency = True,
)

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
configure_coverage_tool = True,
python_version = "3.9",
)

use_repo(python, "pythons_hub")
register_toolchains(
"@pythons_hub//:all",
dev_dependency = True,
)
register_toolchains(
"@rules_python//python/runtime_env_toolchains:all",
dev_dependency = True,
)
7 changes: 4 additions & 3 deletions bazel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
First, in your `MODULE.bazel` file, add a dependency on the Pico SDK and
`rules_cc`:
```python
bazel_dep(name = "pico-sdk", version = "2.0.1")
bazel_dep(name = "pico-sdk", version = "2.1.0")
```

### Register toolchains
Expand Down Expand Up @@ -92,11 +92,12 @@ you encounter along the way.

Currently, the following features are not supported:

* Pico W wireless libraries work, but may not have complete feature parity with
the CMake build.
* Bazel does not yet provide RISC-V support for Pico 2/RP2350.
* The pioasm parser cannot be built from source via Bazel.
* Windows MSVC wildcard build (`bazel build //...`) does not work when targeting
host.
* Bazel does not yet provide RISC-V support for Pico 2/RP2350.
* Pico W wireless libraries have link issues.

## Contributing
When making changes to the Bazel build, please run the Bazel validation script
Expand Down
29 changes: 29 additions & 0 deletions bazel/config/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ string_flag(
],
)

# PICO_BAZEL_CONFIG: PICO_ASYNC_CONTEXT_IMPL, The default implementation for pico_async_context to link, type=string, default=threadsafe_background, group=build
string_flag(
name = "PICO_ASYNC_CONTEXT_IMPL",
build_setting_default = "threadsafe_background",
values = [
"poll",
"threadsafe_background",
"freertos",
],
)

# PICO_BAZEL_CONFIG: PICO_BINARY_INFO_ENABLED, Whether to include binary info in final firmware, type=bool, default=1, group=pico_stdlib
bool_flag(
name = "PICO_BINARY_INFO_ENABLED",
Expand Down Expand Up @@ -248,6 +259,24 @@ label_flag(
build_setting_default = "//bazel:empty_cc_lib",
)

# PICO_BAZEL_CONFIG: PICO_BT_ENABLE_BLE, [Bazel only] Whether or not to link in BLE portions of the btstack as part of //src/rp2_common/pico_btstack. Also defines ENABLE_BLE=1, type=bool, default=False, group=wireless
bool_flag(
name = "PICO_BT_ENABLE_BLE",
build_setting_default = False,
)

# PICO_BAZEL_CONFIG: PICO_BT_ENABLE_CLASSIC, [Bazel only] Whether or not to link in classic BT portions of the btstack as part of //src/rp2_common/pico_btstack. Also defines ENABLE_CLASSIC=1, type=bool, default=False, group=wireless
bool_flag(
name = "PICO_BT_ENABLE_CLASSIC",
build_setting_default = False,
)

# PICO_BAZEL_CONFIG: PICO_BT_ENABLE_MESH, [Bazel only] Whether or not to link in mesh BT portions of the btstack as part of //src/rp2_common/pico_btstack. Also defines ENABLE_MESH=1, type=bool, default=False, group=wireless
bool_flag(
name = "PICO_BT_ENABLE_MESH",
build_setting_default = False,
)

# PICO_BAZEL_CONFIG: PICO_LWIP_CONFIG, [Bazel only] The cc_library that provides lwipopts.h, default=//bazel:empty_cc_lib, group=wireless
label_flag(
name = "PICO_LWIP_CONFIG",
Expand Down
50 changes: 45 additions & 5 deletions bazel/constraint/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("//bazel/util:label_flag_matches.bzl", "label_flag_matches")

package(default_visibility = ["//visibility:public"])

# This constraint represents the dimension that guides the Pico SDK build. This
Expand Down Expand Up @@ -48,6 +50,11 @@ config_setting(
flag_values = {"//bazel/config:PICO_BOARD": "pico_w"},
)

config_setting(
name = "is_pico2_w",
flag_values = {"//bazel/config:PICO_BOARD": "pico2_w"},
)

config_setting(
name = "pico_toolchain_clang_enabled",
flag_values = {"//bazel/config:PICO_TOOLCHAIN": "clang"},
Expand Down Expand Up @@ -173,6 +180,21 @@ config_setting(
flag_values = {"//bazel/config:PICO_DEFAULT_PRINTF_IMPL": "compiler"},
)

config_setting(
name = "pico_async_context_poll_enabled",
flag_values = {"//bazel/config:PICO_ASYNC_CONTEXT_IMPL": "poll"},
)

config_setting(
name = "pico_async_context_threadsafe_background_enabled",
flag_values = {"//bazel/config:PICO_ASYNC_CONTEXT_IMPL": "threadsafe_background"},
)

config_setting(
name = "pico_async_context_freertos_enabled",
flag_values = {"//bazel/config:PICO_ASYNC_CONTEXT_IMPL": "freertos"},
)

config_setting(
name = "pico_use_default_max_page_size_enabled",
flag_values = {"//bazel/config:PICO_USE_DEFAULT_MAX_PAGE_SIZE": "True"},
Expand All @@ -199,16 +221,34 @@ config_setting(
)

config_setting(
name = "pico_btstack_config_unset",
flag_values = {"//bazel/config:PICO_BTSTACK_CONFIG": "//bazel:empty_cc_lib"},
name = "pico_bt_enable_ble_enabled",
flag_values = {"//bazel/config:PICO_BT_ENABLE_BLE": "True"},
)

config_setting(
name = "pico_lwip_config_unset",
flag_values = {"//bazel/config:PICO_LWIP_CONFIG": "//bazel:empty_cc_lib"},
name = "pico_bt_enable_classic_enabled",
flag_values = {"//bazel/config:PICO_BT_ENABLE_CLASSIC": "True"},
)

config_setting(
name = "pico_bt_enable_mesh_enabled",
flag_values = {"//bazel/config:PICO_BT_ENABLE_MESH": "True"},
)

label_flag_matches(
name = "pico_lwip_config_unset",
flag = "//bazel/config:PICO_LWIP_CONFIG",
value = "//bazel:empty_cc_lib",
)

label_flag_matches(
name = "pico_btstack_config_unset",
flag = "//bazel/config:PICO_BTSTACK_CONFIG",
value = "//bazel:empty_cc_lib",
)

label_flag_matches(
name = "pico_freertos_unset",
flag_values = {"//bazel/config:PICO_FREERTOS_LIB": "//bazel:empty_cc_lib"},
flag = "//bazel/config:PICO_FREERTOS_LIB",
value = "//bazel:empty_cc_lib",
)
1 change: 1 addition & 0 deletions bazel/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def compatible_with_pico_w():
return select({
"@pico-sdk//bazel/constraint:cyw43_wireless": [],
"@pico-sdk//bazel/constraint:is_pico_w": [],
"@pico-sdk//bazel/constraint:is_pico2_w": [],
"//conditions:default": ["@platforms//:incompatible"],
})

Expand Down
59 changes: 59 additions & 0 deletions bazel/pico_btstack_make_gatt_header.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain")

def _pico_btstack_make_gatt_header_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,
)

out = ctx.actions.declare_file(
"{}_gatt_generated/{}.h".format(ctx.label.name, ctx.file.src.basename.removesuffix(".gatt")),
)

ctx.actions.run(
executable = ctx.executable._make_gat_header_tool,
arguments = [
ctx.file.src.path,
out.path,
"-I",
ctx.file._btstack_hdr.dirname,
] + [

],
inputs = [
ctx.file.src,
ctx.file._btstack_hdr,
],
outputs = [out],
)

cc_ctx = cc_common.create_compilation_context(
headers = depset(direct = [out]),
includes = depset(direct = [out.dirname]),
)

return [
DefaultInfo(files = depset(direct = [out])),
CcInfo(compilation_context = cc_ctx)
]

pico_btstack_make_gatt_header = rule(
implementation = _pico_btstack_make_gatt_header_impl,
attrs = {
"src": attr.label(mandatory = True, allow_single_file = True),
"_btstack_hdr": attr.label(
default = "@btstack//:src/bluetooth_gatt.h",
allow_single_file = True,
),
"_make_gat_header_tool": attr.label(
default = "@btstack//:compile_gatt",
cfg = "exec",
executable = True,
),
},
fragments = ["cpp"],
toolchains = use_cc_toolchain(),
)
37 changes: 37 additions & 0 deletions bazel/util/label_flag_matches.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""A wrapper that enables a `config_setting` matcher for label_flag flags."""

load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")

def _match_label_flag_impl(ctx):
matches = str(ctx.attr.expected_value.label) == str(ctx.attr.flag.label)
return [
config_common.FeatureFlagInfo(value = str(matches)),
BuildSettingInfo(value = matches),
]

_match_label_flag = rule(
implementation = _match_label_flag_impl,
attrs = {
"expected_value": attr.label(
mandatory = True,
doc = "The expected flag value",
),
"flag": attr.label(
mandatory = True,
doc = "The flag to extract a value from",
),
},
)

def label_flag_matches(*, name, flag, value):
_match_label_flag(
name = name + "._impl",
expected_value = native.package_relative_label(value),
flag = flag,
)

native.config_setting(
name = name,
flag_values = {":{}".format(name + "._impl"): "True"},
)
12 changes: 11 additions & 1 deletion bazel/util/transition.bzl
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
def _normalize_flag_value(val):
"""Converts flag values to transition-safe primitives."""
if type(val) == "label":
return str(val)
return val

def declare_transtion(attrs, flag_overrides = None, append_to_flags = None, executable = True):
"""A helper that drastically simplifies declaration of a transition.
Expand Down Expand Up @@ -31,7 +37,7 @@ def declare_transtion(attrs, flag_overrides = None, append_to_flags = None, exec
final_overrides = {}
if flag_overrides != None:
final_overrides = {
key: str(getattr(attrs, value))
key: _normalize_flag_value(getattr(attrs, value))
for key, value in flag_overrides.items()
}
if append_to_flags != None:
Expand Down Expand Up @@ -108,6 +114,8 @@ kitchen_sink_test_binary = declare_transtion(
attrs = {
"bt_stack_config": attr.label(mandatory = True),
"lwip_config": attr.label(mandatory = True),
"enable_ble": attr.bool(default = False),
"enable_bt_classic": attr.bool(default = False),
# This could be shared, but we don't in order to make it clearer that
# a transition is in use.
"_allowlist_function_transition": attr.label(
Expand All @@ -117,6 +125,8 @@ kitchen_sink_test_binary = declare_transtion(
flag_overrides = {
"@pico-sdk//bazel/config:PICO_BTSTACK_CONFIG": "bt_stack_config",
"@pico-sdk//bazel/config:PICO_LWIP_CONFIG": "lwip_config",
"@pico-sdk//bazel/config:PICO_BT_ENABLE_BLE": "enable_ble",
"@pico-sdk//bazel/config:PICO_BT_ENABLE_CLASSIC": "enable_bt_classic",
},
)

Expand Down
18 changes: 14 additions & 4 deletions src/rp2_common/pico_async_context/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@ load("//bazel:defs.bzl", "compatible_with_rp2", "incompatible_with_config")

package(default_visibility = ["//visibility:public"])

cc_library(
alias(
name = "pico_async_context",
actual = select({
"//bazel/constraint:pico_async_context_poll_enabled": ":pico_async_context_poll",
"//bazel/constraint:pico_async_context_threadsafe_background_enabled": ":pico_async_context_threadsafe_background",
"//bazel/constraint:pico_async_context_freertos_enabled": ":pico_async_context_freertos",
"//conditions:default": "//bazel:incompatible_cc_lib",
}),
)

cc_library(
name = "pico_async_context_base",
srcs = ["async_context_base.c"],
hdrs = [
"include/pico/async_context.h",
Expand All @@ -26,7 +36,7 @@ cc_library(
"//bazel/constraint:pico_freertos_unset",
),
deps = [
":pico_async_context",
":pico_async_context_base",
"//bazel/config:PICO_FREERTOS_LIB",
"//src/common/pico_sync",
"//src/common/pico_time",
Expand All @@ -42,7 +52,7 @@ cc_library(
includes = ["include"],
target_compatible_with = compatible_with_rp2(),
deps = [
":pico_async_context",
":pico_async_context_base",
"//src/common/pico_sync",
"//src/common/pico_time",
"//src/rp2_common:pico_platform",
Expand All @@ -56,7 +66,7 @@ cc_library(
includes = ["include"],
target_compatible_with = compatible_with_rp2(),
deps = [
":pico_async_context",
":pico_async_context_base",
"//src/common/pico_sync",
"//src/common/pico_time",
"//src/rp2_common:pico_platform",
Expand Down
Loading

0 comments on commit 338f99f

Please sign in to comment.