pw_build: Update docs for generated third-party

This CL corrects an oversight in generate_3p_gn.py and adds a step to
add a dep on the "docs" target it produces to //docs:third_party_docs.

This pulls in the //third_party/<library>/BUILD.gn files for the docs
toolchain, so the non-doc targets in those files are conditionally
defined based on the `dir_pw_third_party_<library>` build arguments.

These changes required refreshing the build files and docs for
Abseil C++, FuzzTest, and RE2 using generate_3p_gn.py.

Change-Id: I09b8cd70f977605b5a28ca9c8b42f35475beeb32
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/146593
Reviewed-by: Taylor Cramer <cramertj@google.com>
Commit-Queue: Aaron Green <aarongreen@google.com>
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index ae098ad..05415fa 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -99,12 +99,15 @@
 
 group("third_party_docs") {
   deps = [
+    "$dir_pigweed/third_party/abseil-cpp:docs",
     "$dir_pigweed/third_party/boringssl:docs",
     "$dir_pigweed/third_party/emboss:docs",
     "$dir_pigweed/third_party/freertos:docs",
     "$dir_pigweed/third_party/fuchsia:docs",
+    "$dir_pigweed/third_party/fuzztest:docs",
     "$dir_pigweed/third_party/googletest:docs",
     "$dir_pigweed/third_party/nanopb:docs",
+    "$dir_pigweed/third_party/re2:docs",
     "$dir_pigweed/third_party/tinyusb:docs",
   ]
 }
diff --git a/pw_build/py/generate_3p_gn_test.py b/pw_build/py/generate_3p_gn_test.py
index 6bffb7f..5d9f827 100644
--- a/pw_build/py/generate_3p_gn_test.py
+++ b/pw_build/py/generate_3p_gn_test.py
@@ -377,24 +377,26 @@
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_third_party/test/test.gni")
 
-config("test_config1") {
-  cflags = [
-    "common",
-  ]
-}
+if (dir_pw_third_party_test != "") {
+  config("test_config1") {
+    cflags = [
+      "common",
+    ]
+  }
 
-# Generated from //:target0
-pw_executable("target0") {
-  sources = [
-    "$dir_pw_third_party_test/target0.cc",
-  ]
-  configs = [
-    ":test_config1",
-  ]
-  deps = [
-    "foo:target1",
-    "foo:target2",
-  ]
+  # Generated from //:target0
+  pw_executable("target0") {
+    sources = [
+      "$dir_pw_third_party_test/target0.cc",
+    ]
+    configs = [
+      ":test_config1",
+    ]
+    deps = [
+      "foo:target1",
+      "foo:target2",
+    ]
+  }
 }
 
 pw_doc_group("docs") {
@@ -681,6 +683,36 @@
 '''.lstrip(),
         )
 
+    def test_update_third_party_docs(self):
+        """Tests adding docs to //docs::third_party_docs."""
+        with GnGeneratorForTest() as generator:
+            contents = generator.update_third_party_docs(
+                '''
+group("third_party_docs") {
+  deps = [
+    "$dir_pigweed/third_party/existing:docs",
+  ]
+}
+'''
+            )
+        # Formatting is performed separately.
+        self.assertEqual(
+            contents,
+            '''
+group("third_party_docs") {
+deps = ["$dir_pigweed/third_party/repo:docs",
+    "$dir_pigweed/third_party/existing:docs",
+  ]
+}
+''',
+        )
+
+    def test_update_third_party_docs_no_target(self):
+        """Tests adding docs to a file without a "third_party_docs" target."""
+        with GnGeneratorForTest() as generator:
+            with self.assertRaises(ValueError):
+                generator.update_third_party_docs('')
+
     @mock.patch('subprocess.run')
     def test_write_extra(self, mock_run):
         """Tests extra files produced via `bazel run`."""
diff --git a/pw_build/py/pw_build/generate_3p_gn.py b/pw_build/py/pw_build/generate_3p_gn.py
index 92e4fde..8c4e468 100644
--- a/pw_build/py/pw_build/generate_3p_gn.py
+++ b/pw_build/py/pw_build/generate_3p_gn.py
@@ -26,7 +26,7 @@
 from pw_build.gn_config import consolidate_configs, GnConfig
 from pw_build.gn_target import GnTarget
 from pw_build.gn_utils import GnLabel, GnPath
-from pw_build.gn_writer import GnFile, GnWriter, MalformedGnError
+from pw_build.gn_writer import gn_format, GnFile, GnWriter, MalformedGnError
 
 _DOCS_RST_TEMPLATE = Template(
     '''
@@ -291,6 +291,9 @@
             imports.add(f'$dir_pw_third_party/{self._repo}/{self._repo}.gni')
         build_gn.write_imports(sorted(list(imports)))
 
+        if not package:
+            build_gn.write_if(f'dir_pw_third_party_{self._repo_var} != ""')
+
         for config in sorted(self.configs[package], reverse=True):
             build_gn.write_config(config)
 
@@ -300,6 +303,7 @@
             build_gn.write_target(target)
 
         if not package:
+            build_gn.write_end()
             build_gn.write_target_start('pw_doc_group', 'docs')
             build_gn.write_list('sources', ['docs.rst'])
             build_gn.write_end()
@@ -350,6 +354,16 @@
         yield f'.. _{short}: {url}/tree/{revision}'
         yield ''
 
+    def update_third_party_docs(self, contents: str) -> str:
+        """Adds a dep on the generated docs to a "third_party_docs" group."""
+        lines = contents.split('\n')
+        new_deps = f'deps = ["$dir_pigweed/third_party/{self._repo}:docs",'
+        for i in range(len(lines) - 1):
+            if lines[i] == 'group("third_party_docs") {':
+                lines[i + 1] = new_deps
+                return '\n'.join(lines)
+        raise ValueError('"third_party_docs" target not found')
+
     def write_extra(self, extra: IO, label: str) -> None:
         """Runs a Bazel target to generate an extra file."""
         self._workspace.run(label, output=extra)
@@ -401,35 +415,44 @@
     output = Path(pw_root, 'third_party', repo)
 
     with open(output.joinpath('repo.json')) as file:
-        obj = json.load(file)
-        name = obj['name']
-        repos = obj.get('repos', {})
-        aliases = obj.get('aliases', {})
-        add_configs = obj.get('add', [])
-        removeconfigs = obj.get('remove', [])
-        allow_testonly = obj.get('allow_testonly', False)
-        no_gn_check = obj.get('no_gn_check', [])
-        extra_files = obj.get('extra_files', {})
+        repo_json = json.load(file)
 
-    for exclusion in no_gn_check:
+    for exclusion in repo_json.get('no_gn_check', []):
         generator.exclude_from_gn_check(bazel=exclusion)
-    generator.load_targets('cc_library', allow_testonly)
-    generator.generate_configs(add_configs, removeconfigs)
+    generator.load_targets('cc_library', repo_json.get('allow_testonly', False))
+    generator.generate_configs(
+        repo_json.get('add', []), repo_json.get('remove', [])
+    )
 
+    name = repo_json['name']
     with GnFile(Path(output, f'{repo}.gni')) as repo_gni:
         generator.write_repo_gni(repo_gni, name)
 
     for package in generator.packages:
         with GnFile(Path(output, package, 'BUILD.gn'), package) as build_gn:
-            build_gn.repos = repos
-            build_gn.aliases = aliases
+            build_gn.repos = repo_json.get('repos', {})
+            build_gn.aliases = repo_json.get('aliases', {})
             generator.write_build_gn(package, build_gn)
 
+    created_docs_rst = False
     try:
         with open(Path(output, 'docs.rst'), 'x') as docs_rst:
             generator.write_docs_rst(docs_rst, name)
+        created_docs_rst = True
     except OSError:
-        # docs.rst file already exists, just replace the version section.
+        pass  # docs.rst file already exists.
+
+    if created_docs_rst:
+        # Add the doc group to //docs:third_party_docs
+        docs_build_gn_path = Path(pw_root, 'docs', 'BUILD.gn')
+        with open(docs_build_gn_path, 'r') as docs_build_gn:
+            contents = docs_build_gn.read()
+        with open(docs_build_gn_path, 'w') as docs_build_gn:
+            docs_build_gn.write(generator.update_third_party_docs(contents))
+        gn_format(docs_build_gn_path)
+
+    else:
+        # Replace the version section of the existing docs.rst.
         with open(Path(output, 'docs.rst'), 'r') as docs_rst:
             contents = '\n'.join(generator.update_version(docs_rst))
         with open(Path(output, 'docs.rst'), 'w') as docs_rst:
@@ -441,7 +464,7 @@
     except OSError:
         pass  # OWNERS file already exists.
 
-    for filename, label in extra_files.items():
+    for filename, label in repo_json.get('extra_files', {}).items():
         with open(Path(output, filename), 'w') as extra:
             generator.write_extra(extra, label)
 
diff --git a/pw_build/py/pw_build/gn_writer.py b/pw_build/py/pw_build/gn_writer.py
index 48a2b6f..354a5de 100644
--- a/pw_build/py/pw_build/gn_writer.py
+++ b/pw_build/py/pw_build/gn_writer.py
@@ -17,7 +17,7 @@
 import subprocess
 
 from datetime import datetime
-from pathlib import PurePath, PurePosixPath
+from pathlib import Path, PurePath, PurePosixPath
 from types import TracebackType
 from typing import Dict, IO, Iterable, Iterator, List, Optional, Type, Union
 
@@ -325,6 +325,11 @@
             raise MalformedGnError(f'unclosed scope(s): {self._scopes}')
 
 
+def gn_format(gn_file: Path) -> None:
+    """Calls `gn format` on a BUILD.gn or GN import file."""
+    subprocess.check_call(['gn', 'format', gn_file])
+
+
 class GnFile:
     """Represents an open BUILD.gn file that is formatted on close.
 
@@ -371,4 +376,4 @@
     ) -> None:
         """Closes the GN file and formats it."""
         self._file.close()
-        subprocess.check_call(['gn', 'format', self._pathname])
+        gn_format(Path(self._pathname))
diff --git a/third_party/abseil-cpp/BUILD.gn b/third_party/abseil-cpp/BUILD.gn
index 41de09d..a8a5437 100644
--- a/third_party/abseil-cpp/BUILD.gn
+++ b/third_party/abseil-cpp/BUILD.gn
@@ -21,32 +21,34 @@
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_third_party/abseil-cpp/abseil-cpp.gni")
 
-config("abseil_cpp_public_config1") {
-  include_dirs = [ "$dir_pw_third_party_abseil_cpp" ]
-}
+if (dir_pw_third_party_abseil_cpp != "") {
+  config("abseil_cpp_public_config1") {
+    include_dirs = [ "$dir_pw_third_party_abseil_cpp" ]
+  }
 
-config("abseil_cpp_config1") {
-  cflags = [
-    "-DNOMINMAX",
-    "-Wall",
-    "-Wcast-qual",
-    "-Wconversion-null",
-    "-Wextra",
-    "-Wformat-security",
-    "-Wmissing-declarations",
-    "-Woverlength-strings",
-    "-Wpointer-arith",
-    "-Wundef",
-    "-Wunused-local-typedefs",
-    "-Wunused-result",
-    "-Wvarargs",
-    "-Wvla",
-    "-Wwrite-strings",
-  ]
-}
+  config("abseil_cpp_config1") {
+    cflags = [
+      "-DNOMINMAX",
+      "-Wall",
+      "-Wcast-qual",
+      "-Wconversion-null",
+      "-Wextra",
+      "-Wformat-security",
+      "-Wmissing-declarations",
+      "-Woverlength-strings",
+      "-Wpointer-arith",
+      "-Wundef",
+      "-Wunused-local-typedefs",
+      "-Wunused-result",
+      "-Wvarargs",
+      "-Wvla",
+      "-Wwrite-strings",
+    ]
+  }
 
-config("abseil_cpp_config2") {
-  ldflags = [ "-pthread" ]
+  config("abseil_cpp_config2") {
+    ldflags = [ "-pthread" ]
+  }
 }
 
 pw_doc_group("docs") {
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn
index e75fae3..10f3ec4 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.gn
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn
@@ -162,6 +162,7 @@
     ":debugging_internal",
     "../base:config",
     "../base:core_headers",
+    "../base:dynamic_annotations",
     "../base:raw_logging_internal",
   ]
 }
diff --git a/third_party/abseil-cpp/absl/utility/BUILD.gn b/third_party/abseil-cpp/absl/utility/BUILD.gn
index 274a918..c135b76 100644
--- a/third_party/abseil-cpp/absl/utility/BUILD.gn
+++ b/third_party/abseil-cpp/absl/utility/BUILD.gn
@@ -21,6 +21,19 @@
 import("$dir_pw_build/target_types.gni")
 import("$dir_pw_third_party/abseil-cpp/abseil-cpp.gni")
 
+# Generated from //absl/utility:if_constexpr
+pw_source_set("if_constexpr") {
+  public =
+      [ "$dir_pw_third_party_abseil_cpp/absl/utility/internal/if_constexpr.h" ]
+  public_configs = [ "../..:abseil_cpp_public_config1" ]
+  configs = [
+    "../../configs:internal_disabled_warnings",
+    "../..:abseil_cpp_config1",
+  ]
+  remove_configs = [ "$dir_pw_fuzzer:instrumentation" ]
+  public_deps = [ "../base:config" ]
+}
+
 # Generated from //absl/utility:utility
 pw_source_set("utility") {
   public = [ "$dir_pw_third_party_abseil_cpp/absl/utility/utility.h" ]
diff --git a/third_party/abseil-cpp/docs.rst b/third_party/abseil-cpp/docs.rst
index 878c609..ade408a 100644
--- a/third_party/abseil-cpp/docs.rst
+++ b/third_party/abseil-cpp/docs.rst
@@ -49,5 +49,6 @@
 
 Version
 =======
-The update script was last run for revision:
-8518869eb9a8ef098a9dd7780b9e55d5b43b5873
+The update script was last run for revision `67f9650`_.
+
+.. _67f9650: https://github.com/abseil/abseil-cpp/tree/67f9650c93a4fa04728a5b754ae8297d2c55d898
diff --git a/third_party/fuzztest/BUILD.gn b/third_party/fuzztest/BUILD.gn
index f2fe934..3581480 100644
--- a/third_party/fuzztest/BUILD.gn
+++ b/third_party/fuzztest/BUILD.gn
@@ -21,8 +21,10 @@
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_third_party/fuzztest/fuzztest.gni")
 
-config("fuzztest_public_config1") {
-  include_dirs = [ "$dir_pw_third_party_fuzztest" ]
+if (dir_pw_third_party_fuzztest != "") {
+  config("fuzztest_public_config1") {
+    include_dirs = [ "$dir_pw_third_party_fuzztest" ]
+  }
 }
 
 pw_doc_group("docs") {
diff --git a/third_party/fuzztest/centipede/BUILD.gn b/third_party/fuzztest/centipede/BUILD.gn
index 37b05ae..efddad8 100644
--- a/third_party/fuzztest/centipede/BUILD.gn
+++ b/third_party/fuzztest/centipede/BUILD.gn
@@ -181,6 +181,7 @@
     "$dir_pw_toolchain/host_clang:sanitize_undefined",
     "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
   ]
+  public_deps = [ ":int_utils" ]
 }
 
 # Generated from //centipede:centipede_callbacks
@@ -319,6 +320,7 @@
     ":environment",
     ":execution_result",
     ":feature",
+    ":feature_set",
     ":logging",
     ":remote_file",
     ":rusage_profiler",
@@ -340,6 +342,7 @@
   sources = [
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.cc",
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.h",
+    "$dir_pw_third_party_fuzztest/centipede/callstack.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_bitset.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_byteset.h",
     "$dir_pw_third_party_fuzztest/centipede/defs.h",
@@ -350,8 +353,10 @@
     "$dir_pw_third_party_fuzztest/centipede/feature.cc",
     "$dir_pw_third_party_fuzztest/centipede/feature.h",
     "$dir_pw_third_party_fuzztest/centipede/foreach_nonzero.h",
+    "$dir_pw_third_party_fuzztest/centipede/int_utils.h",
     "$dir_pw_third_party_fuzztest/centipede/knobs.cc",
     "$dir_pw_third_party_fuzztest/centipede/knobs.h",
+    "$dir_pw_third_party_fuzztest/centipede/pc_info.h",
     "$dir_pw_third_party_fuzztest/centipede/reverse_pc_table.h",
     "$dir_pw_third_party_fuzztest/centipede/runner.cc",
     "$dir_pw_third_party_fuzztest/centipede/runner.h",
@@ -395,6 +400,7 @@
   sources = [
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.cc",
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.h",
+    "$dir_pw_third_party_fuzztest/centipede/callstack.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_bitset.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_byteset.h",
     "$dir_pw_third_party_fuzztest/centipede/defs.h",
@@ -405,8 +411,10 @@
     "$dir_pw_third_party_fuzztest/centipede/feature.cc",
     "$dir_pw_third_party_fuzztest/centipede/feature.h",
     "$dir_pw_third_party_fuzztest/centipede/foreach_nonzero.h",
+    "$dir_pw_third_party_fuzztest/centipede/int_utils.h",
     "$dir_pw_third_party_fuzztest/centipede/knobs.cc",
     "$dir_pw_third_party_fuzztest/centipede/knobs.h",
+    "$dir_pw_third_party_fuzztest/centipede/pc_info.h",
     "$dir_pw_third_party_fuzztest/centipede/reverse_pc_table.h",
     "$dir_pw_third_party_fuzztest/centipede/runner.cc",
     "$dir_pw_third_party_fuzztest/centipede/runner.h",
@@ -450,6 +458,7 @@
   sources = [
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.cc",
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.h",
+    "$dir_pw_third_party_fuzztest/centipede/callstack.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_bitset.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_byteset.h",
     "$dir_pw_third_party_fuzztest/centipede/defs.h",
@@ -460,8 +469,10 @@
     "$dir_pw_third_party_fuzztest/centipede/feature.cc",
     "$dir_pw_third_party_fuzztest/centipede/feature.h",
     "$dir_pw_third_party_fuzztest/centipede/foreach_nonzero.h",
+    "$dir_pw_third_party_fuzztest/centipede/int_utils.h",
     "$dir_pw_third_party_fuzztest/centipede/knobs.cc",
     "$dir_pw_third_party_fuzztest/centipede/knobs.h",
+    "$dir_pw_third_party_fuzztest/centipede/pc_info.h",
     "$dir_pw_third_party_fuzztest/centipede/reverse_pc_table.h",
     "$dir_pw_third_party_fuzztest/centipede/runner.cc",
     "$dir_pw_third_party_fuzztest/centipede/runner.h",
@@ -505,6 +516,7 @@
   sources = [
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.cc",
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.h",
+    "$dir_pw_third_party_fuzztest/centipede/callstack.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_bitset.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_byteset.h",
     "$dir_pw_third_party_fuzztest/centipede/defs.h",
@@ -515,8 +527,10 @@
     "$dir_pw_third_party_fuzztest/centipede/feature.cc",
     "$dir_pw_third_party_fuzztest/centipede/feature.h",
     "$dir_pw_third_party_fuzztest/centipede/foreach_nonzero.h",
+    "$dir_pw_third_party_fuzztest/centipede/int_utils.h",
     "$dir_pw_third_party_fuzztest/centipede/knobs.cc",
     "$dir_pw_third_party_fuzztest/centipede/knobs.h",
+    "$dir_pw_third_party_fuzztest/centipede/pc_info.h",
     "$dir_pw_third_party_fuzztest/centipede/reverse_pc_table.h",
     "$dir_pw_third_party_fuzztest/centipede/runner.cc",
     "$dir_pw_third_party_fuzztest/centipede/runner.h",
@@ -560,6 +574,7 @@
   sources = [
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.cc",
     "$dir_pw_third_party_fuzztest/centipede/byte_array_mutator.h",
+    "$dir_pw_third_party_fuzztest/centipede/callstack.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_bitset.h",
     "$dir_pw_third_party_fuzztest/centipede/concurrent_byteset.h",
     "$dir_pw_third_party_fuzztest/centipede/defs.h",
@@ -570,8 +585,10 @@
     "$dir_pw_third_party_fuzztest/centipede/feature.cc",
     "$dir_pw_third_party_fuzztest/centipede/feature.h",
     "$dir_pw_third_party_fuzztest/centipede/foreach_nonzero.h",
+    "$dir_pw_third_party_fuzztest/centipede/int_utils.h",
     "$dir_pw_third_party_fuzztest/centipede/knobs.cc",
     "$dir_pw_third_party_fuzztest/centipede/knobs.h",
+    "$dir_pw_third_party_fuzztest/centipede/pc_info.h",
     "$dir_pw_third_party_fuzztest/centipede/reverse_pc_table.h",
     "$dir_pw_third_party_fuzztest/centipede/runner.cc",
     "$dir_pw_third_party_fuzztest/centipede/runner.h",
@@ -631,7 +648,9 @@
     ":logging",
     ":util",
     "../../abseil-cpp/absl/log:check",
+    "../../abseil-cpp/absl/status",
     "../../abseil-cpp/absl/strings",
+    "../../abseil-cpp/absl/strings:str_format",
     "../../abseil-cpp/absl/time",
   ]
 }
@@ -719,6 +738,7 @@
     ":command",
     ":defs",
     ":logging",
+    ":pc_info",
     ":util",
     "../../abseil-cpp/absl/container:flat_hash_map",
     "../../abseil-cpp/absl/container:flat_hash_set",
@@ -750,9 +770,8 @@
     ":coverage",
     ":defs",
     ":feature",
-    ":logging",
+    ":feature_set",
     ":util",
-    "../../abseil-cpp/absl/container:flat_hash_set",
     "../../abseil-cpp/absl/strings",
   ]
 }
@@ -919,7 +938,56 @@
     "$dir_pw_toolchain/host_clang:sanitize_undefined",
     "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
   ]
-  public_deps = [ "../../abseil-cpp/absl/base:core_headers" ]
+  public_deps = [
+    ":int_utils",
+    "../../abseil-cpp/absl/base:core_headers",
+  ]
+}
+
+# Generated from //centipede:feature_set
+pw_source_set("feature_set") {
+  public = [ "$dir_pw_third_party_fuzztest/centipede/feature_set.h" ]
+  sources = [ "$dir_pw_third_party_fuzztest/centipede/feature_set.cc" ]
+  public_configs = [ "..:fuzztest_public_config1" ]
+  configs = [
+    "../../abseil-cpp/configs:disabled_warnings",
+    "../../re2/configs:disabled_warnings",
+    "../configs:internal_disabled_warnings",
+  ]
+  remove_configs = [
+    "$dir_pw_fuzzer:instrumentation",
+    "$dir_pw_toolchain/host_clang:sanitize_address",
+    "$dir_pw_toolchain/host_clang:sanitize_memory",
+    "$dir_pw_toolchain/host_clang:sanitize_thread",
+    "$dir_pw_toolchain/host_clang:sanitize_undefined",
+    "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
+  ]
+  public_deps = [
+    ":coverage",
+    ":defs",
+    ":feature",
+    ":util",
+    "../../abseil-cpp/absl/container:flat_hash_set",
+  ]
+}
+
+# Generated from //centipede:int_utils
+pw_source_set("int_utils") {
+  public = [ "$dir_pw_third_party_fuzztest/centipede/int_utils.h" ]
+  public_configs = [ "..:fuzztest_public_config1" ]
+  configs = [
+    "../../abseil-cpp/configs:disabled_warnings",
+    "../../re2/configs:disabled_warnings",
+    "../configs:internal_disabled_warnings",
+  ]
+  remove_configs = [
+    "$dir_pw_fuzzer:instrumentation",
+    "$dir_pw_toolchain/host_clang:sanitize_address",
+    "$dir_pw_toolchain/host_clang:sanitize_memory",
+    "$dir_pw_toolchain/host_clang:sanitize_thread",
+    "$dir_pw_toolchain/host_clang:sanitize_undefined",
+    "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
+  ]
 }
 
 # Generated from //centipede:knobs
@@ -999,10 +1067,9 @@
   ]
 }
 
-# Generated from //centipede:pagemap
-pw_source_set("pagemap") {
-  public = [ "$dir_pw_third_party_fuzztest/centipede/pagemap.h" ]
-  sources = [ "$dir_pw_third_party_fuzztest/centipede/pagemap.cc" ]
+# Generated from //centipede:pc_info
+pw_source_set("pc_info") {
+  public = [ "$dir_pw_third_party_fuzztest/centipede/pc_info.h" ]
   public_configs = [ "..:fuzztest_public_config1" ]
   configs = [
     "../../abseil-cpp/configs:disabled_warnings",
@@ -1017,10 +1084,6 @@
     "$dir_pw_toolchain/host_clang:sanitize_undefined",
     "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
   ]
-  public_deps = [
-    ":defs",
-    "../../abseil-cpp/absl/types:span",
-  ]
 }
 
 # Generated from //centipede:remote_file
@@ -1065,7 +1128,10 @@
     "$dir_pw_toolchain/host_clang:sanitize_undefined",
     "$dir_pw_toolchain/host_clang:sanitize_undefined_heuristic",
   ]
-  public_deps = [ "../../abseil-cpp/absl/types:span" ]
+  public_deps = [
+    ":pc_info",
+    "../../abseil-cpp/absl/types:span",
+  ]
 }
 
 # Generated from //centipede:runner_cmp_trace
diff --git a/third_party/fuzztest/docs.rst b/third_party/fuzztest/docs.rst
index ef85899..b4bef3b 100644
--- a/third_party/fuzztest/docs.rst
+++ b/third_party/fuzztest/docs.rst
@@ -79,5 +79,6 @@
 
 Version
 =======
-The update script was last run for revision:
-f2e9e2a19a7b16101d1e6f01a87e639687517a1c
+The update script was last run for revision `3c77f97`_.
+
+.. _3c77f97: https://github.com/google/fuzztest/tree/3c77f97183a1270796d25db1a8956706a25af238
diff --git a/third_party/re2/BUILD.gn b/third_party/re2/BUILD.gn
index 9d6e263..7dbbbc4 100644
--- a/third_party/re2/BUILD.gn
+++ b/third_party/re2/BUILD.gn
@@ -21,65 +21,67 @@
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_third_party/re2/re2.gni")
 
-config("re2_public_config1") {
-  include_dirs = [ "$dir_pw_third_party_re2" ]
-}
+if (dir_pw_third_party_re2 != "") {
+  config("re2_public_config1") {
+    include_dirs = [ "$dir_pw_third_party_re2" ]
+  }
 
-# Generated from //:re2
-pw_source_set("re2") {
-  public = [
-    "$dir_pw_third_party_re2/re2/filtered_re2.h",
-    "$dir_pw_third_party_re2/re2/re2.h",
-    "$dir_pw_third_party_re2/re2/set.h",
-    "$dir_pw_third_party_re2/re2/stringpiece.h",
-  ]
-  sources = [
-    "$dir_pw_third_party_re2/re2/bitmap256.cc",
-    "$dir_pw_third_party_re2/re2/bitmap256.h",
-    "$dir_pw_third_party_re2/re2/bitstate.cc",
-    "$dir_pw_third_party_re2/re2/compile.cc",
-    "$dir_pw_third_party_re2/re2/dfa.cc",
-    "$dir_pw_third_party_re2/re2/filtered_re2.cc",
-    "$dir_pw_third_party_re2/re2/mimics_pcre.cc",
-    "$dir_pw_third_party_re2/re2/nfa.cc",
-    "$dir_pw_third_party_re2/re2/onepass.cc",
-    "$dir_pw_third_party_re2/re2/parse.cc",
-    "$dir_pw_third_party_re2/re2/perl_groups.cc",
-    "$dir_pw_third_party_re2/re2/pod_array.h",
-    "$dir_pw_third_party_re2/re2/prefilter.cc",
-    "$dir_pw_third_party_re2/re2/prefilter.h",
-    "$dir_pw_third_party_re2/re2/prefilter_tree.cc",
-    "$dir_pw_third_party_re2/re2/prefilter_tree.h",
-    "$dir_pw_third_party_re2/re2/prog.cc",
-    "$dir_pw_third_party_re2/re2/prog.h",
-    "$dir_pw_third_party_re2/re2/re2.cc",
-    "$dir_pw_third_party_re2/re2/regexp.cc",
-    "$dir_pw_third_party_re2/re2/regexp.h",
-    "$dir_pw_third_party_re2/re2/set.cc",
-    "$dir_pw_third_party_re2/re2/simplify.cc",
-    "$dir_pw_third_party_re2/re2/sparse_array.h",
-    "$dir_pw_third_party_re2/re2/sparse_set.h",
-    "$dir_pw_third_party_re2/re2/stringpiece.cc",
-    "$dir_pw_third_party_re2/re2/tostring.cc",
-    "$dir_pw_third_party_re2/re2/unicode_casefold.cc",
-    "$dir_pw_third_party_re2/re2/unicode_casefold.h",
-    "$dir_pw_third_party_re2/re2/unicode_groups.cc",
-    "$dir_pw_third_party_re2/re2/unicode_groups.h",
-    "$dir_pw_third_party_re2/re2/walker-inl.h",
-    "$dir_pw_third_party_re2/util/logging.h",
-    "$dir_pw_third_party_re2/util/mix.h",
-    "$dir_pw_third_party_re2/util/mutex.h",
-    "$dir_pw_third_party_re2/util/rune.cc",
-    "$dir_pw_third_party_re2/util/strutil.cc",
-    "$dir_pw_third_party_re2/util/strutil.h",
-    "$dir_pw_third_party_re2/util/utf.h",
-    "$dir_pw_third_party_re2/util/util.h",
-  ]
-  cflags = [ "-pthread" ]
-  ldflags = [ "-pthread" ]
-  public_configs = [ ":re2_public_config1" ]
-  configs = [ "configs:internal_disabled_warnings" ]
-  remove_configs = [ "$dir_pw_fuzzer:instrumentation" ]
+  # Generated from //:re2
+  pw_source_set("re2") {
+    public = [
+      "$dir_pw_third_party_re2/re2/filtered_re2.h",
+      "$dir_pw_third_party_re2/re2/re2.h",
+      "$dir_pw_third_party_re2/re2/set.h",
+      "$dir_pw_third_party_re2/re2/stringpiece.h",
+    ]
+    sources = [
+      "$dir_pw_third_party_re2/re2/bitmap256.cc",
+      "$dir_pw_third_party_re2/re2/bitmap256.h",
+      "$dir_pw_third_party_re2/re2/bitstate.cc",
+      "$dir_pw_third_party_re2/re2/compile.cc",
+      "$dir_pw_third_party_re2/re2/dfa.cc",
+      "$dir_pw_third_party_re2/re2/filtered_re2.cc",
+      "$dir_pw_third_party_re2/re2/mimics_pcre.cc",
+      "$dir_pw_third_party_re2/re2/nfa.cc",
+      "$dir_pw_third_party_re2/re2/onepass.cc",
+      "$dir_pw_third_party_re2/re2/parse.cc",
+      "$dir_pw_third_party_re2/re2/perl_groups.cc",
+      "$dir_pw_third_party_re2/re2/pod_array.h",
+      "$dir_pw_third_party_re2/re2/prefilter.cc",
+      "$dir_pw_third_party_re2/re2/prefilter.h",
+      "$dir_pw_third_party_re2/re2/prefilter_tree.cc",
+      "$dir_pw_third_party_re2/re2/prefilter_tree.h",
+      "$dir_pw_third_party_re2/re2/prog.cc",
+      "$dir_pw_third_party_re2/re2/prog.h",
+      "$dir_pw_third_party_re2/re2/re2.cc",
+      "$dir_pw_third_party_re2/re2/regexp.cc",
+      "$dir_pw_third_party_re2/re2/regexp.h",
+      "$dir_pw_third_party_re2/re2/set.cc",
+      "$dir_pw_third_party_re2/re2/simplify.cc",
+      "$dir_pw_third_party_re2/re2/sparse_array.h",
+      "$dir_pw_third_party_re2/re2/sparse_set.h",
+      "$dir_pw_third_party_re2/re2/stringpiece.cc",
+      "$dir_pw_third_party_re2/re2/tostring.cc",
+      "$dir_pw_third_party_re2/re2/unicode_casefold.cc",
+      "$dir_pw_third_party_re2/re2/unicode_casefold.h",
+      "$dir_pw_third_party_re2/re2/unicode_groups.cc",
+      "$dir_pw_third_party_re2/re2/unicode_groups.h",
+      "$dir_pw_third_party_re2/re2/walker-inl.h",
+      "$dir_pw_third_party_re2/util/logging.h",
+      "$dir_pw_third_party_re2/util/mix.h",
+      "$dir_pw_third_party_re2/util/mutex.h",
+      "$dir_pw_third_party_re2/util/rune.cc",
+      "$dir_pw_third_party_re2/util/strutil.cc",
+      "$dir_pw_third_party_re2/util/strutil.h",
+      "$dir_pw_third_party_re2/util/utf.h",
+      "$dir_pw_third_party_re2/util/util.h",
+    ]
+    cflags = [ "-pthread" ]
+    ldflags = [ "-pthread" ]
+    public_configs = [ ":re2_public_config1" ]
+    configs = [ "configs:internal_disabled_warnings" ]
+    remove_configs = [ "$dir_pw_fuzzer:instrumentation" ]
+  }
 }
 
 pw_doc_group("docs") {
diff --git a/third_party/re2/docs.rst b/third_party/re2/docs.rst
index e974aa6..5f15b82 100644
--- a/third_party/re2/docs.rst
+++ b/third_party/re2/docs.rst
@@ -49,5 +49,6 @@
 
 Version
 =======
-The update script was last run for revision:
-11073deb73b3d01018308863c0bcdfd0d51d3e70
+The update script was last run for revision `c9cba76`_.
+
+.. _c9cba76: https://github.com/google/re2/tree/c9cba76063cf4235c1a15dd14a24a4ef8d623761