Support linking multiple stdio implementations

Changes the Bazel build so stdio implementations are no longer mutually
exclusive.
diff --git a/bazel/README.md b/bazel/README.md
index db5078c..db515b0 100644
--- a/bazel/README.md
+++ b/bazel/README.md
@@ -92,20 +92,6 @@
    --@pico-sdk//bazel/config:pico_config_platform_headers=//path/to:pico_board_config
    ```
 
-### Selecting a stdio mode
-To select a different stdio mode, add it to your `platform` definition. For
-example:
-```python
-platform(
-    name = "rp2040",
-    constraint_values = [
-        "@pico-sdk//bazel/constraint:rp2040",
-        "@pico-sdk//bazel/constraint:stdio_usb", # Configures stdio_mode.
-        "@platforms//cpu:armv6-m",
-    ],
-)
-```
-
 ## Building the Pico SDK itself
 
 ### First time setup
diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel
index aa60746..ec04091 100644
--- a/bazel/config/BUILD.bazel
+++ b/bazel/config/BUILD.bazel
@@ -50,6 +50,24 @@
     build_setting_default = False,
 )
 
+# PICO_BAZEL_CONFIG: PICO_STDIO_UART, OPTION: Globally enable stdio UART, default=1, group=pico_stdlib
+bool_flag(
+    name = "PICO_STDIO_UART",
+    build_setting_default = True,
+)
+
+# PICO_BAZEL_CONFIG: PICO_STDIO_USB, OPTION: Globally enable stdio USB, default=0, group=pico_stdlib
+bool_flag(
+    name = "PICO_STDIO_USB",
+    build_setting_default = False,
+)
+
+# PICO_BAZEL_CONFIG: PICO_STDIO_SEMIHOSTING, OPTION: Globally enable stdio semihosting, default=0, group=pico_stdlib
+bool_flag(
+    name = "PICO_STDIO_SEMIHOSTING",
+    build_setting_default = False,
+)
+
 # This should always point to a cc_library that provides
 # a "pico_config_extra_headers.h".
 label_flag(
diff --git a/bazel/constraint/BUILD.bazel b/bazel/constraint/BUILD.bazel
index 837f7c8..9728506 100644
--- a/bazel/constraint/BUILD.bazel
+++ b/bazel/constraint/BUILD.bazel
@@ -55,29 +55,17 @@
     flag_values = {"//bazel/config:PICO_CXX_ENABLE_RTTI": "True"},
 )
 
-# This constraint setting guides Bazel's build file evaluation differences
-# across different stdio configurations (e.g. stdio_usb needs TinyUSB).
-constraint_setting(
-    name = "stdio_mode",
-    default_constraint_value = "stdio_uart",
+config_setting(
+    name = "pico_stdio_uart_enabled",
+    flag_values = {"//bazel/config:PICO_STDIO_UART": "True"},
 )
 
-# When this constraint value is active, stdio is built against a hardware UART.
-constraint_value(
-    name = "stdio_uart",
-    constraint_setting = ":stdio_mode",
+config_setting(
+    name = "pico_stdio_usb_enabled",
+    flag_values = {"//bazel/config:PICO_STDIO_USB": "True"},
 )
 
-# When this constraint value is active, stdio is built against TinyUSB-based
-# USB serial.
-constraint_value(
-    name = "stdio_usb",
-    constraint_setting = ":stdio_mode",
-)
-
-# When this constraint value is active, stdio is built against an ARM
-# semihosting library.
-constraint_value(
-    name = "stdio_semihosting",
-    constraint_setting = ":stdio_mode",
+config_setting(
+    name = "pico_stdio_semihosting_enabled",
+    flag_values = {"//bazel/config:PICO_STDIO_SEMIHOSTING": "True"},
 )
diff --git a/src/boards/BUILD.bazel b/src/boards/BUILD.bazel
index 0a59430..07abb05 100644
--- a/src/boards/BUILD.bazel
+++ b/src/boards/BUILD.bazel
@@ -66,15 +66,6 @@
     for board in BOARD_CHOICES
 ]
 
-cc_library(
-    name = "stdio_defines",
-    defines = select({
-        "//bazel/constraint:stdio_semihosting": ["LIB_PICO_STDIO_SEMIHOSTING=1"],
-        "//bazel/constraint:stdio_uart": ["LIB_PICO_STDIO_UART=1"],
-        "//bazel/constraint:stdio_usb": ["LIB_PICO_STDIO_USB=1"],
-    }),
-)
-
 # Creates a config_setting for each known board option with the name:
 #     PICO_BOARD_[choice]
 declare_flag_choices(
@@ -96,7 +87,6 @@
             "PICO_BUILD=1",
         ],
     }),
-    deps = [":stdio_defines"]
 )
 
 cc_library(
diff --git a/src/rp2_common/pico_stdio/BUILD.bazel b/src/rp2_common/pico_stdio/BUILD.bazel
index c6ba06a..b7b3fbf 100644
--- a/src/rp2_common/pico_stdio/BUILD.bazel
+++ b/src/rp2_common/pico_stdio/BUILD.bazel
@@ -1,5 +1,34 @@
+load("//bazel/util:sdk_define.bzl", "pico_sdk_define")
+
 package(default_visibility = ["//visibility:public"])
 
+pico_sdk_define(
+    name = "LIB_PICO_STDIO_UART",
+    define_name = "LIB_PICO_STDIO_UART",
+    from_flag = "//bazel/config:PICO_STDIO_UART",
+)
+
+pico_sdk_define(
+    name = "LIB_PICO_STDIO_USB",
+    define_name = "LIB_PICO_STDIO_USB",
+    from_flag = "//bazel/config:PICO_STDIO_USB",
+)
+
+pico_sdk_define(
+    name = "LIB_PICO_STDIO_SEMIHOSTING",
+    define_name = "LIB_PICO_STDIO_SEMIHOSTING",
+    from_flag = "//bazel/config:PICO_STDIO_SEMIHOSTING",
+)
+
+cc_library(
+    name = "stdio_defines",
+    deps = [
+        ":LIB_PICO_STDIO_UART",
+        ":LIB_PICO_STDIO_USB",
+        ":LIB_PICO_STDIO_SEMIHOSTING",
+    ],
+)
+
 # This exists to break dependency cycles between
 # this library and the stdio implementations.
 # Application code should always use :pico_stdio instead.
@@ -14,6 +43,7 @@
         "//bazel/constraint:rp2": [],
         "//conditions:default": ["@platforms//:incompatible"],
     }),
+    deps = [":stdio_defines"],
     visibility = [
         "//src/rp2_common/pico_stdio_semihosting:__pkg__",
         "//src/rp2_common/pico_stdio_uart:__pkg__",
@@ -42,14 +72,20 @@
         "//conditions:default": ["@platforms//:incompatible"],
     }),
     deps = [
+        ":stdio_defines",
         "//src/common/pico_base",
         "//src/common/pico_sync",
         "//src/common/pico_time",
         "//src/rp2_common/pico_printf",
     ] + select({
-        "//bazel/constraint:stdio_semihosting": ["//src/rp2_common/pico_stdio_semihosting"],
-        "//bazel/constraint:stdio_uart": ["//src/rp2_common/pico_stdio_uart"],
-        "//bazel/constraint:stdio_usb": ["//src/rp2_common/pico_stdio_usb"],
+        "//bazel/constraint:pico_stdio_semihosting_enabled": ["//src/rp2_common/pico_stdio_semihosting"],
+        "//conditions:default": [],
+    }) + select({
+        "//bazel/constraint:pico_stdio_uart_enabled": ["//src/rp2_common/pico_stdio_uart"],
+        "//conditions:default": [],
+    }) + select({
+        "//bazel/constraint:pico_stdio_usb_enabled": ["//src/rp2_common/pico_stdio_usb"],
+        "//conditions:default": [],
     }),
     alwayslink = True,  # Ensures the wrapped symbols are linked in.
 )
diff --git a/src/rp2_common/pico_stdio_usb/BUILD.bazel b/src/rp2_common/pico_stdio_usb/BUILD.bazel
index bb414f5..efe69b0 100644
--- a/src/rp2_common/pico_stdio_usb/BUILD.bazel
+++ b/src/rp2_common/pico_stdio_usb/BUILD.bazel
@@ -39,9 +39,10 @@
         "stdio_usb.c",
         "stdio_usb_descriptors.c",
     ],
-    target_compatible_with = [
-        "//bazel/constraint:stdio_usb",
-    ] + select({
+    target_compatible_with = select({
+        "//bazel/constraint:pico_stdio_usb_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }) + select({
         "//bazel/constraint:rp2": [],
         "//conditions:default": ["@platforms//:incompatible"],
     }),
diff --git a/src/rp2_common/pico_stdlib/BUILD.bazel b/src/rp2_common/pico_stdlib/BUILD.bazel
index ef7603d..a322ce0 100644
--- a/src/rp2_common/pico_stdlib/BUILD.bazel
+++ b/src/rp2_common/pico_stdlib/BUILD.bazel
@@ -13,8 +13,13 @@
         "//src/rp2_common/hardware_clocks",
         "//src/rp2_common/hardware_pll",
     ] + select({
-        "//bazel/constraint:stdio_semihosting": ["//src/rp2_common/pico_stdio_semihosting"],
-        "//bazel/constraint:stdio_uart": ["//src/rp2_common/pico_stdio_uart"],
-        "//bazel/constraint:stdio_usb": ["//src/rp2_common/pico_stdio_usb"],
+        "//bazel/constraint:pico_stdio_semihosting_enabled": ["//src/rp2_common/pico_stdio_semihosting"],
+        "//conditions:default": [],
+    }) + select({
+        "//bazel/constraint:pico_stdio_uart_enabled": ["//src/rp2_common/pico_stdio_uart"],
+        "//conditions:default": [],
+    }) + select({
+        "//bazel/constraint:pico_stdio_usb_enabled": ["//src/rp2_common/pico_stdio_usb"],
+        "//conditions:default": [],
     }),
 )