浏览代码

`spirv-remap`: Support outputting each SPIR-V module to a filename

The `spirv-remap` tool now supports two output modes:
  * Outputting one or more inputs to a single directory -- the previous
    behavior
  * One output file per input -- new behavior.
Allan MacKinnon 2 年之前
父节点
当前提交
c8c669fc2a
共有 1 个文件被更改,包括 61 次插入32 次删除
  1. 61 32
      StandAlone/spirv-remap.cpp

+ 61 - 32
StandAlone/spirv-remap.cpp

@@ -37,7 +37,11 @@
 #include <fstream>
 #include <fstream>
 #include <cstring>
 #include <cstring>
 #include <stdexcept>
 #include <stdexcept>
+#include <filesystem>
 
 
+//
+// Include remapper
+//
 #include "../SPIRV/SPVRemapper.h"
 #include "../SPIRV/SPVRemapper.h"
 
 
 namespace {
 namespace {
@@ -172,7 +176,7 @@ namespace {
             << " [--strip-all | --strip all | -s]"
             << " [--strip-all | --strip all | -s]"
             << " [--strip-white-list]"
             << " [--strip-white-list]"
             << " [--do-everything]"
             << " [--do-everything]"
-            << " --input | -i file1 [file2...] --output|-o DESTDIR"
+            << " --input | -i file1 [file2...] --output|-o DESTDIR | destfile1 [destfile2...]"
             << std::endl;
             << std::endl;
 
 
         std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;
         std::cout << "  " << basename(name) << " [--version | -V]" << std::endl;
@@ -182,32 +186,45 @@ namespace {
     }
     }
 
 
     // grind through each SPIR in turn
     // grind through each SPIR in turn
-    void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
-                 const std::string& whiteListFile, int opts, int verbosity)
+    void execute(const std::vector<std::string>& inputFiles,
+                 const std::vector<std::string>& outputDirOrFiles,
+                 const bool                      isSingleOutputDir,
+                 const std::string&              whiteListFile,
+                 int                             opts,
+                 int                             verbosity)
     {
     {
         std::vector<std::string> whiteListStrings;
         std::vector<std::string> whiteListStrings;
-        if(!whiteListFile.empty())
+        if (!whiteListFile.empty())
             read(whiteListStrings, whiteListFile, verbosity);
             read(whiteListStrings, whiteListFile, verbosity);
 
 
-        for (auto it = inputFile.cbegin(); it != inputFile.cend(); ++it) {
-            const std::string &filename = *it;
+        for (std::size_t ii=0; ii<inputFiles.size(); ii++) {
             std::vector<SpvWord> spv;
             std::vector<SpvWord> spv;
-            read(spv, filename, verbosity);
+            read(spv, inputFiles[ii], verbosity);
+
             spv::spirvbin_t(verbosity).remap(spv, whiteListStrings, opts);
             spv::spirvbin_t(verbosity).remap(spv, whiteListStrings, opts);
-            const std::string outfile = outputDir + path_sep_char() + basename(filename);
-            write(spv, outfile, verbosity);
+
+            if (isSingleOutputDir) {
+                // write all outputs to same directory
+                const std::string outFile = outputDirOrFiles[0] + path_sep_char() + basename(inputFiles[ii]);
+                write(spv, outFile, verbosity);
+            } else {
+                // write each input to its associated output
+                write(spv, outputDirOrFiles[ii], verbosity);
+            }
         }
         }
 
 
         if (verbosity > 0)
         if (verbosity > 0)
-            std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
+            std::cout << "Done: " << inputFiles.size() << " file(s) processed" << std::endl;
     }
     }
 
 
     // Parse command line options
     // Parse command line options
-    void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
-        std::string& outputDir,
-        std::string& stripWhiteListFile,
-        int& options,
-        int& verbosity)
+    void parseCmdLine(int argc,
+                      char** argv,
+                      std::vector<std::string>& inputFiles,
+                      std::vector<std::string>& outputDirOrFiles,
+                      std::string& stripWhiteListFile,
+                      int& options,
+                      int& verbosity)
     {
     {
         if (argc < 2)
         if (argc < 2)
             usage(argv[0]);
             usage(argv[0]);
@@ -222,18 +239,19 @@ namespace {
             const std::string arg = argv[a];
             const std::string arg = argv[a];
 
 
             if (arg == "--output" || arg == "-o") {
             if (arg == "--output" || arg == "-o") {
-                // Output directory
-                if (++a >= argc)
-                    usage(argv[0], "--output requires an argument");
-                if (!outputDir.empty())
-                    usage(argv[0], "--output can be provided only once");
-
-                outputDir = argv[a++];
+                // Collect output dirs or files
+                for (++a; a < argc && argv[a][0] != '-'; ++a)
+                    outputDirOrFiles.push_back(argv[a]);
 
 
-                // Remove trailing directory separator characters
-                while (!outputDir.empty() && outputDir.back() == path_sep_char())
-                    outputDir.pop_back();
+                if (outputDirOrFiles.size() == 0)
+                    usage(argv[0], "--output requires an argument");
 
 
+                // Remove trailing directory separator characters from all paths
+                for (std::size_t ii=0; ii<outputDirOrFiles.size(); ii++) {
+                    auto path = outputDirOrFiles[ii];
+                    while (!path.empty() && path.back() == path_sep_char())
+                        path.pop_back();
+                }
             }
             }
             else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts
             else if (arg == "-vv")     { verbosity = 2; ++a; } // verbosity shortcuts
             else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...
             else if (arg == "-vvv")    { verbosity = 3; ++a; } // ...
@@ -262,7 +280,7 @@ namespace {
             } else if (arg == "--input" || arg == "-i") {
             } else if (arg == "--input" || arg == "-i") {
                 // Collect input files
                 // Collect input files
                 for (++a; a < argc && argv[a][0] != '-'; ++a)
                 for (++a; a < argc && argv[a][0] != '-'; ++a)
-                    inputFile.push_back(argv[a]);
+                    inputFiles.push_back(argv[a]);
             } else if (arg == "--do-everything") {
             } else if (arg == "--do-everything") {
                 ++a;
                 ++a;
                 options = options | spv::spirvbin_t::DO_EVERYTHING;
                 options = options | spv::spirvbin_t::DO_EVERYTHING;
@@ -346,8 +364,8 @@ namespace {
 
 
 int main(int argc, char** argv)
 int main(int argc, char** argv)
 {
 {
-    std::vector<std::string> inputFile;
-    std::string              outputDir;
+    std::vector<std::string> inputFiles;
+    std::vector<std::string> outputDirOrFiles;
     std::string              whiteListFile;
     std::string              whiteListFile;
     int                      opts;
     int                      opts;
     int                      verbosity;
     int                      verbosity;
@@ -361,13 +379,24 @@ int main(int argc, char** argv)
     if (argc < 2)
     if (argc < 2)
         usage(argv[0]);
         usage(argv[0]);
 
 
-    parseCmdLine(argc, argv, inputFile, outputDir, whiteListFile, opts, verbosity);
+    parseCmdLine(argc, argv, inputFiles, outputDirOrFiles, whiteListFile, opts, verbosity);
+
+    if (outputDirOrFiles.empty())
+        usage(argv[0], "Output directory or file(s) required.");
+
+    const bool isMultiInput      = inputFiles.size() > 1;
+    const bool isMultiOutput     = outputDirOrFiles.size() > 1;
+    const bool isSingleOutputDir = !isMultiOutput && std::filesystem::is_directory(outputDirOrFiles[0]);
+
+    if (isMultiInput && !isMultiOutput && !isSingleOutputDir)
+        usage(argv[0], "Output is not a directory.");
+
 
 
-    if (outputDir.empty())
-        usage(argv[0], "Output directory required");
+    if (isMultiInput && isMultiOutput && (outputDirOrFiles.size() != inputFiles.size()))
+        usage(argv[0], "Output must be either a single directory or one output file per input.");
 
 
     // Main operations: read, remap, and write.
     // Main operations: read, remap, and write.
-    execute(inputFile, outputDir, whiteListFile, opts, verbosity);
+    execute(inputFiles, outputDirOrFiles, isSingleOutputDir, whiteListFile, opts, verbosity);
 
 
     // If we get here, everything went OK!  Nothing more to be done.
     // If we get here, everything went OK!  Nothing more to be done.
 }
 }