ShaderCompiler: Add --log-format option
This commit is contained in:
parent
106d629342
commit
e62969999a
|
|
@ -36,6 +36,9 @@ namespace Nz::ShaderLang
|
|||
#include <Nazara/Shader/ShaderLangErrorList.hpp>
|
||||
};
|
||||
|
||||
NAZARA_SHADER_API std::string_view ToString(ErrorCategory errorCategory);
|
||||
NAZARA_SHADER_API std::string_view ToString(ErrorType errorType);
|
||||
|
||||
class NAZARA_SHADER_API Error : public std::exception
|
||||
{
|
||||
public:
|
||||
|
|
@ -47,6 +50,7 @@ namespace Nz::ShaderLang
|
|||
inline ErrorCategory GetErrorCategory() const;
|
||||
const std::string& GetErrorMessage() const;
|
||||
inline ErrorType GetErrorType() const;
|
||||
const std::string& GetFullErrorMessage() const;
|
||||
inline const SourceLocation& GetSourceLocation() const;
|
||||
|
||||
const char* what() const noexcept override;
|
||||
|
|
@ -58,6 +62,7 @@ namespace Nz::ShaderLang
|
|||
virtual std::string BuildErrorMessage() const = 0;
|
||||
|
||||
private:
|
||||
mutable std::string m_fullErrorMessage;
|
||||
mutable std::string m_errorMessage;
|
||||
ErrorCategory m_errorCategory;
|
||||
SourceLocation m_sourceLocation;
|
||||
|
|
|
|||
|
|
@ -44,17 +44,7 @@ struct fmt::formatter<Nz::ShaderLang::ErrorCategory> : formatter<string_view>
|
|||
template <typename FormatContext>
|
||||
auto format(const Nz::ShaderLang::ErrorCategory& p, FormatContext& ctx) -> decltype(ctx.out())
|
||||
{
|
||||
// TODO: Add ToString
|
||||
std::string_view name = "<unhandled error category>";
|
||||
switch (p)
|
||||
{
|
||||
case Nz::ShaderLang::ErrorCategory::Ast: name = "Ast"; break;
|
||||
case Nz::ShaderLang::ErrorCategory::Compilation: name = "Compilation"; break;
|
||||
case Nz::ShaderLang::ErrorCategory::Lexing: name = "Lexing"; break;
|
||||
case Nz::ShaderLang::ErrorCategory::Parsing: name = "Parsing"; break;
|
||||
}
|
||||
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
return formatter<string_view>::format(ToString(p), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -64,16 +54,7 @@ struct fmt::formatter<Nz::ShaderLang::ErrorType> : formatter<string_view>
|
|||
template <typename FormatContext>
|
||||
auto format(const Nz::ShaderLang::ErrorType& p, FormatContext& ctx) -> decltype(ctx.out())
|
||||
{
|
||||
// TODO: Add ToString
|
||||
std::string_view name = "<unhandled error type>";
|
||||
switch (p)
|
||||
{
|
||||
#define NAZARA_SHADERLANG_ERROR(ErrorPrefix, ErrorName, ...) case Nz::ShaderLang::ErrorType:: ErrorPrefix ## ErrorName: name = #ErrorPrefix #ErrorName; break;
|
||||
|
||||
#include <Nazara/Shader/ShaderLangErrorList.hpp>
|
||||
}
|
||||
|
||||
return formatter<string_view>::format(name, ctx);
|
||||
return formatter<string_view>::format(ToString(p), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -107,9 +88,42 @@ struct fmt::formatter<Nz::ShaderLang::TokenType> : formatter<string_view>
|
|||
|
||||
namespace Nz::ShaderLang
|
||||
{
|
||||
std::string_view ToString(ErrorCategory errorCategory)
|
||||
{
|
||||
switch (errorCategory)
|
||||
{
|
||||
case ErrorCategory::Ast: return "Ast";
|
||||
case ErrorCategory::Compilation: return "Compilation";
|
||||
case ErrorCategory::Lexing: return "Lexing";
|
||||
case ErrorCategory::Parsing: return "Parsing";
|
||||
}
|
||||
|
||||
return "<unhandled error category>";
|
||||
}
|
||||
|
||||
std::string_view ToString(ErrorType errorType)
|
||||
{
|
||||
switch (errorType)
|
||||
{
|
||||
#define NAZARA_SHADERLANG_ERROR(ErrorPrefix, ErrorName, ...) case ErrorType:: ErrorPrefix ## ErrorName: return #ErrorPrefix #ErrorName;
|
||||
|
||||
#include <Nazara/Shader/ShaderLangErrorList.hpp>
|
||||
}
|
||||
|
||||
return "<unhandled error type>";
|
||||
}
|
||||
|
||||
const std::string& Error::GetErrorMessage() const
|
||||
{
|
||||
if (m_errorMessage.empty())
|
||||
m_errorMessage = BuildErrorMessage();
|
||||
|
||||
return m_errorMessage;
|
||||
}
|
||||
|
||||
const std::string& Error::GetFullErrorMessage() const
|
||||
{
|
||||
if (m_fullErrorMessage.empty())
|
||||
{
|
||||
if (m_sourceLocation.IsValid())
|
||||
{
|
||||
|
|
@ -118,22 +132,22 @@ namespace Nz::ShaderLang
|
|||
sourceFile = *m_sourceLocation.file;
|
||||
|
||||
if (m_sourceLocation.startLine != m_sourceLocation.endLine)
|
||||
m_errorMessage = fmt::format("{}({} -> {},{} -> {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.endLine, m_sourceLocation.startColumn, m_sourceLocation.endColumn, m_errorType, BuildErrorMessage());
|
||||
m_fullErrorMessage = fmt::format("{}({} -> {},{} -> {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.endLine, m_sourceLocation.startColumn, m_sourceLocation.endColumn, m_errorType, GetErrorMessage());
|
||||
else if (m_sourceLocation.startColumn != m_sourceLocation.endColumn)
|
||||
m_errorMessage = fmt::format("{}({},{} -> {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.startColumn, m_sourceLocation.endColumn, m_errorType, BuildErrorMessage());
|
||||
m_fullErrorMessage = fmt::format("{}({},{} -> {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.startColumn, m_sourceLocation.endColumn, m_errorType, GetErrorMessage());
|
||||
else
|
||||
m_errorMessage = fmt::format("{}({}, {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.startColumn, m_errorType, BuildErrorMessage());
|
||||
m_fullErrorMessage = fmt::format("{}({}, {}): {} error: {}", sourceFile, m_sourceLocation.startLine, m_sourceLocation.startColumn, m_errorType, GetErrorMessage());
|
||||
}
|
||||
else
|
||||
m_errorMessage = fmt::format("?: {} error: {}", m_errorType, BuildErrorMessage());
|
||||
m_fullErrorMessage = fmt::format("?: {} error: {}", m_errorType, GetErrorMessage());
|
||||
}
|
||||
|
||||
return m_errorMessage;
|
||||
return m_fullErrorMessage;
|
||||
}
|
||||
|
||||
const char* Error::what() const noexcept
|
||||
{
|
||||
return GetErrorMessage().c_str();
|
||||
return GetFullErrorMessage().c_str();
|
||||
}
|
||||
|
||||
#define NAZARA_SHADERLANG_NEWERRORTYPE(Prefix, ErrorType, ErrorName, ErrorString, ...) \
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@
|
|||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
enum class LogFormat
|
||||
{
|
||||
Classic,
|
||||
VisualStudio
|
||||
};
|
||||
|
||||
std::vector<Nz::UInt8> ReadFileContent(const std::filesystem::path& filePath)
|
||||
{
|
||||
Nz::File file(filePath);
|
||||
|
|
@ -53,6 +59,7 @@ int main(int argc, char* argv[])
|
|||
("c,compile", "Compile input shader")
|
||||
("output-nzsl", "Output shader as NZSL to stdout")
|
||||
("header-file", "Generate an includable header file")
|
||||
("log-format", "Set log format (classic, vs)", cxxopts::value<std::string>())
|
||||
("i,input", "Input file(s)", cxxopts::value<std::string>())
|
||||
("o,output", "Output path", cxxopts::value<std::string>()->default_value("."), "path")
|
||||
("p,partial", "Allow partial compilation")
|
||||
|
|
@ -74,14 +81,27 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (result.count("input") == 0)
|
||||
{
|
||||
fmt::print("no input file\n{}\n", options.help());
|
||||
fmt::print(stderr, "no input file\n{}\n", options.help());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
LogFormat logFormat = LogFormat::Classic;
|
||||
if (result.count("log-format") != 0)
|
||||
{
|
||||
const std::string& formatStr = result["log-format"].as<std::string>();
|
||||
if (formatStr == "vs")
|
||||
logFormat = LogFormat::VisualStudio;
|
||||
else if (formatStr != "classic")
|
||||
{
|
||||
fmt::print(stderr, "{} is not a file\n", formatStr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path inputPath = result["input"].as<std::string>();
|
||||
if (!std::filesystem::is_regular_file(inputPath))
|
||||
{
|
||||
fmt::print("{} is not a file\n", inputPath.generic_u8string());
|
||||
fmt::print(stderr, "{} is not a file\n", inputPath.generic_u8string());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
|
@ -153,62 +173,76 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
catch (const Nz::ShaderLang::Error& error)
|
||||
{
|
||||
fmt::print(stderr, (fmt::emphasis::bold | fg(fmt::color::red)), "{}\n", error.what());
|
||||
|
||||
Nz::ShaderLang::SourceLocation errorLocation = error.GetSourceLocation();
|
||||
const Nz::ShaderLang::SourceLocation& errorLocation = error.GetSourceLocation();
|
||||
if (errorLocation.IsValid())
|
||||
{
|
||||
try
|
||||
if (logFormat == LogFormat::Classic)
|
||||
{
|
||||
// Retrieve line
|
||||
std::string sourceContent = ReadSourceFileContent(*errorLocation.file);
|
||||
fmt::print(stderr, (fmt::emphasis::bold | fg(fmt::color::red)), "{}\n", error.what());
|
||||
|
||||
std::size_t lineStartOffset = 0;
|
||||
if (errorLocation.startLine > 1)
|
||||
try
|
||||
{
|
||||
lineStartOffset = sourceContent.find('\n') + 1;
|
||||
for (std::size_t i = 0; i < errorLocation.startLine - 2; ++i) //< remember startLine is 1-based
|
||||
// Retrieve line
|
||||
std::string sourceContent = ReadSourceFileContent(*errorLocation.file);
|
||||
|
||||
std::size_t lineStartOffset = 0;
|
||||
if (errorLocation.startLine > 1)
|
||||
{
|
||||
lineStartOffset = sourceContent.find('\n', lineStartOffset);
|
||||
if (lineStartOffset == std::string::npos)
|
||||
throw std::runtime_error("file content doesn't match original source");
|
||||
lineStartOffset = sourceContent.find('\n') + 1;
|
||||
for (std::size_t i = 0; i < errorLocation.startLine - 2; ++i) //< remember startLine is 1-based
|
||||
{
|
||||
lineStartOffset = sourceContent.find('\n', lineStartOffset);
|
||||
if (lineStartOffset == std::string::npos)
|
||||
throw std::runtime_error("file content doesn't match original source");
|
||||
|
||||
++lineStartOffset;
|
||||
++lineStartOffset;
|
||||
}
|
||||
}
|
||||
std::size_t lineEndOffset = sourceContent.find('\n', lineStartOffset);
|
||||
|
||||
std::string errorLine = sourceContent.substr(lineStartOffset, lineEndOffset - lineStartOffset);
|
||||
|
||||
// handle tabs
|
||||
Nz::UInt32 startColumn = errorLocation.startColumn - 1;
|
||||
std::size_t startPos = 0;
|
||||
while ((startPos = errorLine.find('\t', startPos)) != std::string::npos)
|
||||
{
|
||||
if (startPos < startColumn)
|
||||
startColumn += 3;
|
||||
|
||||
errorLine.replace(startPos, 1, " ");
|
||||
startPos += 4;
|
||||
}
|
||||
|
||||
std::size_t columnSize;
|
||||
if (errorLocation.startLine == errorLocation.endLine)
|
||||
columnSize = errorLocation.endColumn - errorLocation.startColumn + 1;
|
||||
else
|
||||
columnSize = 1;
|
||||
|
||||
std::string lineStr = std::to_string(errorLocation.startLine);
|
||||
|
||||
fmt::print(stderr, " {} | {}\n", lineStr, errorLine);
|
||||
fmt::print(stderr, " {} | {}", std::string(lineStr.size(), ' '), std::string(startColumn, ' '));
|
||||
fmt::print(stderr, fg(fmt::color::green), "{}\n", std::string(columnSize, '^'));
|
||||
}
|
||||
std::size_t lineEndOffset = sourceContent.find('\n', lineStartOffset);
|
||||
|
||||
std::string errorLine = sourceContent.substr(lineStartOffset, lineEndOffset - lineStartOffset);
|
||||
|
||||
// handle tabs
|
||||
Nz::UInt32 startColumn = errorLocation.startColumn - 1;
|
||||
std::size_t startPos = 0;
|
||||
while ((startPos = errorLine.find("\t", startPos)) != std::string::npos)
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
if (startPos < startColumn)
|
||||
startColumn += 3;
|
||||
|
||||
errorLine.replace(startPos, 1, " ");
|
||||
startPos += 4;
|
||||
fmt::print(stderr, "failed to print error line: {}\n", e.what());
|
||||
}
|
||||
|
||||
std::size_t columnSize;
|
||||
if (errorLocation.startLine == errorLocation.endLine)
|
||||
columnSize = errorLocation.endColumn - errorLocation.startColumn + 1;
|
||||
else
|
||||
columnSize = 1;
|
||||
|
||||
std::string lineStr = std::to_string(errorLocation.startLine);
|
||||
|
||||
fmt::print(stderr, " {} | {}\n", lineStr, errorLine);
|
||||
fmt::print(stderr, " {} | {}", std::string(lineStr.size(), ' '), std::string(startColumn, ' '));
|
||||
fmt::print(stderr, fg(fmt::color::green), "{}\n", std::string(columnSize, '^'));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
else if (logFormat == LogFormat::VisualStudio)
|
||||
{
|
||||
fmt::print(stderr, "failed to print error line: {}\n", e.what());
|
||||
// VS requires absolute path
|
||||
std::filesystem::path fullPath;
|
||||
if (errorLocation.file)
|
||||
fullPath = std::filesystem::absolute(*errorLocation.file);
|
||||
|
||||
fmt::print(stderr, "{}({},{}): error {}: {}\n", fullPath.generic_u8string(), errorLocation.startLine, errorLocation.startColumn, ToString(error.GetErrorType()), error.GetErrorMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
fmt::print(stderr, (fmt::emphasis::bold | fg(fmt::color::red)), "{}\n", error.what());
|
||||
}
|
||||
}
|
||||
catch (const cxxopts::OptionException& e)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
-- Turns resources into includables headers
|
||||
-- Compile shaders to includables headers
|
||||
rule("compile_shaders")
|
||||
on_load(function (target)
|
||||
target:add("deps", "NazaraShaderCompiler")
|
||||
|
|
@ -22,7 +22,7 @@ rule("compile_shaders")
|
|||
|
||||
-- add commands
|
||||
batchcmds:show_progress(opt.progress, "${color.build.object}compiling shader %s", shaderfile)
|
||||
local argv = {"--compile", "--partial", "--header-file", shaderfile}
|
||||
local argv = {"--compile", "--partial", "--header-file", "--log-format=vs", shaderfile}
|
||||
batchcmds:vrunv(nzslc:targetfile(), argv, { curdir = "." })
|
||||
|
||||
local outputFile = path.join(path.directory(shaderfile), path.basename(shaderfile) .. ".nzslb.h")
|
||||
|
|
|
|||
Loading…
Reference in New Issue