Revert "Replace skslc worklist files with -- delimited command lines."
This reverts commit 3e1b771ce4
.
Reason for revert: Not working on Windows.
Original change's description:
> Replace skslc worklist files with -- delimited command lines.
>
> Command lines with delimiters are a simpler approach; they don't require
> a scratch file to be created and parsed. (I didn't consider this
> approach until after implementing worklists.)
>
> This also fixes a minor issue with result codes when processing multiple
> files at once; in particular, unit tests can ignore compile errors, but
> regular fragment processor compilation should treat compile errors as
> fatal and stop the build.
>
> Change-Id: I3f153e7670d757c6b021bf60a260a2cd3f2090aa
> Bug: skia:10919
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334428
> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
> Auto-Submit: John Stiles <johnstiles@google.com>
TBR=brianosman@google.com,ethannicholas@google.com,johnstiles@google.com
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: skia:10919
Change-Id: I0e4bae8a8e09c61eac4e79453fd38e5e81b29e89
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/335858
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
c59e4486d5
commit
7b239054d9
@ -8,6 +8,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
skslc = sys.argv[1]
|
||||
clangFormat = sys.argv[2]
|
||||
@ -15,14 +16,14 @@ fetchClangFormat = sys.argv[3]
|
||||
processors = sys.argv[4:]
|
||||
|
||||
exeSuffix = '.exe' if sys.platform.startswith('win') else '';
|
||||
skslcArgs = [skslc]
|
||||
clangFormatArgs = [clangFormat, "--sort-includes=false", "-i"]
|
||||
targets = []
|
||||
worklist = tempfile.NamedTemporaryFile(suffix='.worklist')
|
||||
|
||||
# Fetch clang-format if it's not present already.
|
||||
if not os.path.isfile(clangFormat + exeSuffix):
|
||||
subprocess.check_call([sys.executable, fetchClangFormat]);
|
||||
|
||||
# Build argument lists for all the fragment processors that we want to compile.
|
||||
# Build a worklist of all the fragment processors that we want to compile.
|
||||
for p in processors:
|
||||
noExt, _ = os.path.splitext(p)
|
||||
head, tail = os.path.split(noExt)
|
||||
@ -30,27 +31,26 @@ for p in processors:
|
||||
if not os.path.isdir(targetDir):
|
||||
os.mkdir(targetDir)
|
||||
target = os.path.join(targetDir, tail)
|
||||
clangFormatArgs.append(target + ".h")
|
||||
clangFormatArgs.append(target + ".cpp")
|
||||
skslcArgs.append("--");
|
||||
skslcArgs.append(p);
|
||||
skslcArgs.append(target + ".h");
|
||||
skslcArgs.append("--");
|
||||
skslcArgs.append(p);
|
||||
skslcArgs.append(target + ".cpp");
|
||||
targets.append(target + ".h")
|
||||
targets.append(target + ".cpp")
|
||||
|
||||
# Invoke skslc on every target that needs to be compiled.
|
||||
worklist.write(p + "\n")
|
||||
worklist.write(target + ".h\n\n")
|
||||
worklist.write(p + "\n")
|
||||
worklist.write(target + ".cpp\n\n")
|
||||
|
||||
# Invoke skslc, passing in the worklist.
|
||||
worklist.close()
|
||||
try:
|
||||
output = subprocess.check_output(skslcArgs, stderr=subprocess.STDOUT)
|
||||
output = subprocess.check_output([skslc, worklist.name], stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print("### skslc error:\n")
|
||||
print("\n".join(err.output.splitlines()))
|
||||
sys.exit(err.returncode)
|
||||
|
||||
# Invoke clang-format on every generated target.
|
||||
try:
|
||||
output = subprocess.check_output(clangFormatArgs, stderr=subprocess.STDOUT)
|
||||
output = subprocess.check_output([clangFormat, "--sort-includes=false", "-i"] + targets,
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print("### clang-format error:\n")
|
||||
print("\n".join(err.output.splitlines()))
|
||||
sys.exit(err.returncode)
|
||||
|
@ -8,6 +8,7 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
skslc = sys.argv[1]
|
||||
lang = sys.argv[2]
|
||||
@ -23,8 +24,8 @@ def makeEmptyFile(path):
|
||||
if settings != "--settings" and settings != "--nosettings":
|
||||
sys.exit("### Expected --settings or --nosettings, got " + settings)
|
||||
|
||||
skslcArgs = [skslc]
|
||||
targets = []
|
||||
worklist = tempfile.NamedTemporaryFile(suffix='.worklist')
|
||||
|
||||
# Convert the list of command-line inputs into a worklist file sfor skslc.
|
||||
for input in inputs:
|
||||
@ -41,36 +42,31 @@ for input in inputs:
|
||||
targets.append(target)
|
||||
|
||||
if lang == "--fp":
|
||||
skslcArgs.append("--")
|
||||
skslcArgs.append(input)
|
||||
skslcArgs.append(target + ".cpp")
|
||||
skslcArgs.append(settings)
|
||||
skslcArgs.append("--")
|
||||
skslcArgs.append(input)
|
||||
skslcArgs.append(target + ".h")
|
||||
skslcArgs.append(settings)
|
||||
worklist.write(input + "\n")
|
||||
worklist.write(target + ".cpp\n")
|
||||
worklist.write(settings + "\n\n")
|
||||
worklist.write(input + "\n")
|
||||
worklist.write(target + ".h\n")
|
||||
worklist.write(settings + "\n\n")
|
||||
elif lang == "--glsl":
|
||||
skslcArgs.append("--")
|
||||
skslcArgs.append(input)
|
||||
skslcArgs.append(target + ".glsl")
|
||||
skslcArgs.append(settings)
|
||||
worklist.write(input + "\n")
|
||||
worklist.write(target + ".glsl\n")
|
||||
worklist.write(settings + "\n\n")
|
||||
elif lang == "--metal":
|
||||
skslcArgs.append("--")
|
||||
skslcArgs.append(input)
|
||||
skslcArgs.append(target + ".metal")
|
||||
skslcArgs.append(settings)
|
||||
worklist.write(input + "\n")
|
||||
worklist.write(target + ".metal\n")
|
||||
worklist.write(settings + "\n\n")
|
||||
else:
|
||||
sys.exit("### Expected one of: --fp --glsl --metal, got " + lang)
|
||||
|
||||
# Invoke skslc on every target that needs to be compiled.
|
||||
# Invoke skslc, passing in the worklist.
|
||||
worklist.close()
|
||||
try:
|
||||
output = subprocess.check_output(skslcArgs, stderr=subprocess.STDOUT)
|
||||
output = subprocess.check_output([skslc, worklist.name], stderr=subprocess.STDOUT)
|
||||
|
||||
except subprocess.CalledProcessError as err:
|
||||
if err.returncode != 1:
|
||||
print("### skslc error:\n")
|
||||
print("\n".join(err.output.splitlines()))
|
||||
sys.exit(err.returncode)
|
||||
pass # Compile errors (exit code 1) are expected and normal in test code
|
||||
print("### skslc error:\n")
|
||||
print("\n".join(err.output.splitlines()))
|
||||
|
||||
# A special case cleanup pass, just for CPP and H files: if either one of these files starts with
|
||||
# `### Compilation failed`, its sibling should be replaced by an empty file. This improves clarity
|
||||
|
@ -33,13 +33,6 @@ namespace SkOpts {
|
||||
decltype(hash_fn) hash_fn = skslc_standalone::hash_fn;
|
||||
}
|
||||
|
||||
enum class ResultCode {
|
||||
kSuccess = 0,
|
||||
kCompileError = 1,
|
||||
kInputError = 2,
|
||||
kOutputError = 3,
|
||||
};
|
||||
|
||||
// Given the path to a file (e.g. src/gpu/effects/GrFooFragmentProcessor.fp) and the expected
|
||||
// filename prefix and suffix (e.g. "Gr" and ".fp"), returns the "base name" of the
|
||||
// file (in this case, 'FooFragmentProcessor'). If no match, returns the empty string.
|
||||
@ -209,7 +202,8 @@ static bool detect_shader_settings(const SkSL::String& text,
|
||||
* Displays a usage banner; used when the command line arguments don't make sense.
|
||||
*/
|
||||
static void show_usage() {
|
||||
printf("usage: skslc <input> <output> <flags> -- <input2> <output2> <flags> -- ...\n"
|
||||
printf("usage: skslc <input> <output> <flags>\n"
|
||||
" skslc <worklist>\n"
|
||||
"\n"
|
||||
"Allowed flags:\n"
|
||||
"--settings: honor embedded /*#pragma settings*/ comments.\n"
|
||||
@ -219,7 +213,7 @@ static void show_usage() {
|
||||
/**
|
||||
* Handle a single input.
|
||||
*/
|
||||
ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
int processCommand(std::vector<SkSL::String>& args, bool writeErrorsToOutputFile) {
|
||||
bool honorSettings = true;
|
||||
if (args.size() == 4) {
|
||||
// Handle four-argument case: `skslc in.sksl out.glsl --settings`
|
||||
@ -231,11 +225,11 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
} else {
|
||||
printf("unrecognized flag: %s\n\n", settingsArg.c_str());
|
||||
show_usage();
|
||||
return ResultCode::kInputError;
|
||||
return 1;
|
||||
}
|
||||
} else if (args.size() != 3) {
|
||||
show_usage();
|
||||
return ResultCode::kInputError;
|
||||
return 1;
|
||||
}
|
||||
|
||||
SkSL::Program::Kind kind;
|
||||
@ -253,7 +247,7 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
} else {
|
||||
printf("input filename must end in '.vert', '.frag', '.geom', '.fp', '.stage', or "
|
||||
"'.sksl'\n");
|
||||
return ResultCode::kInputError;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream in(inputPath);
|
||||
@ -261,27 +255,30 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
std::istreambuf_iterator<char>());
|
||||
if (in.rdstate()) {
|
||||
printf("error reading '%s'\n", inputPath.c_str());
|
||||
return ResultCode::kInputError;
|
||||
return 2;
|
||||
}
|
||||
|
||||
SkSL::Program::Settings settings;
|
||||
const SkSL::ShaderCapsClass* caps = &SkSL::standaloneCaps;
|
||||
if (honorSettings) {
|
||||
if (!detect_shader_settings(text, &settings, &caps)) {
|
||||
return ResultCode::kInputError;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
const SkSL::String& outputPath = args[2];
|
||||
auto emitCompileError = [&](SkSL::FileOutputStream& out, const char* errorText) {
|
||||
// Overwrite the compiler output, if any, with an error message.
|
||||
out.close();
|
||||
SkSL::FileOutputStream errorStream(outputPath);
|
||||
errorStream.writeText("### Compilation failed:\n\n");
|
||||
errorStream.writeText(errorText);
|
||||
errorStream.close();
|
||||
// Also emit the error directly to stdout.
|
||||
puts(errorText);
|
||||
if (writeErrorsToOutputFile) {
|
||||
// Overwrite the compiler output, if any, with an error message.
|
||||
out.close();
|
||||
SkSL::FileOutputStream errorStream(outputPath);
|
||||
errorStream.writeText("### Compilation failed:\n\n");
|
||||
errorStream.writeText(errorText);
|
||||
errorStream.close();
|
||||
} else {
|
||||
// Emit the error directly to stdout.
|
||||
puts(errorText);
|
||||
}
|
||||
};
|
||||
|
||||
if (outputPath.endsWith(".spirv")) {
|
||||
@ -289,89 +286,89 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
SkSL::Compiler compiler(caps);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toSPIRV(*program, out)) {
|
||||
emitCompileError(out, compiler.errorText().c_str());
|
||||
return ResultCode::kCompileError;
|
||||
return 3;
|
||||
}
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else if (outputPath.endsWith(".glsl")) {
|
||||
SkSL::FileOutputStream out(outputPath);
|
||||
SkSL::Compiler compiler(caps);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toGLSL(*program, out)) {
|
||||
emitCompileError(out, compiler.errorText().c_str());
|
||||
return ResultCode::kCompileError;
|
||||
return 3;
|
||||
}
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else if (outputPath.endsWith(".metal")) {
|
||||
SkSL::FileOutputStream out(outputPath);
|
||||
SkSL::Compiler compiler(caps);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toMetal(*program, out)) {
|
||||
emitCompileError(out, compiler.errorText().c_str());
|
||||
return ResultCode::kCompileError;
|
||||
return 3;
|
||||
}
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else if (outputPath.endsWith(".h")) {
|
||||
SkSL::FileOutputStream out(outputPath);
|
||||
SkSL::Compiler compiler(caps, SkSL::Compiler::kPermitInvalidStaticTests_Flag);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
settings.fReplaceSettings = false;
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toH(*program, base_name(inputPath.c_str(), "Gr", ".fp"), out)) {
|
||||
emitCompileError(out, compiler.errorText().c_str());
|
||||
return ResultCode::kCompileError;
|
||||
return 3;
|
||||
}
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else if (outputPath.endsWith(".cpp")) {
|
||||
SkSL::FileOutputStream out(outputPath);
|
||||
SkSL::Compiler compiler(caps, SkSL::Compiler::kPermitInvalidStaticTests_Flag);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
settings.fReplaceSettings = false;
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toCPP(*program, base_name(inputPath.c_str(), "Gr", ".fp"), out)) {
|
||||
emitCompileError(out, compiler.errorText().c_str());
|
||||
return ResultCode::kCompileError;
|
||||
return 3;
|
||||
}
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else if (outputPath.endsWith(".dehydrated.sksl")) {
|
||||
SkSL::FileOutputStream out(outputPath);
|
||||
SkSL::Compiler compiler(caps);
|
||||
if (!out.isValid()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
auto [symbols, elements] = compiler.loadModule(
|
||||
kind, SkSL::Compiler::MakeModulePath(inputPath.c_str()), nullptr);
|
||||
@ -391,29 +388,43 @@ ResultCode processCommand(std::vector<SkSL::String>& args) {
|
||||
baseName.c_str(), baseName.c_str());
|
||||
if (!out.close()) {
|
||||
printf("error writing '%s'\n", outputPath.c_str());
|
||||
return ResultCode::kOutputError;
|
||||
return 4;
|
||||
}
|
||||
} else {
|
||||
printf("expected output filename to end with '.spirv', '.glsl', '.cpp', '.h', or '.metal'");
|
||||
return ResultCode::kInputError; // the "output filename" is still an input argument
|
||||
return 1;
|
||||
}
|
||||
return ResultCode::kSuccess;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
// Search the command line for -- delimiters. When a -- is reached, we process one command.
|
||||
std::vector<SkSL::String> args = {argv[0]};
|
||||
auto resultCode = ResultCode::kSuccess;
|
||||
for (int index = 1; index < argc; ++index) {
|
||||
SkSL::String arg = argv[index];
|
||||
if (arg != "--") {
|
||||
/**
|
||||
* Processes multiple inputs in a single invocation of skslc.
|
||||
*/
|
||||
int processWorklist(const char* worklistPath) {
|
||||
SkSL::String inputPath(worklistPath);
|
||||
if (!inputPath.endsWith(".worklist")) {
|
||||
printf("expected .worklist file, found: %s\n\n", worklistPath);
|
||||
show_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The worklist contains one line per argument to pass to skslc. When a blank line is reached,
|
||||
// those arguments will be passed to `processCommand`.
|
||||
std::vector<SkSL::String> args = {"skslc"};
|
||||
std::ifstream in(worklistPath);
|
||||
for (SkSL::String line; std::getline(in, line); ) {
|
||||
if (in.rdstate()) {
|
||||
printf("error reading '%s'\n", worklistPath);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!line.empty()) {
|
||||
// We found an argument. Remember it.
|
||||
args.push_back(std::move(arg));
|
||||
args.push_back(std::move(line));
|
||||
} else {
|
||||
// We found a delimiter. If we have any arguments stored up, process them as a command.
|
||||
if (args.size() > 1) {
|
||||
ResultCode outcome = processCommand(args);
|
||||
resultCode = std::max(resultCode, outcome);
|
||||
// We found a blank line. If we have any arguments stored up, process them as a command.
|
||||
if (!args.empty()) {
|
||||
processCommand(args, /*writeErrorsToOutputFile=*/true);
|
||||
|
||||
// Clear every argument except the first ("skslc").
|
||||
args.resize(1);
|
||||
@ -421,14 +432,26 @@ int main(int argc, const char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the final command in the batch.
|
||||
// If the worklist ended with a list of arguments but no blank line, process those now.
|
||||
if (args.size() > 1) {
|
||||
ResultCode outcome = processCommand(args);
|
||||
resultCode = std::max(resultCode, outcome);
|
||||
processCommand(args, /*writeErrorsToOutputFile=*/true);
|
||||
}
|
||||
|
||||
// Return the "worst" status we encountered. For our purposes, compilation errors are the least
|
||||
// serious, because they are expected to occur in unit tests. Other types of errors are not
|
||||
// expected at all during a build.
|
||||
return (int) resultCode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
if (argc == 2) {
|
||||
// Worklists are the only two-argument case for skslc, and we don't intend to support
|
||||
// nested worklists, so we can process them here.
|
||||
return processWorklist(argv[1]);
|
||||
} else {
|
||||
// Process non-worklist inputs.
|
||||
std::vector<SkSL::String> args;
|
||||
for (int index=0; index<argc; ++index) {
|
||||
args.push_back(argv[index]);
|
||||
}
|
||||
|
||||
return processCommand(args, /*writeErrorsToOutputFile=*/false);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user