Ensure dxc is built and loaded by tint_wgsl_fuzzer

- Make the gn and CMake build depend on dxcompiler target.
- In the wgsl fuzzer's init, set the dxc default path to the same
  directory as the executable's via argv[0]. Although argv[0] is not
guaranteed to contain the path to the executable, we mainly need this to
work for ClusterFuzz, where this should be the case.

Bug: chromium:42251292
Change-Id: If85c6cdd52b1ff98caf95327112b93173bcdf5d7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/193900
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 746f8eb..7ecf847 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -282,6 +282,12 @@
   public_configs = [ ":dxc-include-config" ]
 }
 
+source_set("dxcompiler-for-fuzzer") {
+  if (use_libfuzzer && target_cpu != "x86") {
+    public_deps = [ "${dawn_dxc_dir}/../gn/dxc:dxcompiler" ]
+  }
+}
+
 ###############################################################################
 # Fuzzers
 ###############################################################################
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 3a59059..ac4d4b0 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -524,6 +524,10 @@
       target_link_libraries(${TARGET} PRIVATE ${CMAKE_DL_LIBS})
     elseif(${DEPENDENCY} STREQUAL "dxc-include")
       target_include_directories(${TARGET} PRIVATE "${DAWN_THIRD_PARTY_DIR}/dxc/include")
+    elseif(${DEPENDENCY} STREQUAL "dxcompiler-for-fuzzer")
+      if(TINT_BUILD_FUZZERS) # TODO: and target arch is not x86
+        target_link_libraries(${TARGET} PRIVATE dxcompiler)
+      endif()
     elseif(${DEPENDENCY} STREQUAL "jsoncpp")
       target_link_libraries(${TARGET} PRIVATE jsoncpp_static)
     elseif(${DEPENDENCY} STREQUAL "langsvr")
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cfg b/src/tint/cmd/fuzz/wgsl/BUILD.cfg
index de92f71..2e2d939 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cfg
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cfg
@@ -5,7 +5,8 @@
         "OutputName": "tint_wgsl_fuzzer",
         "AdditionalDependencies": {
             /* Depend on all the fuzz targets to pull them all together. */
-            "Internal": [ "**:fuzz" ]
+            "Internal": [ "**:fuzz" ],
+            "External": ["dxcompiler-for-fuzzer"],
         }
     }
 }
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.cmake b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
index 350a170..aeb77bb 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.cmake
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.cmake
@@ -59,6 +59,7 @@
   tint_lang_wgsl_fuzz
   tint_utils_bytes
   tint_utils_cli
+  tint_utils_command
   tint_utils_containers
   tint_utils_diagnostic
   tint_utils_ice
@@ -83,8 +84,12 @@
 
 if(TINT_BUILD_HLSL_WRITER)
   tint_target_add_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
+    tint_lang_hlsl_validate
     tint_lang_hlsl_writer_fuzz
   )
+  tint_target_add_external_dependencies(tint_cmd_fuzz_wgsl_fuzz_cmd fuzz_cmd
+    "dxcompiler-for-fuzzer"
+  )
 endif(TINT_BUILD_HLSL_WRITER)
 
 if(TINT_BUILD_IR_BINARY)
diff --git a/src/tint/cmd/fuzz/wgsl/BUILD.gn b/src/tint/cmd/fuzz/wgsl/BUILD.gn
index 89d7ea9..a060109 100644
--- a/src/tint/cmd/fuzz/wgsl/BUILD.gn
+++ b/src/tint/cmd/fuzz/wgsl/BUILD.gn
@@ -101,6 +101,7 @@
       "${tint_src_dir}/lang/wgsl/writer/raise:fuzz",
       "${tint_src_dir}/utils/bytes",
       "${tint_src_dir}/utils/cli",
+      "${tint_src_dir}/utils/command",
       "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
@@ -122,7 +123,11 @@
     }
 
     if (tint_build_hlsl_writer) {
-      deps += [ "${tint_src_dir}/lang/hlsl/writer:fuzz" ]
+      deps += [
+        "${tint_src_dir}:dxcompiler-for-fuzzer",
+        "${tint_src_dir}/lang/hlsl/validate",
+        "${tint_src_dir}/lang/hlsl/writer:fuzz",
+      ]
     }
 
     if (tint_build_ir_binary) {
diff --git a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
index 733190d..3e9be54 100644
--- a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
@@ -31,13 +31,48 @@
 
 #include "src/tint/cmd/fuzz/wgsl/fuzz.h"
 #include "src/tint/utils/cli/cli.h"
+#include "src/tint/utils/command/command.h"
 #include "src/tint/utils/macros/defer.h"
 #include "src/tint/utils/text/base64.h"
+#include "src/tint/utils/text/string.h"
+
+#if TINT_BUILD_HLSL_WRITER
+#include "src/tint/lang/hlsl/validate/validate.h"
+#endif
 
 namespace {
 
 tint::fuzz::wgsl::Options options;
 
+std::string get_default_dxc_path(char*** argv) {
+    std::string default_dxc_path = "";
+#if TINT_BUILD_HLSL_WRITER
+    // Assume the DXC library is in the same directory as this executable
+    std::string exe_path = (*argv)[0];
+    exe_path = tint::ReplaceAll(exe_path, "\\", "/");
+    auto pos = exe_path.rfind('/');
+    if (pos != std::string::npos) {
+        default_dxc_path = exe_path.substr(0, pos) + '/' + tint::hlsl::validate::kDxcDLLName;
+    } else {
+        // argv[0] doesn't contain path to exe, try relative to cwd
+        default_dxc_path = tint::hlsl::validate::kDxcDLLName;
+    }
+#endif
+    return default_dxc_path;
+}
+
+void print_dxc_path_found(const std::string& dxc_path) {
+#if TINT_BUILD_HLSL_WRITER
+    // Log whether the DXC library was found or not once at initialization.
+    auto dxc = tint::Command::LookPath(dxc_path);
+    if (dxc.Found()) {
+        std::cout << "DXC library found: " << dxc.Path() << std::endl;
+    } else {
+        std::cout << "DXC library not found: " << dxc_path << std::endl;
+    }
+#endif
+}
+
 }  // namespace
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* input, size_t size) {
@@ -94,9 +129,12 @@
         return 0;
     }
 
+    // Read optional user-supplied args or use default provided
     options.filter = opt_filter.value.value_or("");
     options.run_concurrently = opt_concurrent.value.value_or(false);
     options.verbose = opt_verbose.value.value_or(false);
-    options.dxc = opt_dxc.value.value_or("");
+    options.dxc = opt_dxc.value.value_or(get_default_dxc_path(argv));
+
+    print_dxc_path_found(options.dxc);
     return 0;
 }
diff --git a/src/tint/externals.json b/src/tint/externals.json
index 1745609..52150c0 100644
--- a/src/tint/externals.json
+++ b/src/tint/externals.json
@@ -20,6 +20,9 @@
         ],
         "Condition": "tint_build_hlsl_writer"
     },
+    "dxcompiler-for-fuzzer": {
+        "Condition": "tint_build_hlsl_writer"
+    },
     "google-benchmark": {
         "IncludePatterns": [
             "benchmark/benchmark.h"
diff --git a/tools/src/cmd/gen/build/BUILD.bazel.tmpl b/tools/src/cmd/gen/build/BUILD.bazel.tmpl
index 8432d76..939ec4c 100644
--- a/tools/src/cmd/gen/build/BUILD.bazel.tmpl
+++ b/tools/src/cmd/gen/build/BUILD.bazel.tmpl
@@ -140,23 +140,24 @@
 --------------------------------------------------------------------------------
 */ -}}
 {{- define "ExternalDependencyTarget"}}
-{{-        if eq $.Name "abseil"             -}}"@abseil_cpp//absl/strings",
-{{-   else if eq $.Name "dl"                 -}}{{/* unsupported */}}
-{{-   else if eq $.Name "dxc-include"        -}}{{/* unsupported */}}
-{{-   else if eq $.Name "glslang-res-limits" -}}{{/* unsupported */}}
-{{-   else if eq $.Name "glslang"            -}}{{/* unsupported */}}
-{{-   else if eq $.Name "gmock"              -}}"@gtest",
-{{-   else if eq $.Name "google-benchmark"   -}}"@benchmark",
-{{-   else if eq $.Name "gtest"              -}}"@gtest",
-{{-   else if eq $.Name "jsoncpp"            -}}{{/* unsupported */}}
-{{-   else if eq $.Name "langsvr"            -}}{{/* unsupported */}}
-{{-   else if eq $.Name "metal"              -}}{{/* unsupported */}}
-{{-   else if eq $.Name "spirv-headers"      -}}"@spirv_headers//:spirv_cpp11_headers", "@spirv_headers//:spirv_c_headers",
-{{-   else if eq $.Name "spirv-opt-internal" -}}"@spirv_tools//:spirv_tools_opt",
-{{-   else if eq $.Name "spirv-tools"        -}}"@spirv_tools",
-{{-   else if eq $.Name "thread"             -}}{{/* unsupported */}}
-{{-   else if eq $.Name "winsock"            -}}{{/* unsupported */}}
-{{-   else                                   -}}{{Error (printf "unhandled external dependency '%v'" $.Name)}}
+{{-        if eq $.Name "abseil"                -}}"@abseil_cpp//absl/strings",
+{{-   else if eq $.Name "dl"                    -}}{{/* unsupported */}}
+{{-   else if eq $.Name "dxc-include"           -}}{{/* unsupported */}}
+{{-   else if eq $.Name "dxcompiler-for-fuzzer" -}}{{/* unsupported */}}
+{{-   else if eq $.Name "glslang-res-limits"    -}}{{/* unsupported */}}
+{{-   else if eq $.Name "glslang"               -}}{{/* unsupported */}}
+{{-   else if eq $.Name "gmock"                 -}}"@gtest",
+{{-   else if eq $.Name "google-benchmark"      -}}"@benchmark",
+{{-   else if eq $.Name "gtest"                 -}}"@gtest",
+{{-   else if eq $.Name "jsoncpp"               -}}{{/* unsupported */}}
+{{-   else if eq $.Name "langsvr"               -}}{{/* unsupported */}}
+{{-   else if eq $.Name "metal"                 -}}{{/* unsupported */}}
+{{-   else if eq $.Name "spirv-headers"         -}}"@spirv_headers//:spirv_cpp11_headers", "@spirv_headers//:spirv_c_headers",
+{{-   else if eq $.Name "spirv-opt-internal"    -}}"@spirv_tools//:spirv_tools_opt",
+{{-   else if eq $.Name "spirv-tools"           -}}"@spirv_tools",
+{{-   else if eq $.Name "thread"                -}}{{/* unsupported */}}
+{{-   else if eq $.Name "winsock"               -}}{{/* unsupported */}}
+{{-   else                                      -}}{{Error (printf "unhandled external dependency '%v'" $.Name)}}
 {{-   end}}
 {{- end}}
 
diff --git a/tools/src/cmd/gen/build/BUILD.gn.tmpl b/tools/src/cmd/gen/build/BUILD.gn.tmpl
index 47d25be..a5c308f 100644
--- a/tools/src/cmd/gen/build/BUILD.gn.tmpl
+++ b/tools/src/cmd/gen/build/BUILD.gn.tmpl
@@ -164,23 +164,24 @@
 --------------------------------------------------------------------------------
 */ -}}
 {{- define "ExternalDependencyTargets"}}
-{{-        if eq $.Name "abseil"               -}}"${tint_src_dir}:abseil",
-{{-   else if eq $.Name "dl"                   -}}"${tint_src_dir}:dl",
-{{-   else if eq $.Name "dxc-include"          -}}"${tint_src_dir}:dxc-include",
-{{-   else if eq $.Name "glslang-res-limits"   -}}"${tint_glslang_dir}:glslang_default_resource_limits_sources",
-{{-   else if eq $.Name "glslang"              -}}"${tint_glslang_dir}:glslang_lib_sources",
-{{-   else if eq $.Name "google-benchmark"     -}}"${tint_src_dir}:google_benchmark",
-{{-   else if eq $.Name "gtest"                -}}"${tint_src_dir}:gmock_and_gtest",
-{{-   else if eq $.Name "jsoncpp"              -}}"${tint_src_dir}:jsoncpp",
-{{-   else if eq $.Name "langsvr"              -}}"${tint_src_dir}:langsvr",
-{{-   else if eq $.Name "libprotobuf-mutator"  -}}"${tint_lpm_dir}:libprotobuf-mutator",
-{{-   else if eq $.Name "metal"                -}}"${tint_src_dir}:metal",
-{{-   else if eq $.Name "spirv-headers"        -}}"${tint_spirv_headers_dir}:spv_headers",
-{{-   else if eq $.Name "spirv-opt-internal"   -}}"${tint_spirv_tools_dir}:spvtools", "${tint_spirv_tools_dir}:spvtools_opt", "${tint_spirv_tools_dir}:spvtools_val",
-{{-   else if eq $.Name "spirv-tools"          -}}"${tint_spirv_tools_dir}:spvtools_headers", "${tint_spirv_tools_dir}:spvtools_val",
-{{-   else if eq $.Name "thread"               -}}"${tint_src_dir}:thread",
-{{-   else if eq $.Name "winsock"              -}}"${tint_src_dir}:winsock",
-{{-   else                                     -}}{{Error (printf "unhandled external dependency '%v'" $.Name)}}
+{{-        if eq $.Name "abseil"                -}}"${tint_src_dir}:abseil",
+{{-   else if eq $.Name "dl"                    -}}"${tint_src_dir}:dl",
+{{-   else if eq $.Name "dxc-include"           -}}"${tint_src_dir}:dxc-include",
+{{-   else if eq $.Name "dxcompiler-for-fuzzer" -}}"${tint_src_dir}:dxcompiler-for-fuzzer",
+{{-   else if eq $.Name "glslang-res-limits"    -}}"${tint_glslang_dir}:glslang_default_resource_limits_sources",
+{{-   else if eq $.Name "glslang"               -}}"${tint_glslang_dir}:glslang_lib_sources",
+{{-   else if eq $.Name "google-benchmark"      -}}"${tint_src_dir}:google_benchmark",
+{{-   else if eq $.Name "gtest"                 -}}"${tint_src_dir}:gmock_and_gtest",
+{{-   else if eq $.Name "jsoncpp"               -}}"${tint_src_dir}:jsoncpp",
+{{-   else if eq $.Name "langsvr"               -}}"${tint_src_dir}:langsvr",
+{{-   else if eq $.Name "libprotobuf-mutator"   -}}"${tint_lpm_dir}:libprotobuf-mutator",
+{{-   else if eq $.Name "metal"                 -}}"${tint_src_dir}:metal",
+{{-   else if eq $.Name "spirv-headers"         -}}"${tint_spirv_headers_dir}:spv_headers",
+{{-   else if eq $.Name "spirv-opt-internal"    -}}"${tint_spirv_tools_dir}:spvtools", "${tint_spirv_tools_dir}:spvtools_opt", "${tint_spirv_tools_dir}:spvtools_val",
+{{-   else if eq $.Name "spirv-tools"           -}}"${tint_spirv_tools_dir}:spvtools_headers", "${tint_spirv_tools_dir}:spvtools_val",
+{{-   else if eq $.Name "thread"                -}}"${tint_src_dir}:thread",
+{{-   else if eq $.Name "winsock"               -}}"${tint_src_dir}:winsock",
+{{-   else                                      -}}{{Error (printf "unhandled external dependency '%v'" $.Name)}}
 {{-   end}}
 {{- end}}