Coverage Report

Created: 2026-06-10 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/shaderc/glslc/src/file_compiler.cc
Line
Count
Source
1
// Copyright 2015 The Shaderc Authors. All rights reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://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,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "file_compiler.h"
16
17
#include <cassert>
18
#include <fstream>
19
#include <iomanip>
20
#include <iostream>
21
#include <sstream>
22
23
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
24
#include "tint/tint.h"
25
#endif  // SHADERC_ENABLE_WGSL_OUTPUT==1
26
27
#include "file.h"
28
#include "file_includer.h"
29
#include "shader_stage.h"
30
31
#include "libshaderc_util/io_shaderc.h"
32
#include "libshaderc_util/message.h"
33
34
namespace {
35
using shaderc_util::string_piece;
36
37
// A helper function to emit SPIR-V binary code as a list of hex numbers in
38
// text form. Returns true if a non-empty compilation result is emitted
39
// successfully. Return false if nothing should be emitted, either because the
40
// compilation result is empty, or the compilation output is not SPIR-V binary
41
// code.
42
template <typename CompilationResultType>
43
bool EmitSpirvBinaryAsCommaSeparatedNumbers(const CompilationResultType& result,
44
0
                                            std::ostream* out) {
45
  // Return early if the compilation output is not in SPIR-V binary code form.
46
0
  if (!std::is_same<CompilationResultType,
47
0
                    shaderc::SpvCompilationResult>::value)
48
0
    return false;
49
  // Return early if the compilation result is empty.
50
0
  if (result.cbegin() == result.cend()) return false;
51
0
  std::ios::fmtflags output_stream_flag_cache(out->flags());
52
0
  *out << std::hex << std::setfill('0');
53
0
  auto RI = result.cbegin();
54
0
  *out << "0x" << std::setw(8) << *RI++;
55
0
  for (size_t counter = 1; RI != result.cend(); RI++, counter++) {
56
0
    *out << ",";
57
    // Break line for every four words.
58
0
    if (counter % 4 == 0) {
59
0
      *out << std::endl;
60
0
    }
61
0
    *out << "0x" << std::setw(8) << *RI;
62
0
  }
63
0
  out->flags(output_stream_flag_cache);
64
0
  return true;
65
0
}
Unexecuted instantiation: file_compiler.cc:bool (anonymous namespace)::EmitSpirvBinaryAsCommaSeparatedNumbers<shaderc::CompilationResult<unsigned int> >(shaderc::CompilationResult<unsigned int> const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*)
Unexecuted instantiation: file_compiler.cc:bool (anonymous namespace)::EmitSpirvBinaryAsCommaSeparatedNumbers<shaderc::CompilationResult<char> >(shaderc::CompilationResult<char> const&, std::__1::basic_ostream<char, std::__1::char_traits<char> >*)
66
}  // anonymous namespace
67
68
namespace glslc {
69
2.28k
bool FileCompiler::CompileShaderFile(const InputFileSpec& input_file) {
70
2.28k
  std::vector<char> input_data;
71
2.28k
  std::string path = input_file.name;
72
2.28k
  if (!shaderc_util::ReadFile(path, &input_data)) {
73
0
    return false;
74
0
  }
75
76
2.28k
  std::string output_file_name = GetOutputFileName(input_file.name);
77
2.28k
  string_piece error_file_name = input_file.name;
78
79
2.28k
  if (error_file_name == "-") {
80
    // If the input file was stdin, we want to output errors as <stdin>.
81
0
    error_file_name = "<stdin>";
82
0
  }
83
84
2.28k
  string_piece source_string = "";
85
2.28k
  if (!input_data.empty()) {
86
2.28k
    source_string = {&input_data.front(),
87
2.28k
                     &input_data.front() + input_data.size()};
88
2.28k
  }
89
90
2.28k
  std::unique_ptr<FileIncluder> includer(
91
2.28k
      new FileIncluder(&include_file_finder_));
92
  // Get a reference to the dependency trace before we pass the ownership to
93
  // shaderc::CompileOptions.
94
2.28k
  const auto& used_source_files = includer->file_path_trace();
95
2.28k
  options_.SetIncluder(std::move(includer));
96
97
2.28k
  if (input_file.stage == shaderc_spirv_assembly) {
98
    // Only act if the requested target is SPIR-V binary.
99
0
    if (output_type_ == OutputType::SpirvBinary) {
100
0
      const auto result =
101
0
          compiler_.AssembleToSpv(source_string.data(), source_string.size());
102
0
      return EmitCompiledResult(result, input_file.name, output_file_name,
103
0
                                error_file_name, used_source_files);
104
0
    } else {
105
0
      return true;
106
0
    }
107
0
  }
108
109
  // Set the language.  Since we only use the options object in this
110
  // method, then it's ok to always set it without resetting it after
111
  // compilation.  A subsequent compilation will set it again anyway.
112
2.28k
  options_.SetSourceLanguage(input_file.language);
113
114
2.28k
  switch (output_type_) {
115
760
    case OutputType::SpirvBinary: {
116
760
      const auto result = compiler_.CompileGlslToSpv(
117
760
          source_string.data(), source_string.size(), input_file.stage,
118
760
          error_file_name.data(), input_file.entry_point_name.c_str(),
119
760
          options_);
120
760
      return EmitCompiledResult(result, input_file.name, output_file_name,
121
760
                                error_file_name, used_source_files);
122
0
    }
123
0
    case OutputType::SpirvAssemblyText: {
124
0
      const auto result = compiler_.CompileGlslToSpvAssembly(
125
0
          source_string.data(), source_string.size(), input_file.stage,
126
0
          error_file_name.data(), input_file.entry_point_name.c_str(),
127
0
          options_);
128
0
      return EmitCompiledResult(result, input_file.name, output_file_name,
129
0
                                error_file_name, used_source_files);
130
0
    }
131
1.52k
    case OutputType::PreprocessedText: {
132
1.52k
      const auto result = compiler_.PreprocessGlsl(
133
1.52k
          source_string.data(), source_string.size(), input_file.stage,
134
1.52k
          error_file_name.data(), options_);
135
1.52k
      return EmitCompiledResult(result, input_file.name, output_file_name,
136
1.52k
                                error_file_name, used_source_files);
137
0
    }
138
2.28k
  }
139
0
  return false;
140
2.28k
}
141
142
template <typename CompilationResultType>
143
bool FileCompiler::EmitCompiledResult(
144
    const CompilationResultType& result, const std::string& input_file,
145
    const std::string& output_file_name, string_piece error_file_name,
146
2.28k
    const std::unordered_set<std::string>& used_source_files) {
147
2.28k
  total_errors_ += result.GetNumErrors();
148
2.28k
  total_warnings_ += result.GetNumWarnings();
149
150
2.28k
  bool compilation_success =
151
2.28k
      result.GetCompilationStatus() == shaderc_compilation_status_success;
152
153
  // Handle the error message for failing to deduce the shader kind.
154
2.28k
  if (result.GetCompilationStatus() ==
155
2.28k
      shaderc_compilation_status_invalid_stage) {
156
0
    auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name);
157
0
    if (glsl_or_hlsl_extension != "") {
158
0
      std::cerr << "glslc: error: "
159
0
                << "'" << error_file_name << "': "
160
0
                << "." << glsl_or_hlsl_extension
161
0
                << " file encountered but no -fshader-stage specified ahead";
162
0
    } else if (error_file_name == "<stdin>") {
163
0
      std::cerr
164
0
          << "glslc: error: '-': -fshader-stage required when input is from "
165
0
             "standard "
166
0
             "input \"-\"";
167
0
    } else {
168
0
      std::cerr << "glslc: error: "
169
0
                << "'" << error_file_name << "': "
170
0
                << "file not recognized: File format not recognized";
171
0
    }
172
0
    std::cerr << "\n";
173
174
0
    return false;
175
0
  }
176
177
  // Get a string_piece which refers to the normal compilation output for now.
178
  // This string_piece might be redirected to the dependency info to be dumped
179
  // later, if the handler is instantiated to dump as normal compilation output,
180
  // and the original compilation output should be blocked. Otherwise it won't
181
  // be touched. The main output stream dumps this string_piece later.
182
2.28k
  string_piece compilation_output(
183
2.28k
      reinterpret_cast<const char*>(result.cbegin()),
184
2.28k
      reinterpret_cast<const char*>(result.cend()));
185
186
  // If we have dependency info dumping handler instantiated, we should dump
187
  // dependency info first. This may redirect the compilation output
188
  // string_piece to dependency info.
189
2.28k
  std::string potential_dependency_info_output;
190
2.28k
  if (dependency_info_dumping_handler_) {
191
0
    if (!dependency_info_dumping_handler_->DumpDependencyInfo(
192
0
            GetCandidateOutputFileName(input_file), error_file_name.data(),
193
0
            &potential_dependency_info_output, used_source_files)) {
194
0
      return false;
195
0
    }
196
0
    if (!potential_dependency_info_output.empty()) {
197
      // If the potential_dependency_info_output string is not empty, it means
198
      // we should dump dependency info as normal compilation output. Redirect
199
      // the compilation output string_piece to the dependency info stored in
200
      // potential_dependency_info_output to make it happen.
201
0
      compilation_output = potential_dependency_info_output;
202
0
    }
203
0
  }
204
205
2.28k
  std::ostream* out = nullptr;
206
2.28k
  std::ofstream potential_file_stream;
207
2.28k
  if (compilation_success) {
208
491
    out = shaderc_util::GetOutputStream(output_file_name,
209
491
                                        &potential_file_stream, &std::cerr);
210
491
    if (!out || out->fail()) {
211
      // An error message has already been emitted to the stderr stream.
212
0
      return false;
213
0
    }
214
215
    // Write compilation output to output file. If an output format for SPIR-V
216
    // binary code is specified, it is handled here.
217
491
    switch (binary_emission_format_) {
218
0
      case SpirvBinaryEmissionFormat::Unspecified:
219
0
      case SpirvBinaryEmissionFormat::Binary:
220
        // The output format is unspecified or specified as binary output.
221
        // On Windows, the output stream must be set to binary mode.  By
222
        // default the standard output stream is set to text mode, which
223
        // translates newlines (\n) to carriage-return newline pairs
224
        // (\r\n).
225
0
        if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout();
226
0
        out->write(compilation_output.data(), compilation_output.size());
227
0
        if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout();
228
0
        break;
229
0
      case SpirvBinaryEmissionFormat::Numbers:
230
        // The output format is specified to be a list of hex numbers, the
231
        // compilation output must be in SPIR-V binary code form.
232
0
        assert(output_type_ == OutputType::SpirvBinary);
233
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
234
          // Only emits the end-of-line character when the emitted compilation
235
          // result is not empty.
236
0
          *out << std::endl;
237
0
        }
238
0
        break;
239
0
      case SpirvBinaryEmissionFormat::CInitList:
240
        // The output format is specified to be a C-style initializer list, the
241
        // compilation output must be in SPIR-V binary code form.
242
0
        assert(output_type_ == OutputType::SpirvBinary);
243
0
        if (result.begin() != result.end()) {
244
          // Only emits the '{' when the compilation result is not empty.
245
0
          *out << "{";
246
0
        }
247
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
248
          // Only emits the end-of-line character when the emitted compilation
249
          // result is not empty.
250
0
          *out << "}" << std::endl;
251
0
        }
252
0
        break;
253
491
      case SpirvBinaryEmissionFormat::WGSL: {
254
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
255
        tint::Context ctx;
256
        tint::reader::spirv::Parser spv_reader(
257
            &ctx, std::vector<uint32_t>(result.begin(), result.end()));
258
        if (!spv_reader.Parse()) {
259
          std::cout << "error: failed to convert SPIR-V binary to WGSL: "
260
                    << spv_reader.error() << std::endl;
261
          return false;
262
        }
263
        tint::writer::wgsl::Generator wgsl_writer(spv_reader.module());
264
        if (!wgsl_writer.Generate()) {
265
          std::cout << "error: failed to convert to WGSL: "
266
                    << wgsl_writer.error() << std::endl;
267
          return false;
268
        }
269
        *out << wgsl_writer.result();
270
#endif  // SHADERC_ENABLE_WGSL_OUTPUT==1
271
491
        break;
272
0
      }
273
491
    }
274
491
  }
275
276
  // Write error message to std::cerr.
277
2.28k
  std::cerr << result.GetErrorMessage();
278
2.28k
  if (out && out->fail()) {
279
    // Something wrong happened on output.
280
0
    if (out == &std::cout) {
281
0
      std::cerr << "glslc: error: error writing to standard output"
282
0
                << std::endl;
283
0
    } else {
284
0
      std::cerr << "glslc: error: error writing to output file: '"
285
0
                << output_file_name_ << "'" << std::endl;
286
0
    }
287
0
    return false;
288
0
  }
289
290
2.28k
  return compilation_success;
291
2.28k
}
bool glslc::FileCompiler::EmitCompiledResult<shaderc::CompilationResult<unsigned int> >(shaderc::CompilationResult<unsigned int> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, shaderc_util::string_piece, std::__1::unordered_set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Line
Count
Source
146
760
    const std::unordered_set<std::string>& used_source_files) {
147
760
  total_errors_ += result.GetNumErrors();
148
760
  total_warnings_ += result.GetNumWarnings();
149
150
760
  bool compilation_success =
151
760
      result.GetCompilationStatus() == shaderc_compilation_status_success;
152
153
  // Handle the error message for failing to deduce the shader kind.
154
760
  if (result.GetCompilationStatus() ==
155
760
      shaderc_compilation_status_invalid_stage) {
156
0
    auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name);
157
0
    if (glsl_or_hlsl_extension != "") {
158
0
      std::cerr << "glslc: error: "
159
0
                << "'" << error_file_name << "': "
160
0
                << "." << glsl_or_hlsl_extension
161
0
                << " file encountered but no -fshader-stage specified ahead";
162
0
    } else if (error_file_name == "<stdin>") {
163
0
      std::cerr
164
0
          << "glslc: error: '-': -fshader-stage required when input is from "
165
0
             "standard "
166
0
             "input \"-\"";
167
0
    } else {
168
0
      std::cerr << "glslc: error: "
169
0
                << "'" << error_file_name << "': "
170
0
                << "file not recognized: File format not recognized";
171
0
    }
172
0
    std::cerr << "\n";
173
174
0
    return false;
175
0
  }
176
177
  // Get a string_piece which refers to the normal compilation output for now.
178
  // This string_piece might be redirected to the dependency info to be dumped
179
  // later, if the handler is instantiated to dump as normal compilation output,
180
  // and the original compilation output should be blocked. Otherwise it won't
181
  // be touched. The main output stream dumps this string_piece later.
182
760
  string_piece compilation_output(
183
760
      reinterpret_cast<const char*>(result.cbegin()),
184
760
      reinterpret_cast<const char*>(result.cend()));
185
186
  // If we have dependency info dumping handler instantiated, we should dump
187
  // dependency info first. This may redirect the compilation output
188
  // string_piece to dependency info.
189
760
  std::string potential_dependency_info_output;
190
760
  if (dependency_info_dumping_handler_) {
191
0
    if (!dependency_info_dumping_handler_->DumpDependencyInfo(
192
0
            GetCandidateOutputFileName(input_file), error_file_name.data(),
193
0
            &potential_dependency_info_output, used_source_files)) {
194
0
      return false;
195
0
    }
196
0
    if (!potential_dependency_info_output.empty()) {
197
      // If the potential_dependency_info_output string is not empty, it means
198
      // we should dump dependency info as normal compilation output. Redirect
199
      // the compilation output string_piece to the dependency info stored in
200
      // potential_dependency_info_output to make it happen.
201
0
      compilation_output = potential_dependency_info_output;
202
0
    }
203
0
  }
204
205
760
  std::ostream* out = nullptr;
206
760
  std::ofstream potential_file_stream;
207
760
  if (compilation_success) {
208
31
    out = shaderc_util::GetOutputStream(output_file_name,
209
31
                                        &potential_file_stream, &std::cerr);
210
31
    if (!out || out->fail()) {
211
      // An error message has already been emitted to the stderr stream.
212
0
      return false;
213
0
    }
214
215
    // Write compilation output to output file. If an output format for SPIR-V
216
    // binary code is specified, it is handled here.
217
31
    switch (binary_emission_format_) {
218
0
      case SpirvBinaryEmissionFormat::Unspecified:
219
0
      case SpirvBinaryEmissionFormat::Binary:
220
        // The output format is unspecified or specified as binary output.
221
        // On Windows, the output stream must be set to binary mode.  By
222
        // default the standard output stream is set to text mode, which
223
        // translates newlines (\n) to carriage-return newline pairs
224
        // (\r\n).
225
0
        if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout();
226
0
        out->write(compilation_output.data(), compilation_output.size());
227
0
        if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout();
228
0
        break;
229
0
      case SpirvBinaryEmissionFormat::Numbers:
230
        // The output format is specified to be a list of hex numbers, the
231
        // compilation output must be in SPIR-V binary code form.
232
0
        assert(output_type_ == OutputType::SpirvBinary);
233
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
234
          // Only emits the end-of-line character when the emitted compilation
235
          // result is not empty.
236
0
          *out << std::endl;
237
0
        }
238
0
        break;
239
0
      case SpirvBinaryEmissionFormat::CInitList:
240
        // The output format is specified to be a C-style initializer list, the
241
        // compilation output must be in SPIR-V binary code form.
242
0
        assert(output_type_ == OutputType::SpirvBinary);
243
0
        if (result.begin() != result.end()) {
244
          // Only emits the '{' when the compilation result is not empty.
245
0
          *out << "{";
246
0
        }
247
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
248
          // Only emits the end-of-line character when the emitted compilation
249
          // result is not empty.
250
0
          *out << "}" << std::endl;
251
0
        }
252
0
        break;
253
31
      case SpirvBinaryEmissionFormat::WGSL: {
254
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
255
        tint::Context ctx;
256
        tint::reader::spirv::Parser spv_reader(
257
            &ctx, std::vector<uint32_t>(result.begin(), result.end()));
258
        if (!spv_reader.Parse()) {
259
          std::cout << "error: failed to convert SPIR-V binary to WGSL: "
260
                    << spv_reader.error() << std::endl;
261
          return false;
262
        }
263
        tint::writer::wgsl::Generator wgsl_writer(spv_reader.module());
264
        if (!wgsl_writer.Generate()) {
265
          std::cout << "error: failed to convert to WGSL: "
266
                    << wgsl_writer.error() << std::endl;
267
          return false;
268
        }
269
        *out << wgsl_writer.result();
270
#endif  // SHADERC_ENABLE_WGSL_OUTPUT==1
271
31
        break;
272
0
      }
273
31
    }
274
31
  }
275
276
  // Write error message to std::cerr.
277
760
  std::cerr << result.GetErrorMessage();
278
760
  if (out && out->fail()) {
279
    // Something wrong happened on output.
280
0
    if (out == &std::cout) {
281
0
      std::cerr << "glslc: error: error writing to standard output"
282
0
                << std::endl;
283
0
    } else {
284
0
      std::cerr << "glslc: error: error writing to output file: '"
285
0
                << output_file_name_ << "'" << std::endl;
286
0
    }
287
0
    return false;
288
0
  }
289
290
760
  return compilation_success;
291
760
}
bool glslc::FileCompiler::EmitCompiledResult<shaderc::CompilationResult<char> >(shaderc::CompilationResult<char> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, shaderc_util::string_piece, std::__1::unordered_set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Line
Count
Source
146
1.52k
    const std::unordered_set<std::string>& used_source_files) {
147
1.52k
  total_errors_ += result.GetNumErrors();
148
1.52k
  total_warnings_ += result.GetNumWarnings();
149
150
1.52k
  bool compilation_success =
151
1.52k
      result.GetCompilationStatus() == shaderc_compilation_status_success;
152
153
  // Handle the error message for failing to deduce the shader kind.
154
1.52k
  if (result.GetCompilationStatus() ==
155
1.52k
      shaderc_compilation_status_invalid_stage) {
156
0
    auto glsl_or_hlsl_extension = GetGlslOrHlslExtension(error_file_name);
157
0
    if (glsl_or_hlsl_extension != "") {
158
0
      std::cerr << "glslc: error: "
159
0
                << "'" << error_file_name << "': "
160
0
                << "." << glsl_or_hlsl_extension
161
0
                << " file encountered but no -fshader-stage specified ahead";
162
0
    } else if (error_file_name == "<stdin>") {
163
0
      std::cerr
164
0
          << "glslc: error: '-': -fshader-stage required when input is from "
165
0
             "standard "
166
0
             "input \"-\"";
167
0
    } else {
168
0
      std::cerr << "glslc: error: "
169
0
                << "'" << error_file_name << "': "
170
0
                << "file not recognized: File format not recognized";
171
0
    }
172
0
    std::cerr << "\n";
173
174
0
    return false;
175
0
  }
176
177
  // Get a string_piece which refers to the normal compilation output for now.
178
  // This string_piece might be redirected to the dependency info to be dumped
179
  // later, if the handler is instantiated to dump as normal compilation output,
180
  // and the original compilation output should be blocked. Otherwise it won't
181
  // be touched. The main output stream dumps this string_piece later.
182
1.52k
  string_piece compilation_output(
183
1.52k
      reinterpret_cast<const char*>(result.cbegin()),
184
1.52k
      reinterpret_cast<const char*>(result.cend()));
185
186
  // If we have dependency info dumping handler instantiated, we should dump
187
  // dependency info first. This may redirect the compilation output
188
  // string_piece to dependency info.
189
1.52k
  std::string potential_dependency_info_output;
190
1.52k
  if (dependency_info_dumping_handler_) {
191
0
    if (!dependency_info_dumping_handler_->DumpDependencyInfo(
192
0
            GetCandidateOutputFileName(input_file), error_file_name.data(),
193
0
            &potential_dependency_info_output, used_source_files)) {
194
0
      return false;
195
0
    }
196
0
    if (!potential_dependency_info_output.empty()) {
197
      // If the potential_dependency_info_output string is not empty, it means
198
      // we should dump dependency info as normal compilation output. Redirect
199
      // the compilation output string_piece to the dependency info stored in
200
      // potential_dependency_info_output to make it happen.
201
0
      compilation_output = potential_dependency_info_output;
202
0
    }
203
0
  }
204
205
1.52k
  std::ostream* out = nullptr;
206
1.52k
  std::ofstream potential_file_stream;
207
1.52k
  if (compilation_success) {
208
460
    out = shaderc_util::GetOutputStream(output_file_name,
209
460
                                        &potential_file_stream, &std::cerr);
210
460
    if (!out || out->fail()) {
211
      // An error message has already been emitted to the stderr stream.
212
0
      return false;
213
0
    }
214
215
    // Write compilation output to output file. If an output format for SPIR-V
216
    // binary code is specified, it is handled here.
217
460
    switch (binary_emission_format_) {
218
0
      case SpirvBinaryEmissionFormat::Unspecified:
219
0
      case SpirvBinaryEmissionFormat::Binary:
220
        // The output format is unspecified or specified as binary output.
221
        // On Windows, the output stream must be set to binary mode.  By
222
        // default the standard output stream is set to text mode, which
223
        // translates newlines (\n) to carriage-return newline pairs
224
        // (\r\n).
225
0
        if (out == &std::cout) shaderc_util::FlushAndSetBinaryModeOnStdout();
226
0
        out->write(compilation_output.data(), compilation_output.size());
227
0
        if (out == &std::cout) shaderc_util::FlushAndSetTextModeOnStdout();
228
0
        break;
229
0
      case SpirvBinaryEmissionFormat::Numbers:
230
        // The output format is specified to be a list of hex numbers, the
231
        // compilation output must be in SPIR-V binary code form.
232
0
        assert(output_type_ == OutputType::SpirvBinary);
233
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
234
          // Only emits the end-of-line character when the emitted compilation
235
          // result is not empty.
236
0
          *out << std::endl;
237
0
        }
238
0
        break;
239
0
      case SpirvBinaryEmissionFormat::CInitList:
240
        // The output format is specified to be a C-style initializer list, the
241
        // compilation output must be in SPIR-V binary code form.
242
0
        assert(output_type_ == OutputType::SpirvBinary);
243
0
        if (result.begin() != result.end()) {
244
          // Only emits the '{' when the compilation result is not empty.
245
0
          *out << "{";
246
0
        }
247
0
        if (EmitSpirvBinaryAsCommaSeparatedNumbers(result, out)) {
248
          // Only emits the end-of-line character when the emitted compilation
249
          // result is not empty.
250
0
          *out << "}" << std::endl;
251
0
        }
252
0
        break;
253
460
      case SpirvBinaryEmissionFormat::WGSL: {
254
#if SHADERC_ENABLE_WGSL_OUTPUT == 1
255
        tint::Context ctx;
256
        tint::reader::spirv::Parser spv_reader(
257
            &ctx, std::vector<uint32_t>(result.begin(), result.end()));
258
        if (!spv_reader.Parse()) {
259
          std::cout << "error: failed to convert SPIR-V binary to WGSL: "
260
                    << spv_reader.error() << std::endl;
261
          return false;
262
        }
263
        tint::writer::wgsl::Generator wgsl_writer(spv_reader.module());
264
        if (!wgsl_writer.Generate()) {
265
          std::cout << "error: failed to convert to WGSL: "
266
                    << wgsl_writer.error() << std::endl;
267
          return false;
268
        }
269
        *out << wgsl_writer.result();
270
#endif  // SHADERC_ENABLE_WGSL_OUTPUT==1
271
460
        break;
272
0
      }
273
460
    }
274
460
  }
275
276
  // Write error message to std::cerr.
277
1.52k
  std::cerr << result.GetErrorMessage();
278
1.52k
  if (out && out->fail()) {
279
    // Something wrong happened on output.
280
0
    if (out == &std::cout) {
281
0
      std::cerr << "glslc: error: error writing to standard output"
282
0
                << std::endl;
283
0
    } else {
284
0
      std::cerr << "glslc: error: error writing to output file: '"
285
0
                << output_file_name_ << "'" << std::endl;
286
0
    }
287
0
    return false;
288
0
  }
289
290
1.52k
  return compilation_success;
291
1.52k
}
292
293
760
void FileCompiler::AddIncludeDirectory(const std::string& path) {
294
760
  include_file_finder_.search_path().push_back(path);
295
760
}
296
297
0
void FileCompiler::SetIndividualCompilationFlag() {
298
0
  if (output_type_ != OutputType::SpirvAssemblyText) {
299
0
    needs_linking_ = false;
300
0
    file_extension_ = ".spv";
301
0
  }
302
0
}
303
304
760
void FileCompiler::SetDisassemblyFlag() {
305
760
  if (!PreprocessingOnly()) {
306
0
    output_type_ = OutputType::SpirvAssemblyText;
307
0
    needs_linking_ = false;
308
0
    file_extension_ = ".spvasm";
309
0
  }
310
760
}
311
312
760
void FileCompiler::SetPreprocessingOnlyFlag() {
313
760
  output_type_ = OutputType::PreprocessedText;
314
760
  needs_linking_ = false;
315
760
  if (output_file_name_.empty()) {
316
0
    output_file_name_ = "-";
317
0
  }
318
760
}
319
320
760
bool FileCompiler::ValidateOptions(size_t num_files) {
321
760
  if (num_files == 0) {
322
0
    std::cerr << "glslc: error: no input files" << std::endl;
323
0
    return false;
324
0
  }
325
326
760
  if (num_files > 1 && needs_linking_) {
327
0
    std::cerr << "glslc: error: linking multiple files is not supported yet. "
328
0
                 "Use -c to compile files individually."
329
0
              << std::endl;
330
0
    return false;
331
0
  }
332
333
  // If we are outputting many object files, we cannot specify -o. Also
334
  // if we are preprocessing multiple files they must be to stdout.
335
760
  if (num_files > 1 && ((!PreprocessingOnly() && !needs_linking_ &&
336
0
                         !output_file_name_.empty()) ||
337
0
                        (PreprocessingOnly() && output_file_name_ != "-"))) {
338
0
    std::cerr << "glslc: error: cannot specify -o when generating multiple"
339
0
                 " output files"
340
0
              << std::endl;
341
0
    return false;
342
0
  }
343
344
  // If we have dependency info dumping handler instantiated, we should check
345
  // its validity.
346
760
  if (dependency_info_dumping_handler_) {
347
0
    std::string dependency_info_dumping_hander_error_msg;
348
0
    if (!dependency_info_dumping_handler_->IsValid(
349
0
            &dependency_info_dumping_hander_error_msg, num_files)) {
350
0
      std::cerr << "glslc: error: " << dependency_info_dumping_hander_error_msg
351
0
                << std::endl;
352
0
      return false;
353
0
    }
354
0
  }
355
356
  // If the output format is specified to be a binary, a list of hex numbers or
357
  // a C-style initializer list, the output must be in SPIR-V binary code form.
358
760
  if (binary_emission_format_ != SpirvBinaryEmissionFormat::Unspecified) {
359
760
    if (output_type_ != OutputType::SpirvBinary) {
360
760
      std::cerr << "glslc: error: cannot emit output as a ";
361
760
      switch (binary_emission_format_) {
362
0
        case SpirvBinaryEmissionFormat::Binary:
363
0
          std::cerr << "binary";
364
0
          break;
365
0
        case SpirvBinaryEmissionFormat::Numbers:
366
0
          std::cerr << "list of hex numbers";
367
0
          break;
368
0
        case SpirvBinaryEmissionFormat::CInitList:
369
0
          std::cerr << "C-style initializer list";
370
0
          break;
371
760
        case SpirvBinaryEmissionFormat::WGSL:
372
760
          std::cerr << "WGSL source program";
373
760
          break;
374
0
        case SpirvBinaryEmissionFormat::Unspecified:
375
          // The compiler should never be here at runtime. This case is added to
376
          // complete the switch cases.
377
0
          break;
378
760
      }
379
760
      std::cerr << " when only preprocessing the source" << std::endl;
380
760
      return false;
381
760
    }
382
0
    if (dependency_info_dumping_handler_ &&
383
0
        dependency_info_dumping_handler_->DumpingAsCompilationOutput()) {
384
0
      std::cerr << "glslc: error: cannot dump dependency info when specifying "
385
0
                   "any binary output format"
386
0
                << std::endl;
387
0
      return false;
388
0
    }
389
0
  }
390
391
0
  if (binary_emission_format_ == SpirvBinaryEmissionFormat::WGSL) {
392
0
#if SHADERC_ENABLE_WGSL_OUTPUT != 1
393
0
    std::cerr << "glslc: error: can't output WGSL: glslc was built without "
394
0
                 "WGSL output support"
395
0
              << std::endl;
396
0
    return false;
397
0
#endif
398
0
  }
399
400
0
  return true;
401
0
}
402
403
0
void FileCompiler::OutputMessages() {
404
0
  shaderc_util::OutputMessages(&std::cerr, total_warnings_, total_errors_);
405
0
}
406
407
2.28k
std::string FileCompiler::GetOutputFileName(std::string input_filename) {
408
2.28k
  if (output_file_name_.empty()) {
409
0
    return needs_linking_ ? std::string("a.spv")
410
0
                          : GetCandidateOutputFileName(input_filename);
411
2.28k
  } else {
412
2.28k
    return output_file_name_.str();
413
2.28k
  }
414
2.28k
}
415
416
std::string FileCompiler::GetCandidateOutputFileName(
417
0
    std::string input_filename) {
418
0
  if (!output_file_name_.empty() && !PreprocessingOnly()) {
419
0
    return output_file_name_.str();
420
0
  }
421
422
0
  std::string extension = file_extension_;
423
0
  if (PreprocessingOnly() || needs_linking_) {
424
0
    extension = ".spv";
425
0
  }
426
427
0
  std::string candidate_output_file_name =
428
0
      IsStageFile(input_filename)
429
0
          ? shaderc_util::GetBaseFileName(input_filename) + extension
430
0
          : shaderc_util::GetBaseFileName(
431
0
                input_filename.substr(0, input_filename.find_last_of('.')) +
432
0
                extension);
433
0
  return candidate_output_file_name;
434
0
}
435
}  // namesapce glslc