1# Copyright 2020 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15import("//build_overrides/pigweed.gni")
16
17import("$dir_pw_toolchain/host_clang/toolchains.gni")
18import("$dir_pw_unit_test/test.gni")
19
20# Creates a libFuzzer-based fuzzer executable target.
21#
22# This will link `sources` and `deps` with the libFuzzer compiler runtime. The
23# `sources` and `deps` should include a definition of the standard LLVM fuzz
24# target function, `LLVMFuzzerTestOneInput`. For more details, see:
25#   //pw_fuzzer/docs.rst
26#   https://llvm.org/docs/LibFuzzer.html
27#
28template("pw_fuzzer") {
29  # This currently is ONLY supported on Linux and Mac using clang (debug).
30  # TODO(pwbug/179): Add Windows here after testing.
31  fuzzing_platforms = [
32    "linux",
33    "mac",
34  ]
35
36  fuzzing_toolchains = [ "//targets/host:host_clang_fuzz" ]
37
38  # This is how GN says 'elem in list':
39  can_fuzz = fuzzing_platforms + [ host_os ] - [ host_os ] != fuzzing_platforms
40
41  can_fuzz = fuzzing_toolchains + [ current_toolchain ] -
42             [ current_toolchain ] != fuzzing_toolchains && can_fuzz
43
44  if (can_fuzz && pw_toolchain_SANITIZERS != []) {
45    # Build the actual fuzzer using the fuzzing config.
46    pw_executable(target_name) {
47      forward_variables_from(invoker, "*", [ "visibility" ])
48      forward_variables_from(invoker, [ "visibility" ])
49      if (!defined(configs)) {
50        configs = []
51      }
52      configs += [ "$dir_pw_fuzzer:default_config" ]
53      if (pw_toolchain_OSS_FUZZ_ENABLED) {
54        configs += [ "$dir_pw_fuzzer:oss_fuzz" ]
55      } else {
56        configs += [ "$dir_pw_fuzzer:fuzzing" ]
57      }
58
59      _fuzzer_output_dir = "${target_out_dir}/bin"
60      if (defined(invoker.output_dir)) {
61        _fuzzer_output_dir = invoker.output_dir
62      }
63      output_dir = _fuzzer_output_dir
64
65      # Metadata for this fuzzer when used as part of a pw_test_group target.
66      metadata = {
67        tests = [
68          {
69            type = "fuzzer"
70            test_name = target_name
71            test_directory = rebase_path(output_dir, root_build_dir)
72          },
73        ]
74      }
75    }
76
77    # Dummy target to satisfy `pw_test_group`. It is empty as we don't want to
78    # automatically run fuzzers.
79    group(target_name + ".run") {
80    }
81
82    # Dummy target to satisfy `pw_test`. It is empty as we don't need a separate
83    # lib target.
84    group(target_name + ".lib") {
85    }
86  } else {
87    # Build a unit test that exercise the fuzz target function.
88    pw_test(target_name) {
89      # TODO(pwbug/195): Re-enable when there's better configurability for
90      # on-device fuzz testing.
91      enable_if = false
92      sources = []
93      deps = []
94      forward_variables_from(invoker, "*", [ "visibility" ])
95      forward_variables_from(invoker, [ "visibility" ])
96      sources += [ "$dir_pw_fuzzer/pw_fuzzer_disabled.cc" ]
97      deps += [ "$dir_pw_fuzzer:run_as_unit_test" ]
98    }
99  }
100}
101