pw_trace: Add pw_trace:null as default backend

This module is added to act as the default backend for pw_trace where
trace is disabled. With this module, applications would not be required
to set a backend. This backend is implemented with empty functions and
handles unused variables as well.

Test: presubmit involves tests. But an application without backend is
set.
Bug: b/202193001

Change-Id: I676d49ffedf64e5ce493f188349b5a4d8ba17153
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/68141
Reviewed-by: Wyatt Hepler <hepler@google.com>
Reviewed-by: Rob Oliver <rgoliver@google.com>
Commit-Queue: Yuanyao Zhong <yyzhong@google.com>
diff --git a/pw_trace/BUILD.bazel b/pw_trace/BUILD.bazel
index e0b7725..deeb15c 100644
--- a/pw_trace/BUILD.bazel
+++ b/pw_trace/BUILD.bazel
@@ -45,6 +45,29 @@
 )
 
 pw_cc_library(
+    name = "null_headers",
+    hdrs = [
+        "public/pw_trace/internal/null.h",
+        "public_overrides/pw_trace_backend/trace_backend.h",
+    ],
+    includes = [
+        "public",
+        "public_overrides",
+    ],
+    deps = [
+        "//pw_preprocessor",
+    ],
+)
+
+pw_cc_library(
+    name = "null",
+    deps = [
+        "//pw_trace:facade",
+        "//pw_trace:null_headers",
+    ],
+)
+
+pw_cc_library(
     name = "backend",
     deps = [],
 )
@@ -85,6 +108,21 @@
 )
 
 pw_cc_library(
+    name = "trace_null_test",
+    srcs = [
+        "trace_null_test.cc",
+        "trace_null_test_c.c",
+    ],
+    deps = [
+        ":facade",
+        ":null",
+        ":pw_trace",
+        "//pw_preprocessor",
+        "//pw_unit_test",
+    ],
+)
+
+pw_cc_library(
     name = "pw_trace_sample_app",
     srcs = ["example/sample_app.cc"],
     hdrs = ["example/public/pw_trace/example/sample_app.h"],
diff --git a/pw_trace/BUILD.gn b/pw_trace/BUILD.gn
index b0e455b..a62d1af 100644
--- a/pw_trace/BUILD.gn
+++ b/pw_trace/BUILD.gn
@@ -23,6 +23,11 @@
   include_dirs = [ "public" ]
 }
 
+config("null_config") {
+  include_dirs = [ "public_overrides" ]
+  visibility = [ ":*" ]
+}
+
 pw_facade("pw_trace") {
   backend = pw_trace_BACKEND
   public_configs = [ ":default_config" ]
@@ -30,11 +35,25 @@
     "public/pw_trace/internal/trace_internal.h",
     "public/pw_trace/trace.h",
   ]
-  deps = [ dir_pw_preprocessor ]
+  public_deps = [ dir_pw_preprocessor ]
+}
+
+pw_source_set("null") {
+  public_configs = [
+    ":default_config",
+    ":null_config",
+  ]
+  public = [ "public_overrides/pw_trace_backend/trace_backend.h" ]
+  sources = [ "public/pw_trace/internal/null.h" ]
+  friend = [ ":*" ]
+  public_deps = [ dir_pw_preprocessor ]
 }
 
 pw_test_group("tests") {
-  tests = [ ":trace_facade_test" ]
+  tests = [
+    ":trace_facade_test",
+    ":trace_null_test",
+  ]
   if (pw_trace_BACKEND != "") {
     tests += [ ":trace_backend_compile_test" ]
   }
@@ -69,6 +88,14 @@
   ]
 }
 
+pw_test("trace_null_test") {
+  sources = [
+    "trace_null_test.cc",
+    "trace_null_test_c.c",
+  ]
+  deps = [ ":null" ]
+}
+
 pw_doc_group("docs") {
   sources = [ "docs.rst" ]
 }
diff --git a/pw_trace/CMakeLists.txt b/pw_trace/CMakeLists.txt
index 7a4fe84..7b2bf97 100644
--- a/pw_trace/CMakeLists.txt
+++ b/pw_trace/CMakeLists.txt
@@ -18,3 +18,23 @@
   PUBLIC_DEPS
     pw_preprocessor
 )
+
+pw_add_module_library(pw_trace.null
+  IMPLEMENTS_FACADES
+    pw_trace
+  HEADERS
+    public/pw_trace/internal/null.h
+    public_overrides/pw_trace_backend/trace_backend.h
+  PUBLIC_DEPS
+    pw_preprocessor
+)
+
+pw_add_test(pw_trace.pw_trace_null_test
+  SOURCES
+    trace_null_test.cc
+    trace_null_test_c.c
+  DEPS
+    pw_trace.null
+  GROUPS
+    pw_trace
+)
\ No newline at end of file
diff --git a/pw_trace/backend.gni b/pw_trace/backend.gni
index 961dd57..ddb706d 100644
--- a/pw_trace/backend.gni
+++ b/pw_trace/backend.gni
@@ -12,7 +12,9 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
+import("//build_overrides/pigweed.gni")
+
 declare_args() {
-  # Backend for the pw_trace module.
-  pw_trace_BACKEND = ""
+  # Default backend for the pw_trace module is pw_trace:null.
+  pw_trace_BACKEND = "$dir_pw_trace:null"
 }
diff --git a/pw_trace/docs.rst b/pw_trace/docs.rst
index 30cf831..51171ee 100644
--- a/pw_trace/docs.rst
+++ b/pw_trace/docs.rst
@@ -38,12 +38,24 @@
 and are therefore useful at understanding the flow of events in the system over
 time.
 
+The default backend for pw_trace is pw_trace_null, which disables tracing.
+
 Compatibility
 -------------
 Most of the facade is compatible with C and C++, the only exception to this is
 the Scope and Function tracing macros which are convenience wrappers only
 available in C++.
 
+pw_trace:null
+-------------
+``pw_trace_null`` is a ``pw_trace backend`` that ignores all ``pw_trace``
+statements. The backend implements ``pw_trace`` with empty inline functions.
+Using empty functions ensure that the arguments are evaluated and their types
+are correct. Since the functions are inline in the header, the compiler will
+optimize out the function call.
+
+This backend can be used to completely disable ``pw_trace``.
+
 Dependencies
 -------------
 ``pw_preprocessor``
diff --git a/pw_trace/public/pw_trace/internal/null.h b/pw_trace/public/pw_trace/internal/null.h
new file mode 100644
index 0000000..155b54a
--- /dev/null
+++ b/pw_trace/public/pw_trace/internal/null.h
@@ -0,0 +1,83 @@
+// Copyright 2021 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
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "pw_preprocessor/compiler.h"
+#include "pw_preprocessor/util.h"
+
+// Enable traces
+#define PW_TRACE_TYPE_INSTANT 1
+#define PW_TRACE_TYPE_INSTANT_GROUP 1
+#define PW_TRACE_TYPE_DURATION_START 1
+#define PW_TRACE_TYPE_DURATION_END 1
+#define PW_TRACE_TYPE_DURATION_GROUP_START 1
+#define PW_TRACE_TYPE_DURATION_GROUP_END 1
+#define PW_TRACE_TYPE_ASYNC_START 1
+#define PW_TRACE_TYPE_ASYNC_INSTANT 1
+#define PW_TRACE_TYPE_ASYNC_END 1
+
+PW_EXTERN_C_START
+
+// Empty function for compiling out trace statements. Since the function is
+// empty and inline, it should be completely compiled out. This function
+// accomplishes following:
+//
+//   - Uses the arguments to PW_TRACE, which avoids "unused variable" warnings.
+//   - Executes expressions passed to PW_TRACE, so that the behavior is
+//     consistent between this null backend and an actual backend.
+//
+// These two functions are used in PW_TRACE and PW_TRACE_DATA.
+
+static inline void pw_trace_Ignored(int event_type,
+                                    uint8_t flags,
+                                    const char* label,
+                                    const char* group,
+                                    uint32_t trace_id) {
+  (void)event_type;
+  (void)flags;
+  (void)label;
+  (void)group;
+  (void)trace_id;
+}
+
+static inline void pw_trace_data_Ignored(int event_type,
+                                         uint8_t flags,
+                                         const char* label,
+                                         const char* group,
+                                         uint32_t trace_id,
+                                         const char* type,
+                                         const char* data,
+                                         size_t size) {
+  (void)event_type;
+  (void)flags;
+  (void)label;
+  (void)group;
+  (void)trace_id;
+  (void)type;
+  (void)data;
+  (void)size;
+}
+
+PW_EXTERN_C_END
+
+#define PW_TRACE(event_type, flags, label, group, trace_id) \
+  pw_trace_Ignored(event_type, flags, label, group, trace_id)
+
+#define PW_TRACE_DATA(                                           \
+    event_type, flags, label, group, trace_id, type, data, size) \
+  pw_trace_data_Ignored(                                         \
+      event_type, flags, label, group, trace_id, type, data, size)
diff --git a/pw_trace/public_overrides/pw_trace_backend/trace_backend.h b/pw_trace/public_overrides/pw_trace_backend/trace_backend.h
new file mode 100644
index 0000000..c31e7a9
--- /dev/null
+++ b/pw_trace/public_overrides/pw_trace_backend/trace_backend.h
@@ -0,0 +1,16 @@
+// Copyright 2021 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
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include "pw_trace/internal/null.h"
diff --git a/pw_trace/trace_null_test.cc b/pw_trace/trace_null_test.cc
new file mode 100644
index 0000000..d82714d
--- /dev/null
+++ b/pw_trace/trace_null_test.cc
@@ -0,0 +1,30 @@
+// Copyright 2021 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
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "gtest/gtest.h"
+#include "pw_trace/internal/null.h"
+
+#define PW_TRACE_MODULE_NAME "this test!"
+
+extern "C" bool CTest();
+
+namespace {
+
+TEST(TraceNull, PW_TRACE) { PW_TRACE(0, 1, "label", "group", 2); }
+
+TEST(TraceNull, PW_TRACE_DATA) {
+  PW_TRACE_DATA(0, 1, "label", "group", 2, "type", "data", 1);
+}
+
+}  // namespace
diff --git a/pw_trace/trace_null_test_c.c b/pw_trace/trace_null_test_c.c
new file mode 100644
index 0000000..5c4ebdd
--- /dev/null
+++ b/pw_trace/trace_null_test_c.c
@@ -0,0 +1,26 @@
+// Copyright 2021 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
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "pw_trace/internal/null.h"
+
+#define PW_TRACE_MODULE_NAME "c test!"
+
+bool CTest(void) {
+  PW_TRACE(0, 1, "label", "group", 2);
+  PW_TRACE_DATA(0, 1, "label", "group", 2, "type", "data", 1);
+  return true;
+}