pw_build: Expand facade template

This change updates the pw_facade template to create both a facade
interface and library. This avoids having to manually define the
interface when writing a facade module.

Change-Id: I7401c6c363b4e45a976752243d5a77e9d4599c18
diff --git a/pw_build/facade.gni b/pw_build/facade.gni
index d9cd7f1..8f34596 100644
--- a/pw_build/facade.gni
+++ b/pw_build/facade.gni
@@ -32,8 +32,47 @@
 #  - backend: the dependency that implements this facade
 #
 template("pw_facade") {
+  assert(defined(invoker.backend),
+         "pw_facade requires a reference to a backend variable for the facade")
+
+  # A facade's headers are split into a separate target to avoid a circular
+  # dependency between the facade and the backend.
+  #
+  # For example, the following targets:
+  #
+  #   foo_backend = "//foo:foo_backend_bar"
+  #
+  #   pw_facade("foo") {
+  #     backend = foo_backend
+  #     public = [ "foo.h" ]
+  #     sources = [ "foo.cc" ]
+  #   }
+  #
+  #   source_set("foo_backend_bar") {
+  #     deps = [ ":facade" ]
+  #     sources = [ "bar.cc" ]
+  #   }
+  #
+  # Create the following dependency graph:
+  #
+  #   facade  <-.
+  #    ^         \
+  #    |          \
+  #    |           \
+  #   foo  ------>  foo_backend_bar
+  #
+  _facade_vars = [
+    "public_configs",
+    "public_deps",
+    "public",
+  ]
+  source_set("facade") {
+    forward_variables_from(invoker, _facade_vars)
+    sources = public
+  }
+
   if (invoker.backend == "") {
-    # If backend is not set to anything, emit an error.
+    # If backend is not set to anything, create a script that emits an error.
     pw_python_script(target_name) {
       stamp = true
       script = "$dir_pw_build/py/null_backend.py"
@@ -41,19 +80,27 @@
       not_needed(invoker, "*")
     }
   } else {
+    # When a backend is set, create a target defining the facade library.
     source_set(target_name) {
-      # If the backend is set, create a new source_set.
-      _ignore_vars = [
-        "backend",
-        "deps",
-      ]
-      if (defined(invoker.deps)) {
-        deps = invoker.deps
-      } else {
-        deps = []
-      }
-      deps += [ invoker.backend ]
+      # The main library contains everything else specified in the template.
+      _ignore_vars = [ "backend" ] + _facade_vars
       forward_variables_from(invoker, "*", _ignore_vars)
+
+      public_deps = [
+        ":facade",
+
+        # Inject the backend as a dependency.
+        invoker.backend,
+      ]
+
+      if (defined(sources)) {
+        # Protect against the pattern
+        #
+        #   sources = [ "foo.cc" ] + public
+        #
+        # as the public headers are already listed in the :facade target.
+        sources -= invoker.public
+      }
     }
   }
 }
diff --git a/pw_cpu_exception/BUILD.gn b/pw_cpu_exception/BUILD.gn
index 2e62376..580e655 100644
--- a/pw_cpu_exception/BUILD.gn
+++ b/pw_cpu_exception/BUILD.gn
@@ -19,7 +19,8 @@
   include_dirs = [ "public" ]
 }
 
-source_set("facade") {
+pw_facade("pw_cpu_exception") {
+  backend = dir_pw_cpu_exception_backend
   public_configs = [ ":default_config" ]
   public_deps = [
     "$dir_pw_preprocessor",
@@ -29,14 +30,6 @@
   public = [
     "public/pw_cpu_exception/cpu_exception.h",
   ]
-  sources = public
-}
-
-pw_facade("pw_cpu_exception") {
-  backend = dir_pw_cpu_exception_backend
-  public_deps = [
-    ":facade",
-  ]
 }
 
 pw_doc_group("docs") {
diff --git a/pw_dumb_io/BUILD.gn b/pw_dumb_io/BUILD.gn
index 50bc709..47d2d06 100644
--- a/pw_dumb_io/BUILD.gn
+++ b/pw_dumb_io/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 The Pigweed Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
@@ -19,7 +19,8 @@
   include_dirs = [ "public" ]
 }
 
-source_set("facade") {
+pw_facade("pw_dumb_io") {
+  backend = dir_pw_dumb_io_backend
   public_configs = [ ":default_config" ]
   public_deps = [
     "$dir_pw_span",
@@ -28,7 +29,6 @@
   public = [
     "public/pw_dumb_io/dumb_io.h",
   ]
-  sources = public
 }
 
 source_set("default_putget_bytes") {
@@ -40,13 +40,6 @@
   ]
 }
 
-pw_facade("pw_dumb_io") {
-  backend = dir_pw_dumb_io_backend
-  public_deps = [
-    ":facade",
-  ]
-}
-
 pw_doc_group("docs") {
   sources = [
     "docs.rst",
diff --git a/pw_log/BUILD.gn b/pw_log/BUILD.gn
index 40965fb..e3aa8df 100644
--- a/pw_log/BUILD.gn
+++ b/pw_log/BUILD.gn
@@ -20,20 +20,13 @@
   include_dirs = [ "public" ]
 }
 
-source_set("facade") {
+pw_facade("pw_log") {
+  backend = dir_pw_log_backend
   public_configs = [ ":default_config" ]
   public = [
     "public/pw_log/levels.h",
     "public/pw_log/log.h",
   ]
-  sources = public
-}
-
-pw_facade("pw_log") {
-  backend = dir_pw_log_backend
-  public_deps = [
-    ":facade",
-  ]
 }
 
 pw_test_group("tests") {
diff --git a/pw_target_runner/go/src/pigweed.dev/pw_target_runner_client/main.go b/pw_target_runner/go/src/pigweed.dev/pw_target_runner_client/main.go
index cf01b5f..90eb4a8 100644
--- a/pw_target_runner/go/src/pigweed.dev/pw_target_runner_client/main.go
+++ b/pw_target_runner/go/src/pigweed.dev/pw_target_runner_client/main.go
@@ -74,7 +74,7 @@
 	fmt.Println(string(res.Output))
 
 	if res.Result != pb.RunStatus_SUCCESS {
-		return errors.New("Failed to run binary")
+		return errors.New("Binary run was unsuccessful")
 	}
 
 	return nil
diff --git a/pw_unit_test/BUILD.gn b/pw_unit_test/BUILD.gn
index 6d8841e..e4eb1d0 100644
--- a/pw_unit_test/BUILD.gn
+++ b/pw_unit_test/BUILD.gn
@@ -72,9 +72,6 @@
     public_deps = [
       ":pw_unit_test",
       "$dir_pw_log",
-
-      # TODO: When the pw_facade() template is fixed, removed this.
-      "$dir_pw_log_backend",
       "$dir_pw_preprocessor",
     ]
     public = [