Add CMake integration to fuzztest

Closes #123, #135 and numerous requests

PiperOrigin-RevId: 521421500
diff --git a/.github/workflows/cmake_test.yml b/.github/workflows/cmake_test.yml
new file mode 100644
index 0000000..fbdba6b
--- /dev/null
+++ b/.github/workflows/cmake_test.yml
@@ -0,0 +1,65 @@
+# Copyright 2022 Google LLC
+#
+# 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
+#
+#      http://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.
+
+name: CMake Test
+
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+  workflow_dispatch:
+
+# TODO: Support caching.
+jobs:
+  run_tests:
+    name: Run tests
+    runs-on: ubuntu-latest
+    timeout-minutes: 30
+    strategy:
+      matrix:
+        config: ['default', 'fuzztest']
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v3
+      - name: Install dependencies
+        run: |
+          sudo apt-get update && sudo apt-get install -yq \
+            clang libprotobuf-dev protobuf-compiler ninja-build cmake
+      - name: Run end-to-end tests with FUZZTEST_UNIT
+        if: matrix.config == 'default'
+        run: |
+          mkdir build && \
+          cd build && \
+          CC=clang CXX=clang++ cmake -G Ninja \
+            -DCMAKE_BUILD_TYPE=RelWithDebug \
+            -DRE2_BUILD_TESTING=off \
+            -Dprotobuf_BUILD_TESTS=off \
+            -DFUZZTEST_TESTING=on .. && \
+            ninja -j $(nproc) && \
+            ctest -j $(nproc) --output-on-failure -E "benchmark_test"
+      - name: Run all tests with default config
+        if: matrix.config == 'fuzztest'
+        run: |
+          mkdir build && \
+          cd build && \
+          CC=clang CXX=clang++ cmake -G Ninja \
+            -DCMAKE_BUILD_TYPE=RelWithDebug \
+            -DRE2_BUILD_TESTING=off \
+            -Dprotobuf_BUILD_TESTS=off \
+            -DFUZZTEST_FUZZING_MODE=on \
+            -DFUZZTEST_TESTING=on .. && \
+            ninja -j $(nproc) && \
+            ctest -j $(nproc) --output-on-failure
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..2d948a7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,63 @@
+cmake_minimum_required(VERSION 3.16)
+project(fuzztest)
+
+option(FUZZTEST_TESTING "Building the tests." OFF)
+option(FUZZTEST_FUZZING_MODE "Building the fuzztest in fuzzing mode." OFF)
+option(FUZZTEST_USE_GTEST "Building the fuzztest with gtest." ON)
+set(FUZZTEST_COMPATIBILITY_MODE "" CACHE STRING "Compatibility mode. Available options: <empty>, libfuzzer")
+set(CMAKE_CXX_STANDARD 17)
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  set (COMPILER_GCC 1)
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
+  set (COMPILER_CLANG 1) # Safe to treat AppleClang as a regular Clang, in general.
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  set (COMPILER_CLANG 1)
+else ()
+  message (FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER_ID} is not supported")
+endif ()
+
+if (COMPILER_GCC AND (FUZZTEST_FUZZING_MODE OR (FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer")))
+  message (FATAL_ERROR "Compilation with GCC is not yet supported for fuzztest mode. Please use Clang. CC=clang CXX=clang++")
+endif ()
+
+if (FUZZTEST_FUZZING_MODE AND NOT FUZZTEST_COMPATIBILITY_MODE STREQUAL "")
+  message (FATAL_ERROR "Please either use fuzzing mode or compatibility mode")
+endif ()
+
+if (NOT FUZZTEST_COMPATIBILITY_MODE STREQUAL "" AND
+    NOT FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer")
+  message (FATAL_ERROR "Compatibility mode is only supported for libfuzzer")
+endif ()
+
+include(cmake/BuildDependencies.cmake)
+include(cmake/AddFuzzTest.cmake)
+include(cmake/FuzzTestFlagSetup.cmake)
+
+if (FUZZTEST_USE_GTEST OR FUZZTEST_TESTING)
+  add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
+endif ()
+
+include_directories(${re2_SOURCE_DIR})
+
+add_subdirectory(${abseil-cpp_SOURCE_DIR} ${abseil-cpp_BINARY_DIR})
+add_subdirectory(${re2_SOURCE_DIR} ${re2_BINARY_DIR})
+
+if (FUZZTEST_TESTING)
+  enable_testing()
+endif ()
+
+if (FUZZTEST_TESTING)
+  add_subdirectory(${protobuf_SOURCE_DIR} ${protobuf_BINARY_DIR})
+  set(protobuf_PROTOC_EXE "${protobuf_BINARY_DIR}/protoc")
+  include(${protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)
+endif ()
+
+fuzztest_setup_fuzzing_flags()
+
+add_subdirectory(fuzztest)
+
+if (FUZZTEST_TESTING)
+  add_subdirectory(domain_tests)
+  add_subdirectory(e2e_tests)
+endif ()
diff --git a/README.md b/README.md
index 2a74de7..474c7c4 100644
--- a/README.md
+++ b/README.md
@@ -57,9 +57,9 @@
 
 ## How do I use it?
 
-To get started, read the [Quickstart with Bazel](doc/quickstart-bazel.md),
-then take a look at the [Overview](doc/overview.md) and the
-[Codelab](doc/tutorial.md).
+To get started, read the [Quickstart with Bazel](doc/quickstart-bazel.md) or
+[Quickstart with CMake](doc/quickstart-cmake.md), then take a look at the
+[Overview](doc/overview.md) and the [Codelab](doc/tutorial.md).
 
 Once you have a high level understanding about fuzz tests, consider reading the
 rest of the documentation, including the:
diff --git a/cmake/AddFuzzTest.cmake b/cmake/AddFuzzTest.cmake
new file mode 100644
index 0000000..f0d3e58
--- /dev/null
+++ b/cmake/AddFuzzTest.cmake
@@ -0,0 +1,14 @@
+function(link_fuzztest name)
+  target_link_libraries(${name} PRIVATE fuzztest_gtest_main)
+  if (FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer")
+    EXECUTE_PROCESS (
+        COMMAND bash -c "command -v llvm-config || command -v llvm-config-16 || command -v llvm-config-15 || command -v llvm-config-14 || command -v llvm-config-13 || command -v llvm-config-12 || echo"
+        OUTPUT_VARIABLE LLVM_CONFIG OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+    EXECUTE_PROCESS(
+      COMMAND bash -c "find $(${LLVM_CONFIG} --libdir) -name libclang_rt.fuzzer_no_main-x86_64.a | head -1"
+      OUTPUT_VARIABLE FUZZER_NO_MAIN OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+    target_link_libraries(${name} PRIVATE ${FUZZER_NO_MAIN})
+  endif ()
+endfunction()
diff --git a/cmake/BuildDependencies.cmake b/cmake/BuildDependencies.cmake
new file mode 100644
index 0000000..eb1b81f
--- /dev/null
+++ b/cmake/BuildDependencies.cmake
@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 3.16)
+
+include(FetchContent)
+
+set(gtest_URL https://github.com/google/googletest.git)
+set(gtest_TAG release-1.12.1)
+
+set(absl_URL https://github.com/abseil/abseil-cpp.git)
+set(absl_COMMIT dbc61b490c5c259df33af59f9922a7224341397b)
+
+set(re2_URL https://github.com/google/re2.git)
+set(re2_TAG 2023-03-01)
+
+set(proto_URL https://github.com/protocolbuffers/protobuf.git)
+set(proto_TAG v22.2)
+
+if (FUZZTEST_USE_GTEST OR FUZZTEST_TESTING)
+  FetchContent_Declare(
+    googletest
+    GIT_REPOSITORY ${gtest_URL}
+    GIT_TAG        ${gtest_TAG}
+  )
+endif ()
+
+FetchContent_Declare(
+  abseil-cpp
+  GIT_REPOSITORY ${absl_URL}
+  GIT_TAG        ${absl_COMMIT}
+)
+
+FetchContent_Declare(
+  re2
+  GIT_REPOSITORY ${re2_URL}
+  GIT_TAG        ${re2_TAG}
+)
+
+if (FUZZTEST_TESTING)
+  FetchContent_Declare(
+    protobuf
+    GIT_REPOSITORY ${proto_URL}
+    GIT_TAG        ${proto_TAG}
+  )
+endif ()
+
+FetchContent_Populate(abseil-cpp)
+set(ABSL_PROPAGATE_CXX_STD ON)
+set(ABSL_ENABLE_INSTALL ON)
+FetchContent_Populate(re2)
+set(RE2_TESTING OFF)
+FetchContent_Populate(googletest)
+
+if (FUZZTEST_TESTING)
+  FetchContent_Populate(protobuf)
+endif ()
diff --git a/cmake/FuzzTestFlagSetup.cmake b/cmake/FuzzTestFlagSetup.cmake
new file mode 100644
index 0000000..95f744a
--- /dev/null
+++ b/cmake/FuzzTestFlagSetup.cmake
@@ -0,0 +1,15 @@
+macro(fuzztest_setup_fuzzing_flags)
+  if (FUZZTEST_FUZZING_MODE OR (FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer"))
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -UNDEBUG -fsanitize=address")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -UNDEBUG -fsanitize=address")
+    SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
+  endif ()
+  if (FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer")
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer-no-link -DFUZZTEST_COMPATIBILITY_MODE")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link -DFUZZTEST_COMPATIBILITY_MODE")
+  endif ()
+  if (FUZZTEST_FUZZING_MODE OR (FUZZTEST_COMPATIBILITY_MODE STREQUAL "libfuzzer"))
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-coverage=inline-8bit-counters -fsanitize-coverage=trace-cmp -fsanitize=address -DADDRESS_SANITIZER")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-coverage=inline-8bit-counters -fsanitize-coverage=trace-cmp -fsanitize=address -DADDRESS_SANITIZER")
+  endif ()
+endmacro ()
diff --git a/codelab/CMakeLists.txt b/codelab/CMakeLists.txt
new file mode 100644
index 0000000..134f68e
--- /dev/null
+++ b/codelab/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.16)
+project(escaping_test)
+set(CMAKE_CXX_STANDARD 17)
+
+# Remove ../../ in real examples.
+add_subdirectory(../../fuzztest fuzztest)
+
+enable_testing()
+include(GoogleTest)
+
+fuzztest_setup_fuzzing_flags()
+
+add_library(escaping
+  OBJECT
+  escaping.cc
+  escaping.h
+)
+
+add_executable(
+  escaping_test
+  escaping_test.cc
+)
+
+target_link_libraries(
+  escaping_test
+  PRIVATE
+  escaping
+)
+
+link_fuzztest(escaping_test)
+gtest_discover_tests(escaping_test)
+
diff --git a/doc/quickstart-cmake.md b/doc/quickstart-cmake.md
new file mode 100644
index 0000000..ac62b5b
--- /dev/null
+++ b/doc/quickstart-cmake.md
@@ -0,0 +1,250 @@
+# Quickstart with CMake
+
+This tutorial describes how to set up your development environment with CMake as
+the build system, and how to get a simple fuzz test up and running. We recommend
+this tutorial if you're new to FuzzTest or if you need a quick refresher.
+
+## Definitions
+
+The library can work in several different modes.
+
+*   Unit test mode (*default*): FUZZ_TESTs are built without coverage
+    instrumentation and run with random inputs for short period of time along
+    with regular unit TESTs.
+*   Fuzzing mode (controlled by `-DFUZZTEST_FUZZING_MODE=on`): FUZZ_TESTs are
+    built with coverage instrumentation and run individually and indefinitely or
+    for specified amount of time.
+*   Compatibility mode (controlled by `-DFUZZTEST_COMPATIBILITY_MODE=libfuzzer`): like Fuzzing mode, but an
+    external engine is used instead FuzzTest's built in engine. Currently
+    [libFuzzer](https://llvm.org/docs/LibFuzzer.html) is supported.
+
+## Overall rules
+
+We provide a default CMake option for unittest mode, the instructions are
+straightforward and work like
+[googletest](https://google.github.io/googletest/quickstart-cmake.html).
+
+To run in a fuzztest mode, you need to make sure all targets are compiled in a
+special way.
+
+*   `-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -UNDEBUG`
+*   `-fsanitize-coverage=inline-8bit-counters -fsanitize-coverage=trace-cmp`
+*   `-fsanitize=address -DADDRESS_SANITIZER` (optionally enabling sanitizer)
+
+The FuzzTest framework doesn't need to be built with these flags, only the target project.
+
+For all projects to have correct flags set, use a CMake macro
+`fuzztest_setup_fuzzing_flags()`.
+
+For a concrete example, see the root CMakeLists.txt. First, we build framework
+without additional flags and then build the rest of translation units with
+coverage flags. Otherwise we might get into recursive issues, i.e. fuzztest
+framework will be fuzzing itself.
+
+Easiest way to make sure you build everything correctly is to invoke
+`add_subdirectory` first in your project on fuzztest.
+
+## Prerequisites
+
+To use FuzzTest, you'll need:
+
+*   A Linux-based operating system.
+*   [Clang](https://clang.llvm.org/). GCC is not yet supported. Unittest mode
+    mode should work but it's not yet tested.
+*   [CMake](https://https://cmake.org/).
+
+## Set up a CMake workspace
+
+First, create a directory where your project will reside:
+
+```sh
+$ mkdir first_fuzz_project && cd first_fuzz_project
+$ git clone https://github.com/google/fuzztest.git
+```
+
+Create a `CMakeLists.txt`.
+
+```
+cmake_minimum_required(VERSION 3.14)
+project(first_fuzz_project)
+
+# GoogleTest requires at least C++17
+set(CMAKE_CXX_STANDARD 17)
+
+add_subdirectory(fuzztest)
+```
+
+FuzzTest CMake already handles its dependencies on its own:
+[RE2](https://github.com/google/re2),
+[Abseil](https://github.com/abseil/abseil-cpp). We highly recommend using
+[GoogleTest](https://github.com/google/googletest) as well.
+
+## Create and run a fuzz test
+
+With the CMake workspace set up, you can start using FuzzTest. Let's create a
+trivial example to make sure everything runs correctly.
+
+Create a file named `first_fuzz_test.cc` in the directory `first_fuzz` with the
+following contents:
+
+```c++
+#include "fuzztest/fuzztest.h"
+#include "gtest/gtest.h"
+
+TEST(MyTestSuite, OnePlustTwoIsTwoPlusOne) {
+  EXPECT_EQ(1 + 2, 2 + 1);
+}
+
+void IntegerAdditionCommutes(int a, int b) {
+  EXPECT_EQ(a + b, b + a);
+}
+FUZZ_TEST(MyTestSuite, IntegerAdditionCommutes);
+```
+
+The file contains two tests in the test suite named `MyTestSuite`. The first one
+is a unit test named `OnePlustTwoIsTwoPlusOne` asserting that integer addition
+commutes for two specific values.
+
+The second test is a fuzz test that captures the commutative property of integer
+addition more generally. The test consists of a property function with a
+suggestive name `IntegerAdditionCommutes`, and the test registration using the
+macro `FUZZ_TEST`. The property function asserts the commutative property for
+two generic integer parameters.
+
+To build and run the tests, **add** to the file `CMakeLists.txt` the following
+content:
+
+```cmake
+
+...
+
+enable_testing()
+
+include(GoogleTest)
+
+add_executable(
+  first_fuzz_test
+  first_fuzz_test.cc
+)
+
+# If you have other dependencies than FuzzTest, link them:
+# target_link_libraries(first_fuzz_test PRIVATE other_deps)
+
+link_fuzztest(first_fuzz_test)
+gtest_discover_tests(first_fuzz_test)
+```
+
+This defines a C++ test binary and links it with the FuzzTest and GoogleTest
+libraries, as well as the version of the default GoogleTest main that supports
+FuzzTest.
+
+### Unit test mode
+
+There are several ways to run the tests: in the unit test mode and in the
+fuzzing mode (see above). The unit test mode runs both test for a short time
+without sanitizer and coverage instrumentation:
+
+```
+$ mkdir build && cd build
+$ CC=clang CXX=clang++ cmake \
+  -DCMAKE_BUILD_TYPE=RelWithDebug ..
+$ cmake --build .
+$ ./first_fuzz_test
+
+[==========] Running 2 tests from 1 test suite.
+[----------] Global test environment set-up.
+[----------] 2 tests from MyTestSuite
+[ RUN      ] MyTestSuite.OnePlustTwoIsTwoPlusOne
+[       OK ] MyTestSuite.OnePlustTwoIsTwoPlusOne (0 ms)
+[ RUN      ] MyTestSuite.IntegerAdditionCommutes
+[       OK ] MyTestSuite.IntegerAdditionCommutes (13 ms)
+[----------] 2 tests from MyTestSuite (13 ms total)
+
+[----------] Global test environment tear-down
+[==========] 2 tests from 1 test suite ran. (13 ms total)
+[  PASSED  ] 2 tests.
+```
+
+### Fuzzing mode
+
+The fuzzing mode runs a single specified fuzz test with sanitizer and coverage
+instrumentation. It keeps running the test with different input values until it
+finds a crash or it is explicitly terminated by the user.
+
+Before `add_executable(first_fuzz_test ...)`, add the specified flags:
+
+```cmake
+fuzztest_setup_fuzzing_flags()
+```
+
+Then run:
+
+```
+$ CC=clang CXX=clang++ cmake \
+  -DCMAKE_BUILD_TYPE=RelWithDebug \
+  -DFUZZTEST_FUZZING_MODE=on ..
+$ cmake --build .
+$ ./first_fuzz_test --fuzz=MyTestSuite.IntegerAdditionCommutes
+
+[.] Sanitizer coverage enabled. Counter map size: 21290, Cmp map size: 262144
+Note: Google Test filter = MyTestSuite.IntegerAdditionCommutes
+[==========] Running 1 test from 1 test suite.
+[----------] Global test environment set-up.
+[----------] 1 test from MyTestSuite
+[ RUN      ] MyTestSuite.IntegerAdditionCommutes
+[*] Corpus size:     1 | Edges covered:    131 | Fuzzing time:    504.798us | Total runs:  1.00e+00 | Runs/secs:     1
+[*] Corpus size:     2 | Edges covered:    133 | Fuzzing time:    934.176us | Total runs:  3.00e+00 | Runs/secs:     3
+[*] Corpus size:     3 | Edges covered:    134 | Fuzzing time:   2.384383ms | Total runs:  5.30e+01 | Runs/secs:    53
+[*] Corpus size:     4 | Edges covered:    137 | Fuzzing time:   2.732274ms | Total runs:  5.40e+01 | Runs/secs:    54
+[*] Corpus size:     5 | Edges covered:    137 | Fuzzing time:   7.275553ms | Total runs:  2.48e+02 | Runs/secs:   248
+[*] Corpus size:     6 | Edges covered:    137 | Fuzzing time:   21.97155ms | Total runs:  9.12e+02 | Runs/secs:   912
+[*] Corpus size:     7 | Edges covered:    137 | Fuzzing time: 166.721522ms | Total runs:  8.49e+03 | Runs/secs:  8491
+[*] Corpus size:     8 | Edges covered:    146 | Fuzzing time: 500.398497ms | Total runs:  2.77e+04 | Runs/secs: 27741
+[*] Corpus size:     9 | Edges covered:    146 | Fuzzing time: 500.821386ms | Total runs:  2.77e+04 | Runs/secs: 27742
+[*] Corpus size:    10 | Edges covered:    147 | Fuzzing time: 2.597553524s | Total runs:  1.75e+05 | Runs/secs: 87476
+^C
+```
+
+Congratulations! You're now all set for fuzzing with FuzzTest.
+
+## ### Compatibility mode
+
+Linking FuzzTest using `link_fuzztest()` enables linking with external fuzzing engines, when built with `-DFUZZTEST_COMPATIBILITY_MODE`.
+
+```
+$ CC=clang CXX=clang++ cmake \
+  -DCMAKE_BUILD_TYPE=RelWithDebug \
+  -DFUZZTEST_COMPATIBILITY_MODE=libfuzzer ..
+$ cmake --build .
+$ ./first_fuzz_test --fuzz=MyTestSuite.IntegerAdditionCommutes
+
+Note: Google Test filter = MyTestSuite.IntegerAdditionCommutes
+[==========] Running 1 test from 1 test suite.
+[----------] Global test environment set-up.
+[----------] 1 test from MyTestSuite
+[ RUN      ] MyTestSuite.IntegerAdditionCommutes
+FUZZTEST_PRNG_SEED=OffQXb8u5_vZtH4-7wgVOLu_HNAhPIbLz7CFF13u3nk
+INFO: found LLVMFuzzerCustomMutator (0x55edfe61cac0). Disabling -len_control by default.
+INFO: libFuzzer ignores flags that start with '--'
+INFO: Running with entropic power schedule (0xFF, 100).
+INFO: Seed: 1109364873
+INFO: Loaded 1 modules   (18692 inline 8-bit counters): 18692 [0x55edfe975548, 0x55edfe979e4c), 
+INFO: Loaded 1 PC tables (18692 PCs): 18692 [0x55edfe979e50,0x55edfe9c2e90), 
+INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
+INFO: A corpus is not provided, starting from an empty corpus
+#2	INITED cov: 17 ft: 18 corp: 1/1b exec/s: 0 rss: 38Mb
+#3	NEW    cov: 104 ft: 108 corp: 2/66b lim: 4096 exec/s: 0 rss: 38Mb L: 65/65 MS: 1 Custom-
+#4	NEW    cov: 105 ft: 112 corp: 3/121b lim: 4096 exec/s: 0 rss: 38Mb L: 55/65 MS: 1 Custom-
+#5	NEW    cov: 105 ft: 113 corp: 4/196b lim: 4096 exec/s: 0 rss: 38Mb L: 75/75 MS: 1 Custom-
+#16	REDUCE cov: 105 ft: 113 corp: 4/195b lim: 4096 exec/s: 0 rss: 38Mb L: 54/75 MS: 1 Custom-
+#41	NEW    cov: 105 ft: 114 corp: 5/247b lim: 4096 exec/s: 0 rss: 38Mb L: 52/75 MS: 5 Custom-Custom-Custom-Custom-Custom-
+#65	NEW    cov: 106 ft: 115 corp: 6/312b lim: 4096 exec/s: 0 rss: 38Mb L: 65/75 MS: 4 Custom-Custom-Custom-Custom-
+#69	NEW    cov: 108 ft: 119 corp: 7/365b lim: 4096 exec/s: 0 rss: 38Mb L: 53/75 MS: 4 Custom-Custom-Custom-Custom-
+```
+
+## Next steps
+
+*   This tutorial covered the basic setup of the build environment with CMake.
+    To learn more about the FuzzTest framework and how to use it, check out the
+    [Codelab](tutorial.md).
+*   Explore the rest of the [documentation](./).
diff --git a/domain_tests/CMakeLists.txt b/domain_tests/CMakeLists.txt
new file mode 100644
index 0000000..ac4b76d
--- /dev/null
+++ b/domain_tests/CMakeLists.txt
@@ -0,0 +1,290 @@
+get_filename_component(PARENT_DIR ../ ABSOLUTE)
+include_directories(${PARENT_DIR})
+
+include_directories(${CMAKE_BINARY_DIR})
+add_library(
+  fuzztest_domain_testing
+  OBJECT
+  domain_testing.h
+)
+set_target_properties(
+  fuzztest_domain_testing
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+)
+target_link_libraries(
+  fuzztest_domain_testing
+  PUBLIC
+  absl::hash
+  absl::status
+  absl::strings
+  absl::flat_hash_set
+  absl::random_random
+  fuzztest_meta
+  fuzztest_serialization
+  test_protobuf
+  fuzztest_logging
+  fuzztest_type_support
+  protobuf::libprotobuf
+  GTest::gmock
+)
+
+add_executable(
+  fuzztest_aggregate_combinators_test
+  aggregate_combinators_test.cc
+)
+target_link_libraries(
+  fuzztest_aggregate_combinators_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::random_random
+  absl::optional
+  absl::variant
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_aggregate_combinators_test
+  COMMAND
+  fuzztest_aggregate_combinators_test
+)
+
+add_executable(
+  fuzztest_arbitrary_domains_test
+  arbitrary_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_arbitrary_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  protobuf::libprotobuf
+  test_protobuf
+  absl::flat_hash_map
+  absl::flat_hash_set
+  absl::random_random
+  absl::random_bit_gen_ref
+  absl::time
+  absl::status
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_arbitrary_domains_test
+  COMMAND
+  fuzztest_arbitrary_domains_test
+)
+
+add_executable(
+  fuzztest_container_combinators_test
+  container_combinators_test.cc
+)
+target_link_libraries(
+  fuzztest_container_combinators_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::flat_hash_map
+  absl::flat_hash_set
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_container_combinators_test
+  COMMAND
+  fuzztest_container_combinators_test
+)
+
+add_executable(
+  fuzztest_in_regexp_domain_test
+  in_regexp_domain_test.cc
+)
+target_link_libraries(
+  fuzztest_in_regexp_domain_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::flat_hash_set
+  absl::random_random
+  re2
+  fuzztest_regexp_dfa
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_in_regexp_domain_test
+  COMMAND
+  fuzztest_in_regexp_domain_test
+)
+
+add_executable(
+  fuzztest_map_filter_combinator_test
+  map_filter_combinator_test.cc
+)
+target_link_libraries(
+  fuzztest_map_filter_combinator_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_map_filter_combinator_test
+  COMMAND
+  fuzztest_map_filter_combinator_test
+)
+
+add_executable(
+  fuzztest_misc_domains_test
+  misc_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_misc_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_meta
+  fuzztest_serialization
+  fuzztest_logging
+  absl::flat_hash_set
+  absl::int128
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_misc_domains_test
+  COMMAND
+  fuzztest_misc_domains_test
+)
+
+add_executable(
+  fuzztest_numeric_domains_test
+  numeric_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_numeric_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::strings
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_numeric_domains_test
+  COMMAND
+  fuzztest_numeric_domains_test
+)
+
+add_executable(
+  fuzztest_pointer_domains_test
+  pointer_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_pointer_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_pointer_domains_test
+  COMMAND
+  fuzztest_pointer_domains_test
+)
+
+add_executable(
+  fuzztest_recursive_domains_test
+  recursive_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_recursive_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_recursive_domains_test
+  COMMAND
+  fuzztest_recursive_domains_test
+)
+
+add_executable(
+  fuzztest_string_domains_test
+  string_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_string_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::flat_hash_set
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_string_domains_test
+  COMMAND
+  fuzztest_string_domains_test
+)
+
+add_executable(
+  fuzztest_specific_value_domains_test
+  specific_value_domains_test.cc
+)
+target_link_libraries(
+  fuzztest_specific_value_domains_test
+  PUBLIC
+  fuzztest_domain_testing
+  fuzztest_coverage
+  fuzztest_type_support
+  fuzztest_serialization
+  fuzztest_logging
+  absl::flat_hash_set
+  absl::random_random
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  fuzztest_specific_value_domains_test
+  COMMAND
+  fuzztest_specific_value_domains_test
+)
diff --git a/e2e_tests/CMakeLists.txt b/e2e_tests/CMakeLists.txt
new file mode 100644
index 0000000..d749651
--- /dev/null
+++ b/e2e_tests/CMakeLists.txt
@@ -0,0 +1,67 @@
+get_filename_component(PARENT_DIR ../ ABSOLUTE)
+include_directories(${PARENT_DIR})
+
+add_subdirectory(testdata)
+
+add_executable(
+  functional_test
+  functional_test.cc
+)
+target_link_libraries(
+  functional_test
+  PUBLIC
+  fuzztest_io
+  fuzztest_logging
+  fuzztest_serialization
+  fuzztest_subprocess
+  fuzztest_type_support
+  re2
+  absl::flat_hash_map
+  absl::strings
+  absl::str_format
+  absl::time
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  functional_test
+  COMMAND
+  functional_test --test_srcdir="${CMAKE_BINARY_DIR}"
+)
+set_property(
+  TEST
+  functional_test
+  PROPERTY ENVIRONMENT
+  "TEST_SRCDIR=${CMAKE_BINARY_DIR}"
+)
+
+add_executable(
+  benchmark_test
+  benchmark_test.cc
+)
+target_link_libraries(
+  benchmark_test
+  PUBLIC
+  fuzztest_logging
+  fuzztest_subprocess
+  re2
+  absl::flat_hash_map
+  absl::flags
+  absl::flags_parse
+  absl::strings
+  absl::str_format
+  absl::time
+  GTest::gmock_main
+)
+add_test(
+  NAME
+  benchmark_test
+  COMMAND
+  benchmark_test
+)
+set_property(
+  TEST
+  benchmark_test
+  PROPERTY ENVIRONMENT
+  "TEST_SRCDIR=${CMAKE_BINARY_DIR}"
+)
diff --git a/e2e_tests/benchmark_test.cc b/e2e_tests/benchmark_test.cc
index ab16d40..863794b 100644
--- a/e2e_tests/benchmark_test.cc
+++ b/e2e_tests/benchmark_test.cc
@@ -74,7 +74,7 @@
 
 uint64_t ExtractTime(absl::string_view output) {
   static constexpr LazyRE2 kElapsedTimeRE = {"\nElapsed time: (.+)\n"};
-  absl::string_view duration_str;
+  std::string duration_str;
   FUZZTEST_INTERNAL_CHECK(
       RE2::PartialMatch(output, *kElapsedTimeRE, &duration_str),
       "\n\nCould not find:\n\nElapsed time:\n\nin:\n\n", output);
@@ -166,6 +166,8 @@
   auto [status, std_out, std_err] = fuzztest::internal::RunCommand(
       command_line,
       /*environment=*/{}, absl::Seconds(kTimeOutSecs));
+  // Overread tests under asan might not produce any stat.
+  if (absl::StrContains(name, "Overread")) return {};
   return ParseStats(std_err);
 }
 
diff --git a/e2e_tests/testdata/CMakeLists.txt b/e2e_tests/testdata/CMakeLists.txt
new file mode 100644
index 0000000..8d6442a
--- /dev/null
+++ b/e2e_tests/testdata/CMakeLists.txt
@@ -0,0 +1,48 @@
+get_filename_component(PARENT_DIR ../ ABSOLUTE)
+include_directories(${PARENT_DIR})
+
+include_directories(${CMAKE_BINARY_DIR})
+add_executable(
+  fuzz_tests_for_microbenchmarking
+  fuzz_tests_for_microbenchmarking.cc
+)
+target_link_libraries(
+  fuzz_tests_for_microbenchmarking
+  PUBLIC
+  protobuf::libprotobuf
+  test_protobuf
+)
+link_fuzztest(fuzz_tests_for_microbenchmarking)
+
+add_executable(
+  fuzz_tests_for_functional_testing.stripped
+  fuzz_tests_for_functional_testing.cc
+  fuzz_tests_for_microbenchmarking.cc
+  fuzz_tests_using_googletest.cc
+)
+target_link_libraries(
+  fuzz_tests_for_functional_testing.stripped
+  PUBLIC
+  protobuf::libprotobuf
+  test_protobuf
+  absl::function_ref
+  absl::time
+  fuzztest_googletest_fixture_adapter
+)
+link_fuzztest(fuzz_tests_for_functional_testing.stripped)
+set_target_properties(
+  fuzz_tests_for_functional_testing.stripped
+  PROPERTIES RUNTIME_OUTPUT_DIRECTORY
+  "${CMAKE_BINARY_DIR}/com_google_fuzztest/e2e_tests/testdata"
+)
+
+add_executable(
+  fuzz_tests_with_invalid_seeds.stripped
+  fuzz_tests_with_invalid_seeds.cc
+)
+link_fuzztest(fuzz_tests_with_invalid_seeds.stripped)
+set_target_properties(
+  fuzz_tests_with_invalid_seeds.stripped
+  PROPERTIES RUNTIME_OUTPUT_DIRECTORY
+  "${CMAKE_BINARY_DIR}/com_google_fuzztest/e2e_tests/testdata"
+)
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index b0e484d..7bd5dc7 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -142,7 +142,6 @@
         "@com_google_absl//absl/base:core_headers",
         "@com_google_absl//absl/container:flat_hash_map",
         "@com_google_absl//absl/container:flat_hash_set",
-        "@com_google_absl//absl/log:die_if_null",
         "@com_google_absl//absl/numeric:bits",
         "@com_google_absl//absl/numeric:int128",
         "@com_google_absl//absl/random",
diff --git a/fuzztest/CMakeLists.txt b/fuzztest/CMakeLists.txt
new file mode 100644
index 0000000..366e99c
--- /dev/null
+++ b/fuzztest/CMakeLists.txt
@@ -0,0 +1,670 @@
+get_filename_component(PARENT_DIR ../ ABSOLUTE)
+include_directories(${PARENT_DIR})
+
+if (FUZZTEST_TESTING)
+  include_directories(${PROTOBUF_INCLUDE_DIR})
+  add_library(
+    test_protobuf
+    OBJECT
+    "${CMAKE_CURRENT_LIST_DIR}/internal/test_protobuf.proto"
+  )
+  target_link_libraries(
+    test_protobuf
+    PUBLIC
+    protobuf::libprotobuf
+  )
+  protobuf_generate(
+    TARGET
+    test_protobuf
+    IMPORT_DIRS
+    ${CMAKE_CURRENT_LIST_DIR}/internal
+    PROTOC_OUT_DIR
+    ${CMAKE_CURRENT_BINARY_DIR}/internal
+  )
+  include_directories("${CMAKE_BINARY_DIR}")
+endif ()
+
+# TODO: introduce similar functions to absl_cc_library and absl_cc_test to ease
+# the automation of synchronization.
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize=address,undefined -fsanitize-coverage=0")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=address,undefined -fsanitize-coverage=0")
+
+add_library(
+  fuzztest_logging
+  OBJECT
+  internal/logging.cc
+  internal/logging.h
+)
+
+target_link_libraries(
+  fuzztest_logging
+  PUBLIC
+  absl::strings
+)
+
+add_library(
+  fuzztest_meta
+  OBJECT
+  internal/meta.h
+)
+
+set_target_properties(
+  fuzztest_meta
+  PROPERTIES
+  LINKER_LANGUAGE
+  CXX
+)
+target_link_libraries(
+  fuzztest_meta
+  PUBLIC
+  absl::int128
+)
+
+add_library(
+  fuzztest_any
+  OBJECT
+  internal/any.h
+)
+set_target_properties(
+  fuzztest_any
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+)
+target_link_libraries(
+  fuzztest_any
+  PUBLIC
+  fuzztest_meta
+  fuzztest_logging
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_any_test
+    internal/any_test.cc
+  )
+  target_link_libraries(fuzztest_any_test PUBLIC
+    fuzztest_any
+    fuzztest_logging
+    absl::strings
+    GTest::gtest_main
+  )
+  add_test(
+    NAME
+    fuzztest_any_test
+    COMMAND
+    fuzztest_any_test
+  )
+endif()
+
+add_library(
+  fuzztest_type_support
+  OBJECT
+  internal/type_support.cc
+  internal/type_support.h
+)
+
+target_link_libraries(
+  fuzztest_type_support
+  PUBLIC
+  fuzztest_meta
+  absl::symbolize
+  absl::strings
+  absl::str_format
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_type_support_test
+    internal/type_support_test.cc
+  )
+  target_link_libraries(
+    fuzztest_type_support_test
+    PUBLIC
+    fuzztest_domain
+    fuzztest_fixture_driver
+    fuzztest_registration
+    fuzztest_logging
+    fuzztest_coverage
+    fuzztest_type_support
+    protobuf::libprotobuf
+    test_protobuf
+    absl::span
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_type_support_test
+    COMMAND
+    fuzztest_type_support_test
+  )
+endif()
+
+add_library(
+  fuzztest_table_of_recent_compares
+  OBJECT
+  internal/table_of_recent_compares.h
+)
+
+set_target_properties(
+  fuzztest_table_of_recent_compares
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+)
+target_link_libraries(
+  fuzztest_table_of_recent_compares
+  PUBLIC
+  fuzztest_type_support
+  absl::flat_hash_set
+  absl::random_distributions
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_table_of_recent_compares_test
+    internal/table_of_recent_compares_test.cc
+  )
+  target_link_libraries(
+    fuzztest_table_of_recent_compares_test
+    PUBLIC
+    fuzztest_domain
+    absl::random_random
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_table_of_recent_compares_test
+    COMMAND
+    fuzztest_table_of_recent_compares_test
+  )
+endif()
+
+add_library(
+  fuzztest_regexp_dfa
+  OBJECT
+  internal/domains/regexp_dfa.cc
+  internal/domains/regexp_dfa.h
+)
+
+target_link_libraries(
+  fuzztest_regexp_dfa
+  PUBLIC
+  fuzztest_logging
+  absl::flat_hash_map
+  absl::random_distributions
+  re2::re2
+)
+
+add_library(
+  fuzztest_io
+  OBJECT
+  internal/io.cc
+  internal/io.h
+)
+
+target_link_libraries(
+  fuzztest_io
+  PUBLIC
+  fuzztest_logging
+  absl::hash
+  absl::str_format
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_io_test
+    internal/io_test.cc
+  )
+  target_link_libraries(
+    fuzztest_io_test
+    PUBLIC
+    fuzztest_io
+    fuzztest_fuzztest
+    fuzztest_registry
+    fuzztest_logging
+    absl::strings
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_io_test
+    COMMAND
+    fuzztest_io_test
+  )
+endif()
+
+add_library(
+  fuzztest_coverage
+  OBJECT
+  internal/coverage.cc
+  internal/coverage.h
+)
+
+target_link_libraries(
+  fuzztest_coverage
+  PUBLIC
+  fuzztest_logging
+  fuzztest_table_of_recent_compares
+  absl::base
+  absl::span
+)
+
+add_library(
+  fuzztest_registration
+  OBJECT
+  internal/registration.h
+)
+set_target_properties(
+  fuzztest_registration
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+)
+target_link_libraries(
+  fuzztest_registration
+  PUBLIC
+  fuzztest_domain
+  fuzztest_meta
+  fuzztest_type_support
+  absl::str_format
+  absl::span
+)
+
+add_library(
+  fuzztest_fixture_driver
+  OBJECT
+  internal/fixture_driver.h
+  internal/fixture_driver.cc
+)
+
+target_link_libraries(
+  fuzztest_fixture_driver
+  PUBLIC
+  fuzztest_logging
+  fuzztest_registration
+  fuzztest_type_support
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_fixture_driver_test
+    internal/fixture_driver_test.cc
+  )
+  target_link_libraries(
+    fuzztest_fixture_driver_test
+    PUBLIC
+    fuzztest_domain
+    fuzztest_fixture_driver
+    fuzztest_registration
+    fuzztest_logging
+    fuzztest_coverage
+    fuzztest_type_support
+    absl::span
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_fixture_driver_test
+    COMMAND
+    fuzztest_fixture_driver_test
+  )
+endif()
+
+add_library(
+  fuzztest_serialization
+  OBJECT
+  internal/serialization.cc
+  internal/serialization.h
+)
+
+target_link_libraries(
+  fuzztest_serialization
+  PUBLIC
+  fuzztest_meta
+  absl::int128
+  absl::strings
+  absl::str_format
+  absl::span
+  absl::variant
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_serialization_test
+    internal/serialization_test.cc
+  )
+  target_link_libraries(
+    fuzztest_serialization_test
+    PUBLIC
+    fuzztest_logging
+    fuzztest_domain
+    fuzztest_coverage
+    fuzztest_seed_seq
+    fuzztest_fixture_driver
+    fuzztest_serialization
+    fuzztest_io
+    fuzztest_type_support
+    protobuf::libprotobuf
+    fuzztest_runtime
+    absl::time
+    test_protobuf
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_serialization_test
+    COMMAND
+    fuzztest_serialization_test
+  )
+endif ()
+
+add_library(
+  fuzztest_subprocess
+  OBJECT
+  internal/subprocess.cc
+  internal/subprocess.h
+)
+
+target_link_libraries(
+  fuzztest_subprocess
+  PUBLIC
+  fuzztest_logging
+  absl::flat_hash_map
+  absl::strings
+  absl::time
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_subprocess_test
+    internal/subprocess_test.cc
+  )
+  target_link_libraries(
+    fuzztest_subprocess_test
+    PUBLIC
+    fuzztest_logging
+    fuzztest_subprocess
+    absl::time
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_subprocess_test
+    COMMAND
+    fuzztest_subprocess_test
+  )
+endif ()
+
+add_library(
+  fuzztest_domain
+  OBJECT
+  internal/domains/in_grammar_impl.cc
+  domain.h
+  internal/domains/aggregate_of_impl.h
+  internal/domains/arbitrary_impl.h
+  internal/domains/bit_flag_combination_of_impl.h
+  internal/domains/container_mutation_helpers.h
+  internal/domains/container_of_impl.h
+  internal/domains/domain_base.h
+  internal/domains/element_of_impl.h
+  internal/domains/filter_impl.h
+  internal/domains/flat_map_impl.h
+  internal/domains/in_grammar_impl.h
+  internal/domains/in_range_impl.h
+  internal/domains/in_regexp_impl.h
+  internal/domains/map_impl.h
+  internal/domains/one_of_impl.h
+  internal/domains/optional_of_impl.h
+  internal/domains/protobuf_domain_impl.h
+  internal/domains/serialization_helpers.h
+  internal/domains/smart_pointer_of_impl.h
+  internal/domains/unique_elements_container_of_impl.h
+  internal/domains/value_mutation_helpers.h
+  internal/domains/variant_of_impl.h
+)
+
+target_link_libraries(
+  fuzztest_domain
+  PUBLIC
+  fuzztest_coverage
+  fuzztest_logging
+  fuzztest_meta
+  fuzztest_regexp_dfa
+  fuzztest_serialization
+  fuzztest_table_of_recent_compares
+  fuzztest_type_support
+  absl::base
+  absl::flat_hash_map
+  absl::flat_hash_set
+  absl::bits
+  absl::int128
+  absl::random_distributions
+  absl::strings
+  absl::str_format
+  absl::synchronization
+  absl::span
+)
+
+add_library(
+  fuzztest_seed_seq
+  OBJECT
+  internal/seed_seq.cc
+  internal/seed_seq.h
+)
+
+target_link_libraries(
+  fuzztest_seed_seq
+  PUBLIC
+  fuzztest_logging
+  absl::strings
+  absl::random_random
+  absl::span
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_seed_seq_test
+    internal/seed_seq_test.cc
+  )
+  target_link_libraries(
+    fuzztest_seed_seq_test
+    PUBLIC
+    fuzztest_logging
+    fuzztest_domain
+    fuzztest_coverage
+    fuzztest_seed_seq
+    fuzztest_fixture_driver
+    fuzztest_serialization
+    fuzztest_io
+    fuzztest_type_support
+    fuzztest_runtime
+    absl::time
+    GTest::gmock_main
+  )
+  add_test(
+    NAME
+    fuzztest_seed_seq_test
+    COMMAND
+    fuzztest_seed_seq_test
+  )
+endif ()
+
+add_library(
+  fuzztest_runtime
+  OBJECT
+  internal/runtime.cc
+  internal/runtime.h
+)
+
+target_link_libraries(
+  fuzztest_runtime
+  PUBLIC
+  fuzztest_coverage
+  fuzztest_domain
+  fuzztest_fixture_driver
+  fuzztest_io
+  fuzztest_logging
+  fuzztest_meta
+  fuzztest_registration
+  fuzztest_serialization
+  fuzztest_type_support
+  absl::function_ref
+  absl::random_random
+  absl::random_seed_sequences
+  absl::strings
+  absl::str_format
+  absl::time
+  absl::span
+)
+
+if (FUZZTEST_TESTING)
+  add_executable(
+    fuzztest_runtime_test
+    internal/runtime_test.cc
+  )
+  target_link_libraries(
+    fuzztest_runtime_test
+    PUBLIC
+    fuzztest_logging
+    fuzztest_domain
+    fuzztest_coverage
+    fuzztest_seed_seq
+    fuzztest_fixture_driver
+    fuzztest_serialization
+    fuzztest_io
+    fuzztest_type_support
+    fuzztest_runtime
+    absl::time
+    test_protobuf
+    GTest::gtest_main
+  )
+  add_test(
+    NAME
+    fuzztest_runtime_test
+    COMMAND
+    fuzztest_runtime_test
+  )
+endif ()
+
+add_library(
+  fuzztest_compatibility_mode
+  OBJECT
+  internal/compatibility_mode.cc
+  internal/compatibility_mode.h
+)
+
+target_link_libraries(
+  fuzztest_compatibility_mode
+  PUBLIC
+  fuzztest_fixture_driver
+  fuzztest_logging
+  fuzztest_runtime
+  absl::random_distributions
+  absl::strings
+  absl::str_format
+  absl::time
+)
+
+add_library(
+  fuzztest_registry
+  OBJECT
+  internal/registry.cc
+  internal/registry.h
+)
+
+target_link_libraries(
+  fuzztest_registry
+  PUBLIC
+  fuzztest_compatibility_mode
+  fuzztest_fixture_driver
+  fuzztest_registration
+  fuzztest_runtime
+  absl::flat_hash_map
+)
+
+add_library(
+  fuzztest_fuzztest
+  OBJECT
+  fuzztest.cc
+  fuzztest.h
+)
+
+target_link_libraries(
+  fuzztest_fuzztest
+  PUBLIC
+  fuzztest_domain
+  fuzztest_registry
+  absl::str_format
+  absl::strings
+)
+target_include_directories(
+    fuzztest_fuzztest
+    SYSTEM INTERFACE
+    "$<BUILD_INTERFACE:${fuzztest_SOURCE_DIR}>"
+    "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
+
+if (FUZZTEST_USE_GTEST OR FUZZTEST_TESTING)
+  add_library(
+    fuzztest_googletest_adaptor
+    OBJECT
+    googletest_adaptor.h
+  )
+
+  target_link_libraries(
+    fuzztest_googletest_adaptor
+    PUBLIC
+    fuzztest_registry
+    fuzztest_runtime
+    GTest::gtest
+  )
+
+  add_library(
+    fuzztest_googletest_fixture_adapter
+    OBJECT
+    googletest_fixture_adapter.h
+  )
+
+  target_link_libraries(
+    fuzztest_googletest_fixture_adapter
+    PUBLIC
+    fuzztest_fixture_driver
+    GTest::gtest
+  )
+
+  add_library(
+    fuzztest_gtest_main
+    STATIC
+    fuzztest_gtest_main.cc
+  )
+
+  target_link_libraries(
+    fuzztest_gtest_main
+    PUBLIC
+    fuzztest_serialization
+    fuzztest_io
+    fuzztest_coverage
+    fuzztest_logging
+    fuzztest_fixture_driver
+    fuzztest_type_support
+    fuzztest_seed_seq
+    fuzztest_fuzztest
+    fuzztest_registry
+    fuzztest_googletest_adaptor
+    fuzztest_regexp_dfa
+    fuzztest_runtime
+    fuzztest_table_of_recent_compares
+    fuzztest_subprocess
+    fuzztest_compatibility_mode
+    absl::flags
+    absl::flags_parse
+    absl::str_format
+    absl::strings
+    absl::time
+    GTest::gtest
+    GTest::gmock
+  )
+  # Make sure the headers are available.
+  target_include_directories(
+    fuzztest_gtest_main
+    SYSTEM INTERFACE
+    "$<BUILD_INTERFACE:${fuzztest_SOURCE_DIR}>"
+    "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
+endif ()
\ No newline at end of file
diff --git a/fuzztest/internal/domains/protobuf_domain_impl.h b/fuzztest/internal/domains/protobuf_domain_impl.h
index a245df7..db40285 100644
--- a/fuzztest/internal/domains/protobuf_domain_impl.h
+++ b/fuzztest/internal/domains/protobuf_domain_impl.h
@@ -28,7 +28,6 @@
 #include "absl/base/thread_annotations.h"
 #include "absl/container/flat_hash_map.h"
 #include "absl/container/flat_hash_set.h"
-#include "absl/log/die_if_null.h"
 #include "absl/random/bit_gen_ref.h"
 #include "absl/random/random.h"
 #include "absl/strings/string_view.h"
@@ -380,7 +379,10 @@
   PrototypePtr(std::function<const Prototype*()> prototype_factory)
       : prototype_factory_(std::move(prototype_factory)), prototype_(nullptr) {}
   PrototypePtr(const Prototype* prototype)
-      : prototype_factory_(), prototype_(ABSL_DIE_IF_NULL(prototype)) {}
+      : prototype_factory_(), prototype_(prototype) {
+    FUZZTEST_INTERNAL_CHECK_PRECONDITION(prototype != nullptr,
+                                         "Prototype should not be nullptr");
+  }
 
   PrototypePtr& operator=(const PrototypePtr<Prototype>& other) = default;
   PrototypePtr(const PrototypePtr<Prototype>& other) = default;
diff --git a/fuzztest/internal/domains/regexp_dfa.h b/fuzztest/internal/domains/regexp_dfa.h
index 79ff287..a72861d 100644
--- a/fuzztest/internal/domains/regexp_dfa.h
+++ b/fuzztest/internal/domains/regexp_dfa.h
@@ -28,8 +28,7 @@
 #include "absl/random/discrete_distribution.h"
 #include "absl/random/distributions.h"
 #include "./fuzztest/internal/logging.h"
-#include "re2/prog.h"
-#include "re2/regexp.h"
+#include "re2/re2.h"
 
 namespace fuzztest::internal {
 // Represents the deterministic finite automaton (DFA) of a regular expression.