pw_build: Support pw_facade without public headers

- Allow use of pw_facade without public headers, but do not emit a
  .facade subtarget when it is empty. pw_facade still provides value
  since it handles unset backend variables and gives helpful errors.
- Propagate visibility to the ".facade" target. Fix existing visibility
  violations.

Change-Id: I2e64feb241979fbf3aa5a37d4c6bbfe07aaa18f1
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/239755
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
diff --git a/pw_build/facade.gni b/pw_build/facade.gni
index a823360..e3c1bc0 100644
--- a/pw_build/facade.gni
+++ b/pw_build/facade.gni
@@ -79,18 +79,21 @@
 template("pw_facade") {
   assert(defined(invoker.backend),
          "pw_facade requires a reference to a backend variable for the facade")
-  assert(defined(invoker.public),
-         "If your facade does not explicitly expose an API that a backend " +
-             "must depend on, you can just directly depend on the build arg " +
-             "that the `backend` template argument would have been set to.")
 
-  _facade_name = "$target_name.facade"
+  # Only define the .facade subtarget if it has a public attribute to share.
+  if (defined(invoker.public) || defined(invoker.public_deps) ||
+      defined(invoker.public_configs)) {
+    _facade_name = "$target_name.facade"
 
-  if (get_path_info(get_label_info(":$target_name", "dir"), "name") ==
-      get_label_info(":$target_name", "name")) {
-    group("facade") {
-      public_deps = [ ":$_facade_name" ]
+    # Define //foo:facade alias
+    if (get_path_info(get_label_info(":$target_name", "dir"), "name") ==
+        get_label_info(":$target_name", "name")) {
+      group("facade") {
+        public_deps = [ ":$_facade_name" ]
+      }
     }
+  } else {
+    _facade_name = ""
   }
 
   _facade_vars = [
@@ -100,9 +103,12 @@
     "public_configs",
     "public_deps",
     "public",
+    "visibility",
   ]
-  pw_source_set(_facade_name) {
-    forward_variables_from(invoker, _facade_vars, [ "require_link_deps" ])
+  if (_facade_name != "") {
+    pw_source_set(_facade_name) {
+      forward_variables_from(invoker, _facade_vars, [ "require_link_deps" ])
+    }
   }
 
   if (invoker.backend == "") {
@@ -158,14 +164,16 @@
                    ]
     forward_variables_from(invoker, "*", _ignore_vars)
 
-    public_deps = [ ":$_facade_name" ]
-
     # If the backend is set, inject it as a dependency.
     if (invoker.backend != "") {
-      public_deps += [ invoker.backend ]
+      public_deps = [ invoker.backend ]
     } else {
       # If the backend is not set, depend on the *.NO_BACKEND_SET target.
-      public_deps += [ ":$target_name.NO_BACKEND_SET" ]
+      public_deps = [ ":$target_name.NO_BACKEND_SET" ]
+    }
+
+    if (_facade_name != "") {
+      public_deps += [ ":$_facade_name" ]
     }
   }
 
@@ -183,11 +191,11 @@
         }
       }
 
-      _facade_name = get_label_info(":$target_name", "label_no_toolchain")
+      _facade = get_label_info(":$target_name", "label_no_toolchain")
       assert(_dep_is_in_link_dependencies,
              "$_required_dep must be listed in the pw_build_LINK_DEPS build " +
-                 "arg when the $_facade_name facade is in use. Please update " +
-                 "your toolchain configuration.")
+                 "arg when the $_facade facade is in use. Please update your " +
+                 "toolchain configuration.")
     }
   } else {
     not_needed(invoker, [ "require_link_deps" ])
diff --git a/pw_build/gn.rst b/pw_build/gn.rst
index fd20c96..31f5aa5 100644
--- a/pw_build/gn.rst
+++ b/pw_build/gn.rst
@@ -378,12 +378,14 @@
 This allows the facade to provide header files, compilation options or anything
 else a GN ``source_set`` provides.
 
-The ``pw_facade`` template declares two targets:
+The ``pw_facade`` template declares one or two targets:
 
-* ``$target_name``: the public-facing ``pw_source_set``, with a ``public_dep``
-  on the backend
-* ``$target_name.facade``: target used by the backend to avoid circular
-  dependencies
+* ``$target_name``: The public-facing ``pw_source_set``, with a ``public_dep``
+  on the backend. Always declared.
+* ``$target_name.facade``: Target with ``public`` headers, ``public_deps``, and
+  ``public_configs`` shared between the public-facing ``pw_source_set`` and
+  backend to avoid circular dependencies. Only declared if ``public``,
+  ``public_deps``, or ``public_configs`` are provided.
 
 .. code-block::
 
diff --git a/pw_sync/BUILD.gn b/pw_sync/BUILD.gn
index 235d8b6..0f20710 100644
--- a/pw_sync/BUILD.gn
+++ b/pw_sync/BUILD.gn
@@ -131,7 +131,11 @@
     "$dir_pw_preprocessor",
   ]
   sources = [ "recursive_mutex.cc" ]
-  visibility = [ ":*" ]
+  visibility = [
+    ":*",
+    "$dir_pw_sync_baremetal/*",
+    "$dir_pw_sync_stl/*",
+  ]
 }
 
 pw_facade("interrupt_spin_lock") {