yum-mirror/glslang

git clone https://git.yummers.dev/yum-mirror/glslang

Christoph NeuhauserAdd SPIR-V debug option to emit only the source file namee0735231

main
97.1 KiB2340 linesraw
1//
2// Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3// Copyright (C) 2013-2016 LunarG, Inc.
4// Copyright (C) 2016-2020 Google, Inc.
5// Modifications Copyright(C) 2021 Advanced Micro Devices, Inc.All rights reserved.
6//
7// All rights reserved.
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions
11// are met:
12//
13//    Redistributions of source code must retain the above copyright
14//    notice, this list of conditions and the following disclaimer.
15//
16//    Redistributions in binary form must reproduce the above
17//    copyright notice, this list of conditions and the following
18//    disclaimer in the documentation and/or other materials provided
19//    with the distribution.
20//
21//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22//    contributors may be used to endorse or promote products derived
23//    from this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36// POSSIBILITY OF SUCH DAMAGE.
37//
38
39// this only applies to the standalone wrapper, not the front end in general
40#ifndef _CRT_SECURE_NO_WARNINGS
41#define _CRT_SECURE_NO_WARNINGS
42#endif
43
44#include "glslang/Public/ResourceLimits.h"
45#include "Worklist.h"
46#include "DirStackFileIncluder.h"
47#include "./../glslang/Public/ShaderLang.h"
48#include "../glslang/MachineIndependent/localintermediate.h"
49#include "../SPIRV/GlslangToSpv.h"
50#include "../SPIRV/GLSL.std.450.h"
51#include "../SPIRV/disassemble.h"
52
53#include <array>
54#include <atomic>
55#include <cctype>
56#include <cmath>
57#include <cstdlib>
58#include <cstring>
59#include <filesystem>
60#include <iterator>
61#include <map>
62#include <memory>
63#include <set>
64#include <thread>
65#include <type_traits>
66
67#include "../glslang/OSDependent/osinclude.h"
68
69// Build-time generated includes
70#include "glslang/build_info.h"
71
72#include "glslang/glsl_intrinsic_header.h"
73
74extern "C" {
75    GLSLANG_EXPORT void ShOutputHtml();
76}
77
78// Command-line options
79enum TOptions : uint64_t {
80    EOptionNone = 0,
81    EOptionIntermediate = (1ull << 0),
82    EOptionSuppressInfolog = (1ull << 1),
83    EOptionMemoryLeakMode = (1ull << 2),
84    EOptionRelaxedErrors = (1ull << 3),
85    EOptionGiveWarnings = (1ull << 4),
86    EOptionLinkProgram = (1ull << 5),
87    EOptionMultiThreaded = (1ull << 6),
88    EOptionDumpConfig = (1ull << 7),
89    EOptionDumpReflection = (1ull << 8),
90    EOptionSuppressWarnings = (1ull << 9),
91    EOptionDumpVersions = (1ull << 10),
92    EOptionSpv = (1ull << 11),
93    EOptionHumanReadableSpv = (1ull << 12),
94    EOptionVulkanRules = (1ull << 13),
95    EOptionDefaultDesktop = (1ull << 14),
96    EOptionOutputPreprocessed = (1ull << 15),
97    EOptionOutputHexadecimal = (1ull << 16),
98    EOptionReadHlsl = (1ull << 17),
99    EOptionCascadingErrors = (1ull << 18),
100    EOptionAutoMapBindings = (1ull << 19),
101    EOptionFlattenUniformArrays = (1ull << 20),
102    EOptionNoStorageFormat = (1ull << 21),
103    EOptionKeepUncalled = (1ull << 22),
104    EOptionHlslOffsets = (1ull << 23),
105    EOptionHlslIoMapping = (1ull << 24),
106    EOptionAutoMapLocations = (1ull << 25),
107    EOptionDebug = (1ull << 26),
108    EOptionStdin = (1ull << 27),
109    EOptionOptimizeDisable = (1ull << 28),
110    EOptionOptimizeSize = (1ull << 29),
111    EOptionInvertY = (1ull << 30),
112    EOptionDumpBareVersion = (1ull << 31),
113    EOptionCompileOnly = (1ull << 32),
114    EOptionDisplayErrorColumn = (1ull << 33),
115    EOptionLinkTimeOptimization = (1ull << 34),
116    EOptionValidateCrossStageIO = (1ull << 35),
117    EOptionBindingsPerResourceType = (1ull << 36),
118    EOptionRelaxSetBindingLimits = (1ull << 37),
119    EOptionDiscardIsTerminate = (1ull << 38),
120    EOptionOptimizePerformance = (1ull << 39),
121};
122bool targetHlslFunctionality1 = false;
123bool SpvToolsDisassembler = false;
124bool SpvToolsValidate = false;
125bool NaNClamp = false;
126bool stripDebugInfo = false;
127bool emitNonSemanticShaderDebugInfo = false;
128bool emitNonSemanticShaderDebugSource = false;
129bool emitSourceFileName = false;
130bool beQuiet = false;
131bool VulkanRulesRelaxed = false;
132bool autoSampledTextures = false;
133
134//
135// Return codes from main/exit().
136//
137enum TFailCode {
138    ESuccess = 0,
139    EFailUsage,
140    EFailCompile,
141    EFailLink,
142    EFailCompilerCreate,
143    EFailThreadCreate,
144    EFailLinkerCreate
145};
146
147//
148// Forward declarations.
149//
150EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true);
151void CompileFile(const char* fileName, ShHandle);
152void usage();
153char* ReadFileData(const char* fileName);
154void FreeFileData(char* data);
155void InfoLogMsg(const char* msg, const char* name, const int num);
156
157// Globally track if any compile or link failure.
158std::atomic<int8_t> CompileFailed{0};
159std::atomic<int8_t> LinkFailed{0};
160std::atomic<int8_t> CompileOrLinkFailed{0};
161
162// array of unique places to leave the shader names and infologs for the asynchronous compiles
163std::vector<std::unique_ptr<glslang::TWorkItem>> WorkItems;
164
165std::string ConfigFile;
166
167//
168// Parse either a .conf file provided by the user or the default from glslang::DefaultTBuiltInResource
169//
170void ProcessConfigFile()
171{
172    if (ConfigFile.size() == 0)
173        *GetResources() = *GetDefaultResources();
174    else {
175        char* configString = ReadFileData(ConfigFile.c_str());
176        DecodeResourceLimits(GetResources(),  configString);
177        FreeFileData(configString);
178    }
179}
180
181int ReflectOptions = EShReflectionDefault;
182std::underlying_type_t<TOptions> Options = EOptionNone;
183const char* ExecutableName = nullptr;
184const char* binaryFileName = nullptr;
185const char* depencyFileName = nullptr;
186const char* entryPointName = nullptr;
187const char* sourceEntryPointName = nullptr;
188const char* shaderStageName = nullptr;
189const char* variableName = nullptr;
190bool HlslEnable16BitTypes = false;
191bool HlslDX9compatible = false;
192bool HlslDxPositionW = false;
193bool EnhancedMsgs = false;
194bool AbsolutePath = false;
195bool DumpBuiltinSymbols = false;
196std::vector<std::string> IncludeDirectoryList;
197
198// Source environment
199// (source 'Client' is currently the same as target 'Client')
200int ClientInputSemanticsVersion = 100;
201
202// Target environment
203glslang::EShClient Client = glslang::EShClientNone;  // will stay EShClientNone if only validating
204glslang::EShTargetClientVersion ClientVersion;       // not valid until Client is set
205glslang::EShTargetLanguage TargetLanguage = glslang::EShTargetNone;
206glslang::EShTargetLanguageVersion TargetVersion;     // not valid until TargetLanguage is set
207
208// GLSL version
209int GlslVersion = 0; // GLSL version specified on CLI, overrides #version in shader source
210
211std::vector<std::string> Processes;                     // what should be recorded by OpModuleProcessed, or equivalent
212std::string CommandLineArguments;                       // original arguments passed to the standalone compiler
213
214// Per descriptor-set binding base data
215typedef std::map<unsigned int, unsigned int> TPerSetBaseBinding;
216
217std::vector<std::pair<std::string, int>> uniformLocationOverrides;
218int uniformBase = 0;
219
220std::array<std::array<unsigned int, EShLangCount>, glslang::EResCount> baseBinding;
221std::array<std::array<TPerSetBaseBinding, EShLangCount>, glslang::EResCount> baseBindingForSet;
222std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
223
224std::vector<std::pair<std::string, glslang::TBlockStorageClass>> blockStorageOverrides;
225
226bool setGlobalUniformBlock = false;
227std::string globalUniformName;
228unsigned int globalUniformBinding;
229unsigned int globalUniformSet;
230
231bool setGlobalBufferBlock = false;
232std::string atomicCounterBlockName;
233unsigned int atomicCounterBlockSet;
234
235// Add things like "#define ..." to a preamble to use in the beginning of the shader.
236class TPreamble {
237public:
238    TPreamble() { }
239
240    bool isSet() const { return text.size() > 0; }
241    const char* get() const { return text.c_str(); }
242
243    // #define...
244    void addDef(std::string def)
245    {
246        text.append("#define ");
247        fixLine(def);
248
249        Processes.push_back("define-macro ");
250        Processes.back().append(def);
251
252        // The first "=" needs to turn into a space
253        const size_t equal = def.find_first_of("=");
254        if (equal != def.npos)
255            def[equal] = ' ';
256
257        text.append(def);
258        text.append("\n");
259    }
260
261    // #undef...
262    void addUndef(std::string undef)
263    {
264        text.append("#undef ");
265        fixLine(undef);
266
267        Processes.push_back("undef-macro ");
268        Processes.back().append(undef);
269
270        text.append(undef);
271        text.append("\n");
272    }
273
274    void addText(std::string preambleText)
275    {
276        fixLine(preambleText);
277
278        Processes.push_back("preamble-text");
279        Processes.back().append(preambleText);
280
281        text.append(preambleText);
282        text.append("\n");
283    }
284
285protected:
286    void fixLine(std::string& line)
287    {
288        // Can't go past a newline in the line
289        const size_t end = line.find_first_of("\n");
290        if (end != line.npos)
291            line = line.substr(0, end);
292    }
293
294    std::string text;  // contents of preamble
295};
296
297// Track the user's #define and #undef from the command line.
298TPreamble UserPreamble;
299std::string PreambleString;
300
301//
302// Create the default name for saving a binary if -o is not provided.
303//
304const char* GetBinaryName(EShLanguage stage)
305{
306    const char* name;
307    if (binaryFileName == nullptr) {
308        switch (stage) {
309        case EShLangVertex:          name = "vert.spv";    break;
310        case EShLangTessControl:     name = "tesc.spv";    break;
311        case EShLangTessEvaluation:  name = "tese.spv";    break;
312        case EShLangGeometry:        name = "geom.spv";    break;
313        case EShLangFragment:        name = "frag.spv";    break;
314        case EShLangCompute:         name = "comp.spv";    break;
315        case EShLangRayGen:          name = "rgen.spv";    break;
316        case EShLangIntersect:       name = "rint.spv";    break;
317        case EShLangAnyHit:          name = "rahit.spv";   break;
318        case EShLangClosestHit:      name = "rchit.spv";   break;
319        case EShLangMiss:            name = "rmiss.spv";   break;
320        case EShLangCallable:        name = "rcall.spv";   break;
321        case EShLangMesh :           name = "mesh.spv";    break;
322        case EShLangTask :           name = "task.spv";    break;
323        default:                     name = "unknown";     break;
324        }
325    } else
326        name = binaryFileName;
327
328    return name;
329}
330
331//
332// *.conf => this is a config file that can set limits/resources
333//
334bool SetConfigFile(const std::string& name)
335{
336    if (name.size() < 5)
337        return false;
338
339    if (name.compare(name.size() - 5, 5, ".conf") == 0) {
340        ConfigFile = name;
341        return true;
342    }
343
344    return false;
345}
346
347//
348// Give error and exit with failure code.
349//
350void Error(const char* message, const char* detail = nullptr)
351{
352    fprintf(stderr, "%s: Error: ", ExecutableName);
353    if (detail != nullptr)
354        fprintf(stderr, "%s: ", detail);
355    fprintf(stderr, "%s (use -h for usage)\n", message);
356    exit(EFailUsage);
357}
358
359//
360// Process an optional binding base of one the forms:
361//   --argname [stage] base            // base for stage (if given) or all stages (if not)
362//   --argname [stage] [base set]...   // set/base pairs: set the base for given binding set.
363
364// Where stage is one of the forms accepted by FindLanguage, and base is an integer
365//
366void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res)
367{
368    if (argc < 2)
369        usage();
370
371    EShLanguage lang = EShLangCount;
372    int singleBase = 0;
373    TPerSetBaseBinding perSetBase;
374    int arg = 1;
375
376    // Parse stage, if given
377    if (!isdigit(argv[arg][0])) {
378        if (argc < 3) // this form needs one more argument
379            usage();
380
381        lang = FindLanguage(argv[arg++], false);
382    }
383
384    if ((argc - arg) >= 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
385        // Parse a per-set binding base
386        do {
387            const int baseNum = atoi(argv[arg++]);
388            const int setNum = atoi(argv[arg++]);
389            perSetBase[setNum] = baseNum;
390        } while ((argc - arg) >= 2 && isdigit(argv[arg + 0][0]) && isdigit(argv[arg + 1][0]));
391    } else {
392        // Parse single binding base
393        singleBase = atoi(argv[arg++]);
394    }
395
396    argc -= (arg-1);
397    argv += (arg-1);
398
399    // Set one or all languages
400    const int langMin = (lang < EShLangCount) ? lang+0 : 0;
401    const int langMax = (lang < EShLangCount) ? lang+1 : EShLangCount;
402
403    for (int lang = langMin; lang < langMax; ++lang) {
404        if (!perSetBase.empty())
405            baseBindingForSet[res][lang].insert(perSetBase.begin(), perSetBase.end());
406        else
407            baseBinding[res][lang] = singleBase;
408    }
409}
410
411void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array<std::vector<std::string>, EShLangCount>& base)
412{
413    if (argc < 2)
414        usage();
415
416    if (!isdigit(argv[1][0])) {
417        if (argc < 3) // this form needs one more argument
418            usage();
419
420        // Parse form: --argname stage [regname set base...], or:
421        //             --argname stage set
422        const EShLanguage lang = FindLanguage(argv[1], false);
423
424        argc--;
425        argv++;
426
427        while (argc > 1 && argv[1] != nullptr && argv[1][0] != '-') {
428            base[lang].push_back(argv[1]);
429
430            argc--;
431            argv++;
432        }
433
434        // Must have one arg, or a multiple of three (for [regname set binding] triples)
435        if (base[lang].size() != 1 && (base[lang].size() % 3) != 0)
436            usage();
437
438    } else {
439        // Parse form: --argname set
440        for (int lang=0; lang<EShLangCount; ++lang)
441            base[lang].push_back(argv[1]);
442
443        argc--;
444        argv++;
445    }
446}
447
448//
449// Process an optional binding base of one the forms:
450//   --argname name {uniform|buffer|push_constant}
451void ProcessBlockStorage(int& argc, char**& argv, std::vector<std::pair<std::string, glslang::TBlockStorageClass>>& storage)
452{
453    if (argc < 3)
454        usage();
455
456    glslang::TBlockStorageClass blockStorage = glslang::EbsNone;
457
458    std::string strBacking(argv[2]);
459    if (strBacking == "uniform")
460        blockStorage = glslang::EbsUniform;
461    else if (strBacking == "buffer")
462        blockStorage = glslang::EbsStorageBuffer;
463    else if (strBacking == "push_constant")
464        blockStorage = glslang::EbsPushConstant;
465    else {
466        printf("%s: invalid block storage\n", strBacking.c_str());
467        usage();
468    }
469
470    storage.push_back(std::make_pair(std::string(argv[1]), blockStorage));
471
472    argc -= 2;
473    argv += 2;
474}
475
476inline bool isNonDigit(char c) {
477    // a non-digit character valid in a glsl identifier
478    return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
479}
480
481// whether string isa  valid identifier to be used in glsl
482bool isValidIdentifier(const char* str) {
483    std::string idn(str);
484
485    if (idn.length() == 0) {
486        return false;
487    }
488
489    if (idn.length() >= 3 && idn.substr(0, 3) == "gl_") {
490        // identifiers startin with "gl_" are reserved
491        return false;
492    }
493
494    if (!isNonDigit(idn[0])) {
495        return false;
496    }
497
498    for (unsigned int i = 1; i < idn.length(); ++i) {
499        if (!(isdigit(idn[i]) || isNonDigit(idn[i]))) {
500            return false;
501        }
502    }
503
504    return true;
505}
506
507// Process settings for either the global buffer block or global unfirom block
508// of the form:
509//      --argname name set binding
510void ProcessGlobalBlockSettings(int& argc, char**& argv, std::string* name, unsigned int* set, unsigned int* binding)
511{
512    if (argc < 4)
513        usage();
514
515    unsigned int curArg = 1;
516
517    assert(name || set || binding);
518
519    if (name) {
520        if (!isValidIdentifier(argv[curArg])) {
521            printf("%s: invalid identifier\n", argv[curArg]);
522            usage();
523        }
524        *name = argv[curArg];
525
526        curArg++;
527    }
528
529    if (set) {
530        errno = 0;
531        int setVal = static_cast<int>(::strtol(argv[curArg], nullptr, 10));
532        if (errno || setVal < 0) {
533            printf("%s: invalid set\n", argv[curArg]);
534            usage();
535        }
536        *set = setVal;
537
538        curArg++;
539    }
540
541    if (binding) {
542        errno = 0;
543        int bindingVal = static_cast<int>(::strtol(argv[curArg], nullptr, 10));
544        if (errno || bindingVal < 0) {
545            printf("%s: invalid binding\n", argv[curArg]);
546            usage();
547        }
548        *binding = bindingVal;
549
550        curArg++;
551    }
552
553    argc -= (curArg - 1);
554    argv += (curArg - 1);
555}
556
557//
558// Do all command-line argument parsing.  This includes building up the work-items
559// to be processed later, and saving all the command-line options.
560//
561// Does not return (it exits) if command-line is fatally flawed.
562//
563void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItems, int argc, char* argv[])
564{
565    for (int res = 0; res < glslang::EResCount; ++res)
566        baseBinding[res].fill(0);
567
568    ExecutableName = argv[0];
569    workItems.reserve(argc);
570
571    CommandLineArguments.clear();
572    for (int arg = 1; arg < argc; ++arg) {
573        if (arg > 1)
574            CommandLineArguments += ' ';
575        CommandLineArguments += argv[arg];
576    }
577
578    const auto bumpArg = [&]() {
579        if (argc > 0) {
580            argc--;
581            argv++;
582        }
583    };
584
585    // read a string directly attached to a single-letter option
586    const auto getStringOperand = [&](const char* desc) {
587        if (argv[0][2] == 0) {
588            printf("%s must immediately follow option (no spaces)\n", desc);
589            exit(EFailUsage);
590        }
591        return argv[0] + 2;
592    };
593
594    // read a number attached to a single-letter option
595    const auto getAttachedNumber = [&](const char* desc) {
596        int num = atoi(argv[0] + 2);
597        if (num == 0) {
598            printf("%s: expected attached non-0 number\n", desc);
599            exit(EFailUsage);
600        }
601        return num;
602    };
603
604    // minimum needed (without overriding something else) to target Vulkan SPIR-V
605    const auto setVulkanSpv = []() {
606        if (Client == glslang::EShClientNone)
607            ClientVersion = glslang::EShTargetVulkan_1_0;
608        Client = glslang::EShClientVulkan;
609        Options |= EOptionSpv;
610        Options |= EOptionVulkanRules;
611        Options |= EOptionLinkProgram;
612    };
613
614    // minimum needed (without overriding something else) to target OpenGL SPIR-V
615    const auto setOpenGlSpv = []() {
616        if (Client == glslang::EShClientNone)
617            ClientVersion = glslang::EShTargetOpenGL_450;
618        Client = glslang::EShClientOpenGL;
619        Options |= EOptionSpv;
620        Options |= EOptionLinkProgram;
621        // undo a -H default to Vulkan
622        Options &= ~EOptionVulkanRules;
623    };
624
625    const auto getUniformOverride = [getStringOperand]() {
626        const char *arg = getStringOperand("-u<name>:<location>");
627        const char *split = strchr(arg, ':');
628        if (split == nullptr) {
629            printf("%s: missing location\n", arg);
630            exit(EFailUsage);
631        }
632        errno = 0;
633        int location = static_cast<int>(::strtol(split + 1, nullptr, 10));
634        if (errno) {
635            printf("%s: invalid location\n", arg);
636            exit(EFailUsage);
637        }
638        return std::make_pair(std::string(arg, split - arg), location);
639    };
640
641    for (bumpArg(); argc >= 1; bumpArg()) {
642        if (argv[0][0] == '-') {
643            switch (argv[0][1]) {
644            case '-':
645                {
646                    std::string lowerword(argv[0]+2);
647                    std::transform(lowerword.begin(), lowerword.end(), lowerword.begin(), ::tolower);
648
649                    // handle --word style options
650                    if (lowerword == "auto-map-bindings" ||  // synonyms
651                        lowerword == "auto-map-binding"  ||
652                        lowerword == "amb") {
653                        Options |= EOptionAutoMapBindings;
654                    } else if (lowerword == "relax-set-binding-limits") {
655                        Options |= EOptionRelaxSetBindingLimits;
656                    } else if (lowerword == "auto-map-locations" || // synonyms
657                               lowerword == "aml") {
658                        Options |= EOptionAutoMapLocations;
659                    } else if (lowerword == "uniform-base") {
660                        if (argc <= 1)
661                            Error("no <base> provided", lowerword.c_str());
662                        uniformBase = static_cast<int>(::strtol(argv[1], nullptr, 10));
663                        bumpArg();
664                        break;
665                    } else if (lowerword == "client") {
666                        if (argc > 1) {
667                            if (strcmp(argv[1], "vulkan100") == 0)
668                                setVulkanSpv();
669                            else if (strcmp(argv[1], "opengl100") == 0)
670                                setOpenGlSpv();
671                            else
672                                Error("expects vulkan100 or opengl100", lowerword.c_str());
673                        } else
674                            Error("expects vulkan100 or opengl100", lowerword.c_str());
675                        bumpArg();
676                    } else if (lowerword == "define-macro" ||
677                               lowerword == "d") {
678                        if (argc > 1)
679                            UserPreamble.addDef(argv[1]);
680                        else
681                            Error("expects <name[=def]>", argv[0]);
682                        bumpArg();
683                    } else if (lowerword == "dump-builtin-symbols") {
684                        DumpBuiltinSymbols = true;
685                    } else if (lowerword == "entry-point") {
686                        entryPointName = argv[1];
687                        if (argc <= 1)
688                            Error("no <name> provided", lowerword.c_str());
689                        bumpArg();
690                    } else if (lowerword == "flatten-uniform-arrays" || // synonyms
691                               lowerword == "flatten-uniform-array"  ||
692                               lowerword == "fua") {
693                        Options |= EOptionFlattenUniformArrays;
694                    } else if (lowerword == "glsl-version") {
695                        if (argc > 1) {
696                            if (strcmp(argv[1], "100") == 0) {
697                                GlslVersion = 100;
698                            } else if (strcmp(argv[1], "110") == 0) {
699                                GlslVersion = 110;
700                            } else if (strcmp(argv[1], "120") == 0) {
701                                GlslVersion = 120;
702                            } else if (strcmp(argv[1], "130") == 0) {
703                                GlslVersion = 130;
704                            } else if (strcmp(argv[1], "140") == 0) {
705                                GlslVersion = 140;
706                            } else if (strcmp(argv[1], "150") == 0) {
707                                GlslVersion = 150;
708                            } else if (strcmp(argv[1], "300es") == 0) {
709                                GlslVersion = 300;
710                            } else if (strcmp(argv[1], "310es") == 0) {
711                                GlslVersion = 310;
712                            } else if (strcmp(argv[1], "320es") == 0) {
713                                GlslVersion = 320;
714                            } else if (strcmp(argv[1], "330") == 0) {
715                                GlslVersion = 330;
716                            } else if (strcmp(argv[1], "400") == 0) {
717                                GlslVersion = 400;
718                            } else if (strcmp(argv[1], "410") == 0) {
719                                GlslVersion = 410;
720                            } else if (strcmp(argv[1], "420") == 0) {
721                                GlslVersion = 420;
722                            } else if (strcmp(argv[1], "430") == 0) {
723                                GlslVersion = 430;
724                            } else if (strcmp(argv[1], "440") == 0) {
725                                GlslVersion = 440;
726                            } else if (strcmp(argv[1], "450") == 0) {
727                                GlslVersion = 450;
728                            } else if (strcmp(argv[1], "460") == 0) {
729                                GlslVersion = 460;
730                            } else
731                                Error("--glsl-version expected one of: 100, 110, 120, 130, 140, 150,\n"
732                                      "300es, 310es, 320es, 330\n"
733                                      "400, 410, 420, 430, 440, 450, 460");
734                        }
735                        bumpArg();
736                    } else if (lowerword == "hlsl-offsets") {
737                        Options |= EOptionHlslOffsets;
738                    } else if (lowerword == "hlsl-iomap" ||
739                               lowerword == "hlsl-iomapper" ||
740                               lowerword == "hlsl-iomapping") {
741                        Options |= EOptionHlslIoMapping;
742                    } else if (lowerword == "hlsl-enable-16bit-types") {
743                        HlslEnable16BitTypes = true;
744                    } else if (lowerword == "hlsl-dx9-compatible") {
745                        HlslDX9compatible = true;
746                    } else if (lowerword == "hlsl-dx-position-w") {
747                        HlslDxPositionW = true;
748                    } else if (lowerword == "enhanced-msgs") {
749                        EnhancedMsgs = true;
750                    } else if (lowerword == "absolute-path") {
751                        AbsolutePath = true;
752                    } else if (lowerword == "auto-sampled-textures") {
753                        autoSampledTextures = true;
754                    } else if (lowerword == "discard-is-terminate") {
755                        Options |= EOptionDiscardIsTerminate;
756                    } else if (lowerword == "invert-y" ||  // synonyms
757                               lowerword == "iy") {
758                        Options |= EOptionInvertY;
759                    } else if (lowerword == "keep-uncalled" || // synonyms
760                               lowerword == "ku") {
761                        Options |= EOptionKeepUncalled;
762                    } else if (lowerword == "nan-clamp") {
763                        NaNClamp = true;
764                    } else if (lowerword == "no-storage-format" || // synonyms
765                               lowerword == "nsf") {
766                        Options |= EOptionNoStorageFormat;
767                    } else if (lowerword == "preamble-text" ||
768                               lowerword == "p") {
769                        if (argc > 1)
770                            UserPreamble.addText(argv[1]);
771                        else
772                            Error("expects <text>", argv[0]);
773                        bumpArg();
774                    } else if (lowerword == "relaxed-errors") {
775                        Options |= EOptionRelaxedErrors;
776                    } else if (lowerword == "reflect-strict-array-suffix") {
777                        ReflectOptions |= EShReflectionStrictArraySuffix;
778                    } else if (lowerword == "reflect-basic-array-suffix") {
779                        ReflectOptions |= EShReflectionBasicArraySuffix;
780                    } else if (lowerword == "reflect-intermediate-io") {
781                        ReflectOptions |= EShReflectionIntermediateIO;
782                    } else if (lowerword == "reflect-separate-buffers") {
783                        ReflectOptions |= EShReflectionSeparateBuffers;
784                    } else if (lowerword == "reflect-all-block-variables") {
785                        ReflectOptions |= EShReflectionAllBlockVariables;
786                    } else if (lowerword == "reflect-unwrap-io-blocks") {
787                        ReflectOptions |= EShReflectionUnwrapIOBlocks;
788                    } else if (lowerword == "reflect-all-io-variables") {
789                        ReflectOptions |= EShReflectionAllIOVariables;
790                    } else if (lowerword == "reflect-shared-std140-ubo") {
791                        ReflectOptions |= EShReflectionSharedStd140UBO;
792                    } else if (lowerword == "reflect-shared-std140-ssbo") {
793                        ReflectOptions |= EShReflectionSharedStd140SSBO;
794                    } else if (lowerword == "resource-set-bindings" ||  // synonyms
795                               lowerword == "resource-set-binding"  ||
796                               lowerword == "rsb") {
797                        ProcessResourceSetBindingBase(argc, argv, baseResourceSetBinding);
798                    } else if (lowerword == "set-block-storage" ||
799                               lowerword == "sbs") {
800                        ProcessBlockStorage(argc, argv, blockStorageOverrides);
801                    } else if (lowerword == "set-atomic-counter-block" ||
802                               lowerword == "sacb") {
803                        ProcessGlobalBlockSettings(argc, argv, &atomicCounterBlockName, &atomicCounterBlockSet, nullptr);
804                        setGlobalBufferBlock = true;
805                    } else if (lowerword == "set-default-uniform-block" ||
806                               lowerword == "sdub") {
807                        ProcessGlobalBlockSettings(argc, argv, &globalUniformName, &globalUniformSet, &globalUniformBinding);
808                        setGlobalUniformBlock = true;
809                    } else if (lowerword == "shift-image-bindings" ||  // synonyms
810                               lowerword == "shift-image-binding"  ||
811                               lowerword == "sib") {
812                        ProcessBindingBase(argc, argv, glslang::EResImage);
813                    } else if (lowerword == "shift-sampler-bindings" || // synonyms
814                               lowerword == "shift-sampler-binding"  ||
815                               lowerword == "ssb") {
816                        ProcessBindingBase(argc, argv, glslang::EResSampler);
817                    } else if (lowerword == "shift-uav-bindings" ||  // synonyms
818                               lowerword == "shift-uav-binding"  ||
819                               lowerword == "suavb") {
820                        ProcessBindingBase(argc, argv, glslang::EResUav);
821                    } else if (lowerword == "shift-texture-bindings" ||  // synonyms
822                               lowerword == "shift-texture-binding"  ||
823                               lowerword == "stb") {
824                        ProcessBindingBase(argc, argv, glslang::EResTexture);
825                    } else if (lowerword == "shift-ubo-bindings" ||  // synonyms
826                               lowerword == "shift-ubo-binding"  ||
827                               lowerword == "shift-cbuffer-bindings" ||
828                               lowerword == "shift-cbuffer-binding"  ||
829                               lowerword == "sub" ||
830                               lowerword == "scb") {
831                        ProcessBindingBase(argc, argv, glslang::EResUbo);
832                    } else if (lowerword == "shift-ssbo-bindings" ||  // synonyms
833                               lowerword == "shift-ssbo-binding"  ||
834                               lowerword == "sbb") {
835                        ProcessBindingBase(argc, argv, glslang::EResSsbo);
836                    } else if (lowerword == "shift-combined-sampler-bindings" ||
837                               lowerword == "shift-combined-sampler-binding" ||
838                               lowerword == "scsb") {
839                        ProcessBindingBase(argc, argv, glslang::EResCombinedSampler);
840                    } else if (lowerword == "shift-as-bindings" ||
841                               lowerword == "shift-as-binding" ||
842                               lowerword == "sab") {
843                        ProcessBindingBase(argc, argv, glslang::EResAs);
844                    } else if (lowerword == "source-entrypoint" || // synonyms
845                               lowerword == "sep") {
846                        if (argc <= 1)
847                            Error("no <entry-point> provided", lowerword.c_str());
848                        sourceEntryPointName = argv[1];
849                        bumpArg();
850                        break;
851                    } else if (lowerword == "spirv-dis") {
852                        SpvToolsDisassembler = true;
853                    } else if (lowerword == "spirv-val") {
854                        SpvToolsValidate = true;
855                    } else if (lowerword == "stdin") {
856                        Options |= EOptionStdin;
857                        shaderStageName = argv[1];
858                    } else if (lowerword == "suppress-warnings") {
859                        Options |= EOptionSuppressWarnings;
860                    } else if (lowerword == "target-env") {
861                        if (argc > 1) {
862                            if (strcmp(argv[1], "vulkan1.0") == 0) {
863                                setVulkanSpv();
864                                ClientVersion = glslang::EShTargetVulkan_1_0;
865                            } else if (strcmp(argv[1], "vulkan1.1") == 0) {
866                                setVulkanSpv();
867                                ClientVersion = glslang::EShTargetVulkan_1_1;
868                            } else if (strcmp(argv[1], "vulkan1.2") == 0) {
869                                setVulkanSpv();
870                                ClientVersion = glslang::EShTargetVulkan_1_2;
871                            } else if (strcmp(argv[1], "vulkan1.3") == 0) {
872                                setVulkanSpv();
873                                ClientVersion = glslang::EShTargetVulkan_1_3;
874                            } else if (strcmp(argv[1], "vulkan1.4") == 0) {
875                                setVulkanSpv();
876                                ClientVersion = glslang::EShTargetVulkan_1_4;
877                            } else if (strcmp(argv[1], "opengl") == 0) {
878                                setOpenGlSpv();
879                                ClientVersion = glslang::EShTargetOpenGL_450;
880                            } else if (strcmp(argv[1], "spirv1.0") == 0) {
881                                TargetLanguage = glslang::EShTargetSpv;
882                                TargetVersion = glslang::EShTargetSpv_1_0;
883                            } else if (strcmp(argv[1], "spirv1.1") == 0) {
884                                TargetLanguage = glslang::EShTargetSpv;
885                                TargetVersion = glslang::EShTargetSpv_1_1;
886                            } else if (strcmp(argv[1], "spirv1.2") == 0) {
887                                TargetLanguage = glslang::EShTargetSpv;
888                                TargetVersion = glslang::EShTargetSpv_1_2;
889                            } else if (strcmp(argv[1], "spirv1.3") == 0) {
890                                TargetLanguage = glslang::EShTargetSpv;
891                                TargetVersion = glslang::EShTargetSpv_1_3;
892                            } else if (strcmp(argv[1], "spirv1.4") == 0) {
893                                TargetLanguage = glslang::EShTargetSpv;
894                                TargetVersion = glslang::EShTargetSpv_1_4;
895                            } else if (strcmp(argv[1], "spirv1.5") == 0) {
896                                TargetLanguage = glslang::EShTargetSpv;
897                                TargetVersion = glslang::EShTargetSpv_1_5;
898                            } else if (strcmp(argv[1], "spirv1.6") == 0) {
899                                TargetLanguage = glslang::EShTargetSpv;
900                                TargetVersion = glslang::EShTargetSpv_1_6;
901                            } else
902                                Error("--target-env expected one of: vulkan1.0, vulkan1.1, vulkan1.2,\n"
903                                      "vulkan1.3, vulkan1.4, opengl, spirv1.0, spirv1.1, spirv1.2, spirv1.3,\n"
904                                      "spirv1.4, spirv1.5 or spirv1.6");
905                        }
906                        bumpArg();
907                    } else if (lowerword == "undef-macro" ||
908                               lowerword == "u") {
909                        if (argc > 1)
910                            UserPreamble.addUndef(argv[1]);
911                        else
912                            Error("expects <name>", argv[0]);
913                        bumpArg();
914                    } else if (lowerword == "variable-name" || // synonyms
915                               lowerword == "vn") {
916                        Options |= EOptionOutputHexadecimal;
917                        if (argc <= 1)
918                            Error("no <C-variable-name> provided", lowerword.c_str());
919                        variableName = argv[1];
920                        bumpArg();
921                        break;
922                    } else if (lowerword == "quiet") {
923                        beQuiet = true;
924                    } else if (lowerword == "depfile") {
925                        if (argc <= 1)
926                            Error("no <depfile-name> provided", lowerword.c_str());
927                        depencyFileName = argv[1];
928                        bumpArg();
929                    } else if (lowerword == "version") {
930                        Options |= EOptionDumpVersions;
931                    } else if (lowerword == "no-link") {
932                        Options |= EOptionCompileOnly;
933                    } else if (lowerword == "error-column") {
934                        Options |= EOptionDisplayErrorColumn;
935                    } else if (lowerword == "lto") {
936                        Options |= EOptionLinkTimeOptimization;
937                    } else if (lowerword == "validate-io") {
938                        Options |= EOptionValidateCrossStageIO;
939                    } else if (lowerword == "bindings-per-resource-type") {
940                        Options |= EOptionBindingsPerResourceType;
941                    } else if (lowerword == "help") {
942                        usage();
943                        break;
944                    } else {
945                        Error("unrecognized command-line option", argv[0]);
946                    }
947                }
948                break;
949            case 'C':
950                Options |= EOptionCascadingErrors;
951                break;
952            case 'D':
953                if (argv[0][2] == 0)
954                    Options |= EOptionReadHlsl;
955                else
956                    UserPreamble.addDef(getStringOperand("-D<name[=def]>"));
957                break;
958            case 'u':
959                uniformLocationOverrides.push_back(getUniformOverride());
960                break;
961            case 'E':
962                Options |= EOptionOutputPreprocessed;
963                break;
964            case 'G':
965                // OpenGL client
966                setOpenGlSpv();
967                if (argv[0][2] != 0)
968                    ClientInputSemanticsVersion = getAttachedNumber("-G<num> client input semantics");
969                if (ClientInputSemanticsVersion != 100)
970                    Error("unknown client version for -G, should be 100");
971                break;
972            case 'H':
973                Options |= EOptionHumanReadableSpv;
974                if ((Options & EOptionSpv) == 0) {
975                    // default to Vulkan
976                    setVulkanSpv();
977                }
978                break;
979            case 'I':
980                IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
981                break;
982            case 'O':
983                if (argv[0][2] == 'd')
984                    Options |= EOptionOptimizeDisable;
985                else if (argv[0][2] == 's')
986#if ENABLE_OPT
987                    Options |= EOptionOptimizeSize;
988#else
989                    Error("-Os not available; optimizer not linked");
990#endif
991                else if (argv[0][2] == '\0')
992#if ENABLE_OPT
993                    Options |= EOptionOptimizePerformance;
994#else
995                    Error("-O not available; optimizer not linked");
996#endif
997                else
998                    Error("unknown -O option");
999                break;
1000            case 'P':
1001                UserPreamble.addText(getStringOperand("-P<text>"));
1002                break;
1003            case 'R':
1004                VulkanRulesRelaxed = true;
1005                break;
1006            case 'S':
1007                if (argc <= 1)
1008                    Error("no <stage> specified for -S");
1009                shaderStageName = argv[1];
1010                bumpArg();
1011                break;
1012            case 'U':
1013                UserPreamble.addUndef(getStringOperand("-U<name>"));
1014                break;
1015            case 'V':
1016                setVulkanSpv();
1017                if (argv[0][2] != 0)
1018                    ClientInputSemanticsVersion = getAttachedNumber("-V<num> client input semantics");
1019                if (ClientInputSemanticsVersion != 100)
1020                    Error("unknown client version for -V, should be 100");
1021                break;
1022            case 'c':
1023                Options |= EOptionDumpConfig;
1024                break;
1025            case 'd':
1026                if (strncmp(&argv[0][1], "dumpversion", strlen(&argv[0][1]) + 1) == 0 ||
1027                    strncmp(&argv[0][1], "dumpfullversion", strlen(&argv[0][1]) + 1) == 0)
1028                    Options |= EOptionDumpBareVersion;
1029                else
1030                    Options |= EOptionDefaultDesktop;
1031                break;
1032            case 'e':
1033                entryPointName = argv[1];
1034                if (argc <= 1)
1035                    Error("no <name> provided for -e");
1036                bumpArg();
1037                break;
1038            case 'f':
1039                if (strcmp(&argv[0][2], "hlsl_functionality1") == 0)
1040                    targetHlslFunctionality1 = true;
1041                else
1042                    Error("-f: expected hlsl_functionality1");
1043                break;
1044            case 'g':
1045                // Override previous -g or -g0 argument
1046                stripDebugInfo = false;
1047                emitNonSemanticShaderDebugInfo = false;
1048                emitSourceFileName = false;
1049                Options &= ~EOptionDebug;
1050                if (argv[0][2] == '0')
1051                    stripDebugInfo = true;
1052                else if (argv[0][2] == 'N')
1053                    emitSourceFileName = true;
1054                else {
1055                    Options |= EOptionDebug;
1056                    if (argv[0][2] == 'V') {
1057                        emitNonSemanticShaderDebugInfo = true;
1058                        if (argv[0][3] == 'S') {
1059                            emitNonSemanticShaderDebugSource = true;
1060                        } else {
1061                            emitNonSemanticShaderDebugSource = false;
1062                        }
1063                    }
1064                }
1065                break;
1066            case 'h':
1067                usage();
1068                break;
1069            case 'i':
1070                Options |= EOptionIntermediate;
1071                break;
1072            case 'l':
1073                Options |= EOptionLinkProgram;
1074                break;
1075            case 'm':
1076                Options |= EOptionMemoryLeakMode;
1077                break;
1078            case 'o':
1079                if (argc <= 1)
1080                    Error("no <file> provided for -o");
1081                binaryFileName = argv[1];
1082                bumpArg();
1083                break;
1084            case 'q':
1085                Options |= EOptionDumpReflection;
1086                break;
1087            case 'r':
1088                Options |= EOptionRelaxedErrors;
1089                break;
1090            case 's':
1091                Options |= EOptionSuppressInfolog;
1092                break;
1093            case 't':
1094                Options |= EOptionMultiThreaded;
1095                break;
1096            case 'v':
1097                Options |= EOptionDumpVersions;
1098                break;
1099            case 'w':
1100                Options |= EOptionSuppressWarnings;
1101                break;
1102            case 'x':
1103                Options |= EOptionOutputHexadecimal;
1104                break;
1105            default:
1106                Error("unrecognized command-line option", argv[0]);
1107                break;
1108            }
1109        } else {
1110            std::string name(argv[0]);
1111            if (! SetConfigFile(name)) {
1112                workItems.push_back(std::unique_ptr<glslang::TWorkItem>(new glslang::TWorkItem(name)));
1113            }
1114        }
1115    }
1116
1117    // Make sure that -S is always specified if --stdin is specified
1118    if ((Options & EOptionStdin) && shaderStageName == nullptr)
1119        Error("must provide -S when --stdin is given");
1120
1121    // Make sure that -E is not specified alongside linking (which includes SPV generation)
1122    // Or things that require linking
1123    if (Options & EOptionOutputPreprocessed) {
1124        if (Options & EOptionLinkProgram)
1125            Error("can't use -E when linking is selected");
1126        if (Options & EOptionDumpReflection)
1127            Error("reflection requires linking, which can't be used when -E when is selected");
1128    }
1129
1130    // reflection requires linking
1131    if ((Options & EOptionDumpReflection) && !(Options & EOptionLinkProgram))
1132        Error("reflection requires -l for linking");
1133
1134    // link time optimization makes no sense unless linking
1135    if ((Options & EOptionLinkTimeOptimization) && !(Options & EOptionLinkProgram))
1136        Error("link time optimization requires -l for linking");
1137
1138    // cross stage IO validation makes no sense unless linking
1139    if ((Options & EOptionValidateCrossStageIO) && !(Options & EOptionLinkProgram))
1140        Error("cross stage IO validation requires -l for linking");
1141
1142    // -o or -x makes no sense if there is no target binary
1143    if (binaryFileName && (Options & EOptionSpv) == 0)
1144        Error("no binary generation requested (e.g., -V)");
1145
1146    if ((Options & EOptionFlattenUniformArrays) != 0 &&
1147        (Options & EOptionReadHlsl) == 0)
1148        Error("uniform array flattening only valid when compiling HLSL source.");
1149
1150    if ((Options & EOptionReadHlsl) && (Client == glslang::EShClientOpenGL)) {
1151        Error("Using HLSL input under OpenGL semantics is not currently supported.");
1152    }
1153
1154    // rationalize client and target language
1155    if (TargetLanguage == glslang::EShTargetNone) {
1156        switch (ClientVersion) {
1157        case glslang::EShTargetVulkan_1_0:
1158            TargetLanguage = glslang::EShTargetSpv;
1159            TargetVersion = glslang::EShTargetSpv_1_0;
1160            break;
1161        case glslang::EShTargetVulkan_1_1:
1162            TargetLanguage = glslang::EShTargetSpv;
1163            TargetVersion = glslang::EShTargetSpv_1_3;
1164            break;
1165        case glslang::EShTargetVulkan_1_2:
1166            TargetLanguage = glslang::EShTargetSpv;
1167            TargetVersion = glslang::EShTargetSpv_1_5;
1168            break;
1169        case glslang::EShTargetVulkan_1_3:
1170            TargetLanguage = glslang::EShTargetSpv;
1171            TargetVersion = glslang::EShTargetSpv_1_6;
1172            break;
1173        case glslang::EShTargetVulkan_1_4:
1174            TargetLanguage = glslang::EShTargetSpv;
1175            TargetVersion = glslang::EShTargetSpv_1_6;
1176            break;
1177        case glslang::EShTargetOpenGL_450:
1178            TargetLanguage = glslang::EShTargetSpv;
1179            TargetVersion = glslang::EShTargetSpv_1_0;
1180            break;
1181        default:
1182            break;
1183        }
1184    }
1185    if (TargetLanguage != glslang::EShTargetNone && Client == glslang::EShClientNone)
1186        Error("To generate SPIR-V, also specify client semantics. See -G and -V.");
1187}
1188
1189//
1190// Translate the meaningful subset of command-line options to parser-behavior options.
1191//
1192void SetMessageOptions(EShMessages& messages)
1193{
1194    if (Options & EOptionRelaxedErrors)
1195        messages = (EShMessages)(messages | EShMsgRelaxedErrors);
1196    if (Options & EOptionIntermediate)
1197        messages = (EShMessages)(messages | EShMsgAST);
1198    if (Options & EOptionSuppressWarnings)
1199        messages = (EShMessages)(messages | EShMsgSuppressWarnings);
1200    if (Options & EOptionSpv)
1201        messages = (EShMessages)(messages | EShMsgSpvRules);
1202    if (Options & EOptionVulkanRules)
1203        messages = (EShMessages)(messages | EShMsgVulkanRules);
1204    if (Options & EOptionOutputPreprocessed)
1205        messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
1206    if (Options & EOptionReadHlsl)
1207        messages = (EShMessages)(messages | EShMsgReadHlsl);
1208    if (Options & EOptionCascadingErrors)
1209        messages = (EShMessages)(messages | EShMsgCascadingErrors);
1210    if (Options & EOptionKeepUncalled)
1211        messages = (EShMessages)(messages | EShMsgKeepUncalled);
1212    if (Options & EOptionHlslOffsets)
1213        messages = (EShMessages)(messages | EShMsgHlslOffsets);
1214    if (Options & EOptionDebug)
1215        messages = (EShMessages)(messages | EShMsgDebugInfo);
1216    if (HlslEnable16BitTypes)
1217        messages = (EShMessages)(messages | EShMsgHlslEnable16BitTypes);
1218    if ((Options & EOptionOptimizeDisable) || !ENABLE_OPT)
1219        messages = (EShMessages)(messages | EShMsgHlslLegalization);
1220    if (HlslDX9compatible)
1221        messages = (EShMessages)(messages | EShMsgHlslDX9Compatible);
1222    if (DumpBuiltinSymbols)
1223        messages = (EShMessages)(messages | EShMsgBuiltinSymbolTable);
1224    if (EnhancedMsgs)
1225        messages = (EShMessages)(messages | EShMsgEnhanced);
1226    if (AbsolutePath)
1227        messages = (EShMessages)(messages | EShMsgAbsolutePath);
1228    if (Options & EOptionDisplayErrorColumn)
1229        messages = (EShMessages)(messages | EShMsgDisplayErrorColumn);
1230    if (Options & EOptionLinkTimeOptimization)
1231        messages = (EShMessages)(messages | EShMsgLinkTimeOptimization);
1232    if (Options & EOptionValidateCrossStageIO)
1233        messages = (EShMessages)(messages | EShMsgValidateCrossStageIO);
1234    if (Options & EOptionRelaxSetBindingLimits)
1235        messages = (EShMessages)(messages | EShMsgRelaxSetBindingLimits);
1236}
1237
1238//
1239// Thread entry point, for non-linking asynchronous mode.
1240//
1241void CompileShaders(glslang::TWorklist& worklist)
1242{
1243    if (Options & EOptionDebug)
1244        Error("cannot generate debug information unless linking to generate code");
1245
1246    // NOTE: TWorkList::remove is thread-safe
1247    glslang::TWorkItem* workItem;
1248    if (Options & EOptionStdin) {
1249        if (worklist.remove(workItem)) {
1250            ShHandle compiler = ShConstructCompiler(FindLanguage("stdin"), 0);
1251            if (compiler == nullptr)
1252                return;
1253
1254            CompileFile("stdin", compiler);
1255
1256            if (! (Options & EOptionSuppressInfolog))
1257                workItem->results = ShGetInfoLog(compiler);
1258
1259            ShDestruct(compiler);
1260        }
1261    } else {
1262        while (worklist.remove(workItem)) {
1263            ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), 0);
1264            if (compiler == nullptr)
1265                return;
1266
1267
1268            CompileFile(workItem->name.c_str(), compiler);
1269
1270            if (! (Options & EOptionSuppressInfolog))
1271                workItem->results = ShGetInfoLog(compiler);
1272
1273            ShDestruct(compiler);
1274        }
1275    }
1276}
1277
1278// Outputs the given string, but only if it is non-null and non-empty.
1279// This prevents erroneous newlines from appearing.
1280void PutsIfNonEmpty(const char* str)
1281{
1282    if (str && str[0]) {
1283        puts(str);
1284    }
1285}
1286
1287// Outputs the given string to stderr, but only if it is non-null and non-empty.
1288// This prevents erroneous newlines from appearing.
1289void StderrIfNonEmpty(const char* str)
1290{
1291    if (str && str[0])
1292        fprintf(stderr, "%s\n", str);
1293}
1294
1295// Simple bundling of what makes a compilation unit for ease in passing around,
1296// and separation of handling file IO versus API (programmatic) compilation.
1297struct ShaderCompUnit {
1298    EShLanguage stage;
1299    static const int maxCount = 1;
1300    int count;                          // live number of strings/names
1301    const char* text[maxCount];         // memory owned/managed externally
1302    std::string fileName[maxCount];     // hold's the memory, but...
1303    const char* fileNameList[maxCount]; // downstream interface wants pointers
1304
1305    ShaderCompUnit(EShLanguage stage) : stage(stage), count(0) { }
1306
1307    ShaderCompUnit(const ShaderCompUnit& rhs)
1308    {
1309        stage = rhs.stage;
1310        count = rhs.count;
1311        for (int i = 0; i < count; ++i) {
1312            fileName[i] = rhs.fileName[i];
1313            text[i] = rhs.text[i];
1314            fileNameList[i] = rhs.fileName[i].c_str();
1315        }
1316    }
1317
1318    void addString(std::string& ifileName, const char* itext)
1319    {
1320        assert(count < maxCount);
1321        fileName[count] = ifileName;
1322        text[count] = itext;
1323        fileNameList[count] = fileName[count].c_str();
1324        ++count;
1325    }
1326};
1327
1328// Writes a string into a depfile, escaping some special characters following the Makefile rules.
1329static void writeEscapedDepString(std::ofstream& file, const std::string& str)
1330{
1331    for (char c : str) {
1332        switch (c) {
1333        case ' ':
1334        case ':':
1335        case '#':
1336        case '[':
1337        case ']':
1338        case '\\':
1339            file << '\\';
1340            break;
1341        case '$':
1342            file << '$';
1343            break;
1344        }
1345        file << c;
1346    }
1347}
1348
1349// Writes a depfile similar to gcc -MMD foo.c
1350bool writeDepFile(std::string depfile, std::vector<std::string>& binaryFiles, const std::vector<std::string>& sources)
1351{
1352    std::ofstream file(depfile);
1353    if (file.fail())
1354        return false;
1355
1356    for (auto binaryFile = binaryFiles.begin(); binaryFile != binaryFiles.end(); binaryFile++) {
1357        writeEscapedDepString(file, *binaryFile);
1358        file << ":";
1359        for (auto sourceFile = sources.begin(); sourceFile != sources.end(); sourceFile++) {
1360            file << " ";
1361            writeEscapedDepString(file, *sourceFile);
1362        }
1363        file << std::endl;
1364    }
1365    return true;
1366}
1367
1368//
1369// For linking mode: Will independently parse each compilation unit, but then put them
1370// in the same program and link them together, making at most one linked module per
1371// pipeline stage.
1372//
1373// Uses the new C++ interface instead of the old handle-based interface.
1374//
1375
1376void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
1377{
1378    // keep track of what to free
1379    std::list<glslang::TShader*> shaders;
1380
1381    EShMessages messages = EShMsgDefault;
1382    SetMessageOptions(messages);
1383
1384    DirStackFileIncluder includer;
1385    std::for_each(IncludeDirectoryList.begin(), IncludeDirectoryList.end(), [&includer](const std::string& dir) {
1386        includer.pushExternalDirectory(dir); });
1387
1388    std::vector<std::string> sources;
1389
1390    //
1391    // Per-shader processing...
1392    //
1393
1394    glslang::TProgram& program = *new glslang::TProgram;
1395    const bool compileOnly = (Options & EOptionCompileOnly) != 0;
1396    for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
1397        const auto &compUnit = *it;
1398        for (int i = 0; i < compUnit.count; i++) {
1399            sources.push_back(compUnit.fileNameList[i]);
1400        }
1401        glslang::TShader* shader = new glslang::TShader(compUnit.stage);
1402        shader->setStringsWithLengthsAndNames(compUnit.text, nullptr, compUnit.fileNameList, compUnit.count);
1403        if (entryPointName)
1404            shader->setEntryPoint(entryPointName);
1405        if (sourceEntryPointName) {
1406            if (entryPointName == nullptr)
1407                printf("Warning: Changing source entry point name without setting an entry-point name.\n"
1408                       "Use '-e <name>'.\n");
1409            shader->setSourceEntryPoint(sourceEntryPointName);
1410        }
1411
1412        if (compileOnly)
1413            shader->setCompileOnly();
1414
1415        shader->setOverrideVersion(GlslVersion);
1416
1417        std::string intrinsicString = getIntrinsic(compUnit.text, compUnit.count);
1418
1419        PreambleString = "";
1420        if (UserPreamble.isSet())
1421            PreambleString.append(UserPreamble.get());
1422
1423        if (!intrinsicString.empty())
1424            PreambleString.append(intrinsicString);
1425
1426        shader->setPreamble(PreambleString.c_str());
1427        shader->addProcesses(Processes);
1428
1429        // Set IO mapper binding shift values
1430        for (int r = 0; r < glslang::EResCount; ++r) {
1431            const glslang::TResourceType res = glslang::TResourceType(r);
1432
1433            // Set base bindings
1434            shader->setShiftBinding(res, baseBinding[res][compUnit.stage]);
1435
1436            // Set bindings for particular resource sets
1437            // TODO: use a range based for loop here, when available in all environments.
1438            for (auto i = baseBindingForSet[res][compUnit.stage].begin();
1439                 i != baseBindingForSet[res][compUnit.stage].end(); ++i)
1440                shader->setShiftBindingForSet(res, i->second, i->first);
1441        }
1442        shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
1443        shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]);
1444
1445        if (autoSampledTextures)
1446            shader->setTextureSamplerTransformMode(EShTexSampTransUpgradeTextureRemoveSampler);
1447
1448        if (Options & EOptionAutoMapBindings)
1449            shader->setAutoMapBindings(true);
1450
1451        if (Options & EOptionAutoMapLocations)
1452            shader->setAutoMapLocations(true);
1453
1454        for (auto& uniOverride : uniformLocationOverrides) {
1455            shader->addUniformLocationOverride(uniOverride.first.c_str(),
1456                                               uniOverride.second);
1457        }
1458
1459        shader->setUniformLocationBase(uniformBase);
1460
1461        if (VulkanRulesRelaxed) {
1462            for (auto& storageOverride : blockStorageOverrides) {
1463                shader->addBlockStorageOverride(storageOverride.first.c_str(),
1464                    storageOverride.second);
1465            }
1466
1467            if (setGlobalBufferBlock) {
1468                shader->setAtomicCounterBlockName(atomicCounterBlockName.c_str());
1469                shader->setAtomicCounterBlockSet(atomicCounterBlockSet);
1470            }
1471
1472            if (setGlobalUniformBlock) {
1473                shader->setGlobalUniformBlockName(globalUniformName.c_str());
1474                shader->setGlobalUniformSet(globalUniformSet);
1475                shader->setGlobalUniformBinding(globalUniformBinding);
1476            }
1477        }
1478
1479        shader->setNanMinMaxClamp(NaNClamp);
1480
1481#ifdef ENABLE_HLSL
1482        shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
1483        if (Options & EOptionHlslIoMapping)
1484            shader->setHlslIoMapping(true);
1485#endif
1486
1487        if (Options & EOptionInvertY)
1488            shader->setInvertY(true);
1489
1490        if (HlslDxPositionW)
1491            shader->setDxPositionW(true);
1492
1493        if (EnhancedMsgs)
1494            shader->setEnhancedMsgs();
1495
1496        if (emitNonSemanticShaderDebugInfo)
1497            shader->setDebugInfo(true);
1498
1499        if (emitSourceFileName && compUnit.count > 0)
1500            shader->setSourceFile(compUnit.fileNameList[0]);
1501
1502        if (Options & EOptionBindingsPerResourceType)
1503            shader->setBindingsPerResourceType();
1504
1505        if (Options & EOptionDiscardIsTerminate)
1506            shader->setDiscardIsTerminate(true);
1507
1508        // Set up the environment, some subsettings take precedence over earlier
1509        // ways of setting things.
1510        if (Options & EOptionSpv) {
1511            shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
1512                                                            : glslang::EShSourceGlsl,
1513                                compUnit.stage, Client, ClientInputSemanticsVersion);
1514            shader->setEnvClient(Client, ClientVersion);
1515            shader->setEnvTarget(TargetLanguage, TargetVersion);
1516#ifdef ENABLE_HLSL
1517            if (targetHlslFunctionality1)
1518                shader->setEnvTargetHlslFunctionality1();
1519#endif
1520            if (VulkanRulesRelaxed)
1521                shader->setEnvInputVulkanRulesRelaxed();
1522        }
1523
1524        shaders.push_back(shader);
1525
1526        const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
1527
1528        if (Options & EOptionOutputPreprocessed) {
1529            std::string str;
1530            if (shader->preprocess(GetResources(), defaultVersion, ENoProfile, false, false, messages, &str, includer)) {
1531                PutsIfNonEmpty(str.c_str());
1532            } else {
1533                CompileFailed = 1;
1534            }
1535            StderrIfNonEmpty(shader->getInfoLog());
1536            StderrIfNonEmpty(shader->getInfoDebugLog());
1537            continue;
1538        }
1539
1540        if (! shader->parse(GetResources(), defaultVersion, false, messages, includer))
1541            CompileFailed = 1;
1542
1543        if (!compileOnly)
1544            program.addShader(shader);
1545
1546        if (! (Options & EOptionSuppressInfolog) &&
1547            ! (Options & EOptionMemoryLeakMode)) {
1548            if (!beQuiet)
1549                StderrIfNonEmpty(compUnit.fileName[0].c_str());
1550            StderrIfNonEmpty(shader->getInfoLog());
1551            StderrIfNonEmpty(shader->getInfoDebugLog());
1552        }
1553    }
1554
1555    //
1556    // Program-level processing...
1557    //
1558
1559    if (!compileOnly) {
1560        // Link
1561        if (!(Options & EOptionOutputPreprocessed) && !program.link(messages))
1562            LinkFailed = true;
1563
1564        // Map IO
1565        if (Options & EOptionSpv) {
1566            if (!program.mapIO())
1567                LinkFailed = true;
1568        }
1569
1570        // Report
1571        if (!(Options & EOptionSuppressInfolog) && !(Options & EOptionMemoryLeakMode)) {
1572            StderrIfNonEmpty(program.getInfoLog());
1573            StderrIfNonEmpty(program.getInfoDebugLog());
1574        }
1575
1576        // Reflect
1577        if (Options & EOptionDumpReflection) {
1578            program.buildReflection(ReflectOptions);
1579            program.dumpReflection();
1580        }
1581    }
1582
1583    std::vector<std::string> outputFiles;
1584
1585    // Dump SPIR-V
1586    if (Options & EOptionSpv) {
1587#ifdef ENABLE_SPIRV
1588        CompileOrLinkFailed.fetch_or(CompileFailed);
1589        CompileOrLinkFailed.fetch_or(LinkFailed);
1590        if (static_cast<bool>(CompileOrLinkFailed.load()))
1591            printf("SPIR-V is not generated for failed compile or link\n");
1592        else {
1593            std::vector<glslang::TIntermediate*> intermediates;
1594            if (!compileOnly) {
1595                for (int stage = 0; stage < EShLangCount; ++stage) {
1596                    if (auto* i = program.getIntermediate((EShLanguage)stage)) {
1597                        intermediates.emplace_back(i);
1598                    }
1599                }
1600            } else {
1601                for (const auto* shader : shaders) {
1602                    if (auto* i = shader->getIntermediate()) {
1603                        intermediates.emplace_back(i);
1604                    }
1605                }
1606            }
1607            for (auto* intermediate : intermediates) {
1608                std::vector<unsigned int> spirv;
1609                spv::SpvBuildLogger logger;
1610                glslang::SpvOptions spvOptions;
1611                if (Options & EOptionDebug) {
1612                    spvOptions.generateDebugInfo = true;
1613                    if (emitNonSemanticShaderDebugInfo) {
1614                        spvOptions.emitNonSemanticShaderDebugInfo = true;
1615                        if (emitNonSemanticShaderDebugSource) {
1616                            spvOptions.emitNonSemanticShaderDebugSource = true;
1617                        }
1618                    }
1619                } else if (stripDebugInfo)
1620                    spvOptions.stripDebugInfo = true;
1621                else if (emitSourceFileName)
1622                    spvOptions.emitSourceFileName = true;
1623                spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
1624                spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
1625                spvOptions.optimizePerformance = (Options & EOptionOptimizePerformance) != 0;
1626                spvOptions.disassemble = SpvToolsDisassembler;
1627                spvOptions.validate = SpvToolsValidate;
1628                spvOptions.compileOnly = compileOnly;
1629                spvOptions.compilerSignature = "glslang";
1630                spvOptions.commandLineArguments = CommandLineArguments.c_str();
1631                std::error_code currentPathError;
1632                const std::string currentWorkingDirectory = std::filesystem::current_path(currentPathError).string();
1633                if (!currentPathError)
1634                    spvOptions.currentWorkingDirectory = currentWorkingDirectory.c_str();
1635                glslang::GlslangToSpv(*intermediate, spirv, &logger, &spvOptions);
1636
1637                // Dump the spv to a file or stdout, etc., but only if not doing
1638                // memory/perf testing, as it's not internal to programmatic use.
1639                if (!(Options & EOptionMemoryLeakMode)) {
1640                    printf("%s", logger.getAllMessages().c_str());
1641                    const auto filename = GetBinaryName(intermediate->getStage());
1642                    if (Options & EOptionOutputHexadecimal) {
1643                        if (!glslang::OutputSpvHex(spirv, filename, variableName))
1644                            exit(EFailUsage);
1645                    } else {
1646                        if (!glslang::OutputSpvBin(spirv, filename))
1647                            exit(EFailUsage);
1648                    }
1649
1650                    outputFiles.push_back(filename);
1651                    if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv))
1652                        spv::Disassemble(std::cout, spirv);
1653                }
1654            }
1655        }
1656#else
1657        Error("This configuration of glslang does not have SPIR-V support");
1658#endif
1659    }
1660
1661    CompileOrLinkFailed.fetch_or(CompileFailed);
1662    CompileOrLinkFailed.fetch_or(LinkFailed);
1663    if (depencyFileName && !static_cast<bool>(CompileOrLinkFailed.load())) {
1664        std::set<std::string> includedFiles = includer.getIncludedFiles();
1665        sources.insert(sources.end(), includedFiles.begin(), includedFiles.end());
1666
1667        writeDepFile(depencyFileName, outputFiles, sources);
1668    }
1669
1670    // Free everything up, program has to go before the shaders
1671    // because it might have merged stuff from the shaders, and
1672    // the stuff from the shaders has to have its destructors called
1673    // before the pools holding the memory in the shaders is freed.
1674    delete &program;
1675    while (shaders.size() > 0) {
1676        delete shaders.back();
1677        shaders.pop_back();
1678    }
1679}
1680
1681//
1682// Do file IO part of compile and link, handing off the pure
1683// API/programmatic mode to CompileAndLinkShaderUnits(), which can
1684// be put in a loop for testing memory footprint and performance.
1685//
1686// This is just for linking mode: meaning all the shaders will be put into the
1687// the same program linked together.
1688//
1689// This means there are a limited number of work items (not multi-threading mode)
1690// and that the point is testing at the linking level. Hence, to enable
1691// performance and memory testing, the actual compile/link can be put in
1692// a loop, independent of processing the work items and file IO.
1693//
1694void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist)
1695{
1696    std::vector<ShaderCompUnit> compUnits;
1697
1698    // If this is using stdin, we can't really detect multiple different file
1699    // units by input type. We need to assume that we're just being given one
1700    // file of a certain type.
1701    if ((Options & EOptionStdin) != 0) {
1702        ShaderCompUnit compUnit(FindLanguage("stdin"));
1703        std::istreambuf_iterator<char> begin(std::cin), end;
1704        std::string tempString(begin, end);
1705        char* fileText = strdup(tempString.c_str());
1706        std::string fileName = "stdin";
1707        compUnit.addString(fileName, fileText);
1708        compUnits.push_back(compUnit);
1709    } else {
1710        // Transfer all the work items from to a simple list of
1711        // of compilation units.  (We don't care about the thread
1712        // work-item distribution properties in this path, which
1713        // is okay due to the limited number of shaders, know since
1714        // they are all getting linked together.)
1715        glslang::TWorkItem* workItem;
1716        while (Worklist.remove(workItem)) {
1717            ShaderCompUnit compUnit(FindLanguage(workItem->name));
1718            char* fileText = ReadFileData(workItem->name.c_str());
1719            if (fileText == nullptr)
1720                usage();
1721            compUnit.addString(workItem->name, fileText);
1722            compUnits.push_back(compUnit);
1723        }
1724    }
1725
1726    // Actual call to programmatic processing of compile and link,
1727    // in a loop for testing memory and performance.  This part contains
1728    // all the perf/memory that a programmatic consumer will care about.
1729    for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1730        for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
1731           CompileAndLinkShaderUnits(compUnits);
1732
1733        if (Options & EOptionMemoryLeakMode)
1734            glslang::OS_DumpMemoryCounters();
1735    }
1736
1737    // free memory from ReadFileData, which got stored in a const char*
1738    // as the first string above
1739    for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
1740        FreeFileData(const_cast<char*>(it->text[0]));
1741}
1742
1743int singleMain()
1744{
1745    glslang::TWorklist workList;
1746    std::for_each(WorkItems.begin(), WorkItems.end(), [&workList](std::unique_ptr<glslang::TWorkItem>& item) {
1747        assert(item);
1748        workList.add(item.get());
1749    });
1750
1751    if (Options & EOptionDumpConfig) {
1752        printf("%s", GetDefaultTBuiltInResourceString().c_str());
1753        if (workList.empty())
1754            return ESuccess;
1755    }
1756
1757    if (Options & EOptionDumpBareVersion) {
1758        int spirvGeneratorVersion = 0;
1759#ifdef ENABLE_SPIRV
1760        spirvGeneratorVersion = glslang::GetSpirvGeneratorVersion();
1761#endif
1762        printf("%d:%d.%d.%d%s\n", spirvGeneratorVersion, GLSLANG_VERSION_MAJOR, GLSLANG_VERSION_MINOR,
1763                GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR);
1764        if (workList.empty())
1765            return ESuccess;
1766    } else if (Options & EOptionDumpVersions) {
1767        int spirvGeneratorVersion = 0;
1768#ifdef ENABLE_SPIRV
1769        spirvGeneratorVersion = glslang::GetSpirvGeneratorVersion();
1770#endif
1771        printf("Glslang Version: %d:%d.%d.%d%s\n", spirvGeneratorVersion, GLSLANG_VERSION_MAJOR,
1772                GLSLANG_VERSION_MINOR, GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR);
1773        printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
1774        printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
1775        std::string spirvVersion;
1776#if ENABLE_SPIRV
1777        glslang::GetSpirvVersion(spirvVersion);
1778#endif
1779        printf("SPIR-V Version %s\n", spirvVersion.c_str());
1780        printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
1781        printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
1782        printf("SPIR-V Generator Version %d\n", spirvGeneratorVersion);
1783        printf("GL_KHR_vulkan_glsl version %d\n", 100);
1784        printf("ARB_GL_gl_spirv version %d\n", 100);
1785        if (workList.empty())
1786            return ESuccess;
1787    }
1788
1789    if (workList.empty() && ((Options & EOptionStdin) == 0)) {
1790        usage();
1791    }
1792
1793    if (Options & EOptionStdin) {
1794        WorkItems.push_back(std::unique_ptr<glslang::TWorkItem>{new glslang::TWorkItem("stdin")});
1795        workList.add(WorkItems.back().get());
1796    }
1797
1798    ProcessConfigFile();
1799
1800    if ((Options & EOptionReadHlsl) && !((Options & EOptionOutputPreprocessed) || (Options & EOptionSpv)))
1801        Error("HLSL requires SPIR-V code generation (or preprocessing only)");
1802
1803    //
1804    // Two modes:
1805    // 1) linking all arguments together, single-threaded, new C++ interface
1806    // 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
1807    //
1808    if (Options & (EOptionLinkProgram | EOptionOutputPreprocessed)) {
1809        glslang::InitializeProcess();
1810        glslang::InitializeProcess();  // also test reference counting of users
1811        glslang::InitializeProcess();  // also test reference counting of users
1812        glslang::FinalizeProcess();    // also test reference counting of users
1813        glslang::FinalizeProcess();    // also test reference counting of users
1814        CompileAndLinkShaderFiles(workList);
1815        glslang::FinalizeProcess();
1816    } else {
1817        ShInitialize();
1818        ShInitialize();  // also test reference counting of users
1819        ShFinalize();    // also test reference counting of users
1820
1821        bool printShaderNames = workList.size() > 1;
1822
1823        if (Options & EOptionMultiThreaded) {
1824            std::array<std::thread, 16> threads;
1825            for (unsigned int t = 0; t < threads.size(); ++t) {
1826                threads[t] = std::thread(CompileShaders, std::ref(workList));
1827                if (threads[t].get_id() == std::thread::id()) {
1828                    fprintf(stderr, "Failed to create thread\n");
1829                    return EFailThreadCreate;
1830                }
1831            }
1832
1833            std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
1834        } else
1835            CompileShaders(workList);
1836
1837        // Print out all the resulting infologs
1838        for (size_t w = 0; w < WorkItems.size(); ++w) {
1839            if (WorkItems[w]) {
1840                if (printShaderNames || WorkItems[w]->results.size() > 0)
1841                    PutsIfNonEmpty(WorkItems[w]->name.c_str());
1842                PutsIfNonEmpty(WorkItems[w]->results.c_str());
1843            }
1844        }
1845
1846        ShFinalize();
1847    }
1848
1849    if (CompileFailed.load())
1850        return EFailCompile;
1851    if (LinkFailed.load())
1852        return EFailLink;
1853
1854    return 0;
1855}
1856
1857int C_DECL main(int argc, char* argv[])
1858{
1859    ProcessArguments(WorkItems, argc, argv);
1860
1861    int ret = 0;
1862
1863    // Loop over the entire init/finalize cycle to watch memory changes
1864    const int iterations = 1;
1865    if (iterations > 1)
1866        glslang::OS_DumpMemoryCounters();
1867    for (int i = 0; i < iterations; ++i) {
1868        ret = singleMain();
1869        if (iterations > 1)
1870            glslang::OS_DumpMemoryCounters();
1871    }
1872
1873    return ret;
1874}
1875
1876//
1877//   Deduce the language from the filename.  Files must end in one of the
1878//   following extensions:
1879//
1880//   .vert = vertex
1881//   .tesc = tessellation control
1882//   .tese = tessellation evaluation
1883//   .geom = geometry
1884//   .frag = fragment
1885//   .comp = compute
1886//   .rgen = ray generation
1887//   .rint = ray intersection
1888//   .rahit = ray any hit
1889//   .rchit = ray closest hit
1890//   .rmiss = ray miss
1891//   .rcall = ray callable
1892//   .mesh  = mesh
1893//   .task  = task
1894//   Additionally, the file names may end in .<stage>.glsl and .<stage>.hlsl
1895//   where <stage> is one of the stages listed above.
1896//
1897EShLanguage FindLanguage(const std::string& name, bool parseStageName)
1898{
1899    std::string stageName;
1900    if (shaderStageName)
1901        stageName = shaderStageName;
1902    else if (parseStageName) {
1903        // Note: "first" extension means "first from the end", i.e.
1904        // if the file is named foo.vert.glsl, then "glsl" is first,
1905        // "vert" is second.
1906        size_t firstExtStart = name.find_last_of(".");
1907        bool hasFirstExt = firstExtStart != std::string::npos;
1908        size_t secondExtStart = hasFirstExt ? name.find_last_of(".", firstExtStart - 1) : std::string::npos;
1909        bool hasSecondExt = secondExtStart != std::string::npos;
1910        std::string firstExt = name.substr(firstExtStart + 1, std::string::npos);
1911        bool usesUnifiedExt = hasFirstExt && (firstExt == "glsl" || firstExt == "hlsl");
1912        if (usesUnifiedExt && firstExt == "hlsl")
1913            Options |= EOptionReadHlsl;
1914        if (hasFirstExt && !usesUnifiedExt)
1915            stageName = firstExt;
1916        else if (usesUnifiedExt && hasSecondExt)
1917            stageName = name.substr(secondExtStart + 1, firstExtStart - secondExtStart - 1);
1918        else {
1919            usage();
1920            return EShLangVertex;
1921        }
1922    } else
1923        stageName = name;
1924
1925    if (stageName == "vert")
1926        return EShLangVertex;
1927    else if (stageName == "tesc")
1928        return EShLangTessControl;
1929    else if (stageName == "tese")
1930        return EShLangTessEvaluation;
1931    else if (stageName == "geom")
1932        return EShLangGeometry;
1933    else if (stageName == "frag")
1934        return EShLangFragment;
1935    else if (stageName == "comp")
1936        return EShLangCompute;
1937    else if (stageName == "rgen")
1938        return EShLangRayGen;
1939    else if (stageName == "rint")
1940        return EShLangIntersect;
1941    else if (stageName == "rahit")
1942        return EShLangAnyHit;
1943    else if (stageName == "rchit")
1944        return EShLangClosestHit;
1945    else if (stageName == "rmiss")
1946        return EShLangMiss;
1947    else if (stageName == "rcall")
1948        return EShLangCallable;
1949    else if (stageName == "mesh")
1950        return EShLangMesh;
1951    else if (stageName == "task")
1952        return EShLangTask;
1953
1954    usage();
1955    return EShLangVertex;
1956}
1957
1958//
1959// Read a file's data into a string, and compile it using the old interface ShCompile,
1960// for non-linkable results.
1961//
1962void CompileFile(const char* fileName, ShHandle compiler)
1963{
1964    int ret = 0;
1965    char* shaderString;
1966    if ((Options & EOptionStdin) != 0) {
1967        std::istreambuf_iterator<char> begin(std::cin), end;
1968        std::string tempString(begin, end);
1969        shaderString = strdup(tempString.c_str());
1970    } else {
1971        shaderString = ReadFileData(fileName);
1972    }
1973
1974    // move to length-based strings, rather than null-terminated strings
1975    int* lengths = new int[1];
1976    lengths[0] = (int)strlen(shaderString);
1977
1978    EShMessages messages = EShMsgDefault;
1979    SetMessageOptions(messages);
1980
1981    if (UserPreamble.isSet())
1982        Error("-D, -U and -P options require -l (linking)\n");
1983
1984    for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1985        for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
1986            // ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
1987            ret = ShCompile(compiler, &shaderString, 1, nullptr, EShOptNone, GetResources(), 0,
1988                            (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages, fileName);
1989            // const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
1990            //                         "or should be l", "ine 1", "string 5\n", "float glo", "bal",
1991            //                         ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
1992            // const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
1993            // ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
1994        }
1995
1996        if (Options & EOptionMemoryLeakMode)
1997            glslang::OS_DumpMemoryCounters();
1998    }
1999
2000    delete [] lengths;
2001    FreeFileData(shaderString);
2002
2003    if (ret == 0)
2004        CompileFailed = true;
2005}
2006
2007//
2008//   print usage to stdout
2009//
2010void usage()
2011{
2012    printf("Usage: glslang [option]... [file]...\n"
2013           "\n"
2014           "'file' with one of the following three endings can be auto-classified:\n"
2015           "1) .<stage>, where <stage> is one of:\n"
2016           "    vert    for a vertex shader\n"
2017           "    tesc    for a tessellation control shader\n"
2018           "    tese    for a tessellation evaluation shader\n"
2019           "    geom    for a geometry shader\n"
2020           "    frag    for a fragment shader\n"
2021           "    comp    for a compute shader\n"
2022           "    mesh    for a mesh shader\n"
2023           "    task    for a task shader\n"
2024           "    rgen    for a ray generation shader\n"
2025           "    rint    for a ray intersection shader\n"
2026           "    rahit   for a ray any hit shader\n"
2027           "    rchit   for a ray closest hit shader\n"
2028           "    rmiss   for a ray miss shader\n"
2029           "    rcall   for a ray callable shader\n"
2030           "2) .<stage>.glsl or .<stage>.hlsl compound suffix, where stage options are\n"
2031           "   described above\n"
2032           "3) .conf, to provide a config file that replaces the default configuration (see\n"
2033           "   -c option below for generating a template)\n"
2034           "\n"
2035           "Options:\n"
2036           "  -C          cascading errors; risk crash from accumulation of error recoveries\n"
2037           "  -D          input is HLSL (this is the default when any suffix is .hlsl)\n"
2038           "  -D<name[=def]> | --D <name[=def]> | --define-macro <name[=def]>\n"
2039           "              define a pre-processor macro\n"
2040           "  -E          print pre-processed GLSL; cannot be used with -l; errors will\n"
2041           "              appear on stderr\n"
2042           "  -G[ver]     create SPIR-V binary under OpenGL semantics; turns on -l; default\n"
2043           "              file name is <stage>.spv (-o overrides this); ver, when present,\n"
2044           "              is the version of the input semantics which will appear in\n"
2045           "              '#define GL_SPIRV ver'; --client opengl100 is the same as -G100; a\n"
2046           "              --target-env for OpenGL will also imply -G; currently only\n"
2047           "              supports GLSL\n"
2048           "  -H          print human readable form of SPIR-V; turns on -V\n"
2049           "  -I<dir>     add <dir> to the include search path; includer's directory is\n"
2050           "              searched first, followed by left-to-right order of -I\n"
2051           "  -O          optimizes SPIR-V for performance\n"
2052           "  -Os         optimizes SPIR-V to minimize size\n"
2053           "  -Od         disables optimization; may cause illegal SPIR-V for HLSL\n"
2054           "  -P<text> | --P <text> | --preamble-text <text>\n"
2055           "              inject custom preamble text which is treated as if it appeared\n"
2056           "              immediately after the version declaration (if any)\n"
2057           "  -R          use relaxed verification rules for generating Vulkan SPIR-V,\n"
2058           "              allowing the use of default uniforms, atomic_uints, and the\n"
2059           "              gl_VertexID and gl_InstanceID keywords\n"
2060           "  -S <stage>  uses the specified <stage> rather than parsing the file extension;\n"
2061           "              choices for <stage> include vert, tesc, tese, geom, frag, and\n"
2062           "              comp; a full list of options is given above\n"
2063           "  -U<name> | --undef-macro <name> | --U <name>\n"
2064           "              undefine a pre-processor macro\n"
2065           "  -V[ver]     create SPIR-V binary under Vulkan semantics; turns on -l; default\n"
2066           "              file name is <stage>.spv (-o overrides this); ver, when present,\n"
2067           "              is the version of the input semantics which will appear in\n"
2068           "              '#define VULKAN ver'; --client vulkan100 is the same as -V100; a\n"
2069           "              '--target-env' for Vulkan will also imply '-V'\n"
2070           "  -c          configuration dump; creates the default configuration file\n"
2071           "              (redirect to a .conf file)\n"
2072           "  -d          default to desktop (#version 110) when there is no shader #version\n"
2073           "              (default is ES version 100)\n"
2074           "  -e <name> | --entry-point <name>\n"
2075           "              specify <name> as the entry-point function name\n"
2076           "  -f{hlsl_functionality1}\n"
2077           "              'hlsl_functionality1' enables use of the\n"
2078           "              SPV_GOOGLE_hlsl_functionality1 extension\n"
2079           "  -g          generate debug information\n"
2080           "  -g0         strip debug information\n"
2081           "  -gV         generate nonsemantic shader debug information\n"
2082           "  -gVS        generate nonsemantic shader debug information with source\n"
2083           "  -gN         generate debug information for the source file name only\n"
2084           "  -h | --help print this usage message\n"
2085           "  -i          intermediate tree (glslang AST) is printed out\n"
2086           "  -l          link all input files together to form a single module\n"
2087           "  -m          memory leak mode\n"
2088           "  -o <file>   save binary to <file>; requires a binary option (e.g., -V)\n"
2089           "  -q          dump reflection query database; requires -l for linking\n"
2090           "  -r | --relaxed-errors\n"
2091           "              relaxed GLSL semantic error-checking mode\n"
2092           "  -s          silence syntax and semantic error reporting\n"
2093           "  -t          multi-threaded mode\n"
2094           "  -u<name>:<loc>\n"
2095           "              specify a uniform location override for --aml\n"
2096           "  -v | --version\n"
2097           "              print version strings\n"
2098           "  -w | --suppress-warnings\n"
2099           "              suppress GLSL warnings, except as required by '#extension : warn'\n"
2100           "  -x          save binary output as text-based 32-bit hexadecimal numbers\n"
2101           "  --absolute-path                   prints absolute path for messages\n"
2102           "  --relax-set-binding-limits        allow larger layout(set) and\n"
2103           "                                    layout(binding) values\n"
2104           "  --auto-map-binding | --auto-map-bindings | --amb\n"
2105           "                                    automatically bind uniform variables without\n"
2106           "                                    explicit bindings\n"
2107           "  --auto-map-locations | --aml      automatically locate input/output lacking\n"
2108           "                                    'location' (fragile, not cross stage)\n"
2109           "  --auto-sampled-textures           removes sampler variables and converts\n"
2110           "                                    existing textures to sampled textures\n"
2111           "  --client {vulkan<ver> | opengl<ver>}\n"
2112           "                                    see -V and -G\n"
2113           "  --depfile <file>                  writes depfile for build systems\n"
2114           "  --discard-is-terminate            map GLSL discard to OpTerminateInvocation\n"
2115           "                                    instead of OpDemoteToHelperInvocation\n"
2116           "  --dump-builtin-symbols            prints builtin symbol table prior each\n"
2117           "                                    compile\n"
2118           "  -dumpfullversion | -dumpversion   print bare major.minor.patchlevel\n"
2119           "  --enhanced-msgs                   print more readable error messages (GLSL\n"
2120           "                                    only)\n"
2121           "  --error-column                    display the column of the error along the\n"
2122           "                                    line\n"
2123           "  --flatten-uniform-array | --flatten-uniform-arrays | --fua\n"
2124           "                                    flatten uniform texture/sampler arrays to\n"
2125           "                                    scalars\n"
2126           "  --glsl-version {100 | 110 | 120 | 130 | 140 | 150 |\n"
2127           "                  300es | 310es | 320es | 330 |\n"
2128           "                  400 | 410 | 420 | 430 | 440 | 450 | 460}\n"
2129           "                                    set GLSL version; overrides #version in\n"
2130           "                                    shader source\n"
2131           "  --hlsl-dx-position-w              W component of SV_Position in HLSL fragment\n"
2132           "                                    shaders compatible with DirectX\n"
2133           "  --hlsl-dx9-compatible             interprets sampler declarations as a\n"
2134           "                                    texture/sampler combo like DirectX9 would,\n"
2135           "                                    and recognizes DirectX9-specific semantics\n"
2136           "  --hlsl-enable-16bit-types         allow 16-bit types in SPIR-V for HLSL\n"
2137           "  --hlsl-iomap | --hlsl-iomapper | --hlsl-iomapping\n"
2138           "                                    perform IO mapping in HLSL register space\n"
2139           "  --hlsl-offsets                    allow block offsets to follow HLSL rules;\n"
2140           "                                    works independently of source language\n"
2141           "  --invert-y | --iy                 invert position.Y output in vertex shader\n"
2142           "  --keep-uncalled | --ku            don't eliminate uncalled functions\n"
2143           "  --lto                             perform link time optimization\n"
2144           "  --nan-clamp                       favor non-NaN operand in min, max, and clamp\n"
2145           "  --no-link                         only compile shader; do not link (GLSL only)\n"
2146           "                                    NOTE: this option will set the export\n"
2147           "                                          linkage attribute on all functions\n"
2148           "  --no-storage-format | --nsf       use Unknown image format\n"
2149           "  --quiet                           do not print anything to stdout unless\n"
2150           "                                    requested by another option\n"
2151           "  --reflect-all-block-variables     reflect all variables in blocks, whether\n"
2152           "                                    inactive or active\n"
2153           "  --reflect-basic-array-suffix      arrays of basic types will have trailing [0]\n"
2154           "  --reflect-intermediate-io         reflection includes inputs/outputs of linked\n"
2155           "                                    shaders rather than just vertex/fragment\n"
2156           "  --reflect-separate-buffers        reflect buffer variables and blocks\n"
2157           "                                    separately to uniforms\n"
2158           "  --reflect-strict-array-suffix     use strict array suffix rules when\n"
2159           "                                    reflecting\n"
2160           "  --reflect-unwrap-io-blocks        unwrap input/output blocks the same as\n"
2161           "                                    uniform blocks\n"
2162           "  --resource-set-binding <stage> [name] <set> [binding]...\n"
2163           "                                    set descriptor set and binding for\n"
2164           "                                    individual resources\n"
2165           "  --resource-set-binding [stage] <set>\n"
2166           "                                    set descriptor set for all resources\n"
2167           "  --resource-set-bindings | --rsb   synonyms for --resource-set-binding\n"
2168           "  --set-atomic-counter-block <name> <set>\n"
2169           "                                    set name and descriptor set for atomic\n"
2170           "                                    counter blocks with -R opt\n"
2171           "  --sacb                            synonym for set-atomic-counter-block\n"
2172           "  --set-block-backing name {uniform | buffer | push_constant}\n"
2173           "                                    changes the backing type of a uniform,\n"
2174           "                                    buffer, or push_constant block declared in\n"
2175           "                                    the program when using the -R option; this\n"
2176           "                                    can be used to change the backing for\n"
2177           "                                    existing blocks as well as implicit ones\n"
2178           "                                    such as 'gl_DefaultUniformBlock'\n"
2179           "  --set-default-uniform-block <name> <set> <binding>\n"
2180           "                                    set name, descriptor set, and binding for\n"
2181           "                                    global default-uniform-block with -R opt\n"
2182           "  --sdub                            synonym for set-default-uniform-block\n"
2183           "  --shift-image-binding [stage] <num>\n"
2184           "                                    base binding number for images (UAV)\n"
2185           "  --shift-image-binding [stage] <num> <set>...\n"
2186           "                                    per-descriptor-set shift values\n"
2187           "  --shift-image-bindings | --sib    synonyms for --shift-image-binding\n"
2188           "  --shift-sampler-binding [stage] <num>\n"
2189           "                                    base binding number for samplers\n"
2190           "  --shift-sampler-binding [stage] <num> <set>...\n"
2191           "                                    per-descriptor-set shift values\n"
2192           "  --shift-sampler-bindings | --ssb  synonyms for --shift-sampler-binding\n"
2193           "  --shift-ssbo-binding [stage] <num>\n"
2194           "                                    base binding number for SSBOs\n"
2195           "  --shift-ssbo-binding [stage] <num> <set>...\n"
2196           "                                    per-descriptor-set shift values\n"
2197           "  --shift-ssbo-bindings | --sbb     synonyms for --shift-ssbo-binding\n"
2198           "  --shift-texture-binding [stage] <num>\n"
2199           "                                    base binding number for textures\n"
2200           "  --shift-texture-binding [stage] <num> <set>...\n"
2201           "                                    per-descriptor-set shift values\n"
2202           "  --shift-texture-bindings | --stb  synonyms for --shift-texture-binding\n"
2203           "  --shift-uav-binding [stage] <num> base binding number for UAVs\n"
2204           "  --shift-uav-binding [stage] <num> <set>...\n"
2205           "                                    per-descriptor-set shift values\n"
2206           "  --shift-uav-bindings | --suavb    synonyms for --shift-uav-binding\n"
2207           "  --shift-ubo-binding [stage] <num> base binding number for UBOs\n"
2208           "  --shift-ubo-binding [stage] <num> <set>...\n"
2209           "                                    per-descriptor-set shift values\n"
2210           "  --shift-ubo-bindings | --sub |\n"
2211           "  --shift-cbuffer-binding | --shift-cbuffer-bindings | --scb\n"
2212           "                                    synonyms for --shift-ubo-binding\n"
2213           "  --shift-combined-sampler-binding [stage] <num>\n"
2214           "                                    base binding number for combined samplers\n"
2215           "  --shift-combined-sampler-binding [stage] <num> <set>...\n"
2216           "                                    per-descriptor-set shift values\n"
2217           "  --shift-combined-sampler-bindings | --scsb\n"
2218           "                                    synonyms for --shift-combined-sampler-binding\n"
2219           "  --shift-as-binding [stage] <num>\n"
2220           "                                    base binding number for acceleration structures\n"
2221           "  --shift-as-binding [stage] <num> <set>...\n"
2222           "                                    per-descriptor-set shift values\n"
2223           "  --shift-as-bindings | --sab\n"
2224           "                                    synonyms for --shift-as-binding\n"
2225           "  --spirv-dis                       output standard-form disassembly; works only\n"
2226           "                                    when a SPIR-V generation option is also used\n"
2227           "  --spirv-val                       execute the SPIRV-Tools validator\n"
2228           "  --source-entrypoint <name> | --sep <name>\n"
2229           "                                    the given shader source function is renamed\n"
2230           "                                    to be the <name> given in -e\n"
2231           "  --stdin                           read from stdin instead of from a file;\n"
2232           "                                    requires providing the shader stage using -S\n"
2233           "  --target-env {vulkan1.0 | vulkan1.1 | vulkan1.2 | vulkan1.3 | vulkan1.4 |\n"
2234           "                opengl | spirv1.0 | spirv1.1 | spirv1.2 | spirv1.3 |\n"
2235           "                spirv1.4 | spirv1.5 | spirv1.6}\n"
2236           "                                    set the execution environment the generated\n"
2237           "                                    code will be executed in; defaults to:\n"
2238           "                                     * vulkan1.0 under --client vulkan<ver>\n"
2239           "                                     * opengl    under --client opengl<ver>\n"
2240           "                                     * spirv1.0  under --target-env vulkan1.0\n"
2241           "                                     * spirv1.3  under --target-env vulkan1.1\n"
2242           "                                     * spirv1.5  under --target-env vulkan1.2\n"
2243           "                                     * spirv1.6  under --target-env vulkan1.3\n"
2244           "                                     * spirv1.6  under --target-env vulkan1.4\n"
2245           "                                    multiple --target-env can be specified\n"
2246           "  --uniform-base <base>             set a base to use for generated uniform\n"
2247           "                                    locations\n"
2248           "  --variable-name <name> | --vn <name>\n"
2249           "                                    creates a C header file that contains a\n"
2250           "                                    uint32_t array named <name> initialized with\n"
2251           "                                    the shader binary code\n"
2252           "  --validate-io                     validate cross stage IO\n"
2253           "  --bindings-per-resource-type\n");
2254
2255    exit(EFailUsage);
2256}
2257
2258#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
2259
2260#include <errno.h>
2261
2262int fopen_s(
2263   FILE** pFile,
2264   const char* filename,
2265   const char* mode
2266)
2267{
2268   if (!pFile || !filename || !mode) {
2269      return EINVAL;
2270   }
2271
2272   FILE* f = fopen(filename, mode);
2273   if (! f) {
2274      if (errno != 0) {
2275         return errno;
2276      } else {
2277         return ENOENT;
2278      }
2279   }
2280   *pFile = f;
2281
2282   return 0;
2283}
2284
2285#endif
2286
2287//
2288//   Malloc a string of sufficient size and read a string into it.
2289//
2290char* ReadFileData(const char* fileName)
2291{
2292    FILE *in = nullptr;
2293    int errorCode = fopen_s(&in, fileName, "r");
2294    if (errorCode || in == nullptr)
2295        Error("unable to open input file");
2296
2297    int count = 0;
2298    while (fgetc(in) != EOF)
2299        count++;
2300
2301    fseek(in, 0, SEEK_SET);
2302
2303    if (count > 3) {
2304        unsigned char head[3];
2305        if (fread(head, 1, 3, in) == 3) {
2306            if (head[0] == 0xef && head[1] == 0xbb && head[2] == 0xbf) {
2307                // skip BOM
2308                count -= 3;
2309            } else {
2310                fseek(in, 0, SEEK_SET);
2311            }
2312        } else {
2313            Error("can't read input file");
2314        }
2315    }
2316
2317    char* return_data = (char*)malloc(count + 1);  // freed in FreeFileData()
2318    if ((int)fread(return_data, 1, count, in) != count) {
2319        free(return_data);
2320        Error("can't read input file");
2321    }
2322
2323    return_data[count] = '\0';
2324    fclose(in);
2325
2326    return return_data;
2327}
2328
2329void FreeFileData(char* data)
2330{
2331    free(data);
2332}
2333
2334void InfoLogMsg(const char* msg, const char* name, const int num)
2335{
2336    if (num >= 0 )
2337        printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
2338    else
2339        printf("#### %s %s INFO LOG ####\n", msg, name);
2340}