summaryrefslogtreecommitdiffstats
path: root/source/core/slang-cpp-compiler.h
blob: f1592d2406160c145b9503048ae0166b23ea1ea7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
#ifndef SLANG_CPP_COMPILER_H
#define SLANG_CPP_COMPILER_H

#include "slang-common.h"
#include "slang-string.h"

#include "slang-process-util.h"

#include "slang-platform.h"

namespace Slang
{

class CPPCompiler: public RefObject
{
public:
    typedef RefObject Super;
    enum class CompilerType
    {
        Unknown,
        VisualStudio,
        GCC,
        Clang,
        SNC,
        GHS,
        CountOf,
    };
    enum class SourceType
    {
        C,              ///< C source
        CPP,            ///< C++ source
    };

    struct Desc
    {
        typedef Desc ThisType;

        UInt GetHashCode() const { return combineHash(int(type), combineHash(int(majorVersion), int(minorVersion))); }
        bool operator==(const ThisType& rhs) const { return type == rhs.type && majorVersion == rhs.majorVersion && minorVersion == rhs.minorVersion;  }
        bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }

            /// Get the version as a value
        Int getVersionValue() const { return majorVersion * 100 + minorVersion;  }

        void appendAsText(StringBuilder& out) const;

            /// Ctor
        Desc(CompilerType inType = CompilerType::Unknown, Int inMajorVersion = 0, Int inMinorVersion = 0):type(inType), majorVersion(inMajorVersion), minorVersion(inMinorVersion) {}

        CompilerType type;                      ///< The type of the compiler
        Int majorVersion;               ///< Major version (interpretation is type specific)
        Int minorVersion;               ///< Minor version
    };

    enum class OptimizationLevel
    {
        None,           ///< Don't optimize at all. 
        Default,        ///< Default optimization level: balance code quality and compilation time. 
        High,           ///< Optimize aggressively. 
        Maximal,        ///< Include optimizations that may take a very long time, or may involve severe space-vs-speed tradeoffs 
    };

    enum class DebugInfoType
    {
        None,       ///< Don't emit debug information at all. 
        Minimal,    ///< Emit as little debug information as possible, while still supporting stack traces. 
        Standard,   ///< Emit whatever is the standard level of debug information for each target. 
        Maximal,    ///< Emit as much debug information as possible for each target. 
    };
    enum class FloatingPointMode
    {
        Default, 
        Fast,
        Precise,
    };

    enum TargetType
    {
        Executable,         ///< Produce an executable
        SharedLibrary,      ///< Produce a shared library object/dll 
        Object,             ///< Produce an object file
    };

    struct Define
    {
        String nameWithSig;             ///< If macro takes parameters include in brackets
        String value;
    };

    struct CompileOptions
    {
        typedef uint32_t Flags;
        struct Flag 
        {
            enum Enum : Flags
            {
                EnableExceptionHandling = 0x01,
                Verbose                 = 0x02,
                EnableSecurityChecks    = 0x04,
            };
        };

        OptimizationLevel optimizationLevel = OptimizationLevel::Default;
        DebugInfoType debugInfoType = DebugInfoType::Standard;
        TargetType targetType = TargetType::Executable;
        SourceType sourceType = SourceType::CPP;
        FloatingPointMode floatingPointMode = FloatingPointMode::Default;

        Flags flags = Flag::EnableExceptionHandling;

        PlatformKind platform = PlatformKind::Unknown;

        String modulePath;      ///< The path/name of the output module. Should not have the extension, as that will be added for each of the target types

        List<Define> defines;

        List<String> sourceFiles;

        List<String> includePaths;
        List<String> libraryPaths;
    };

    struct Diagnostic
    {
        enum class Type
        {
            Unknown,
            Info,
            Warning,
            Error,
            CountOf,
        };
        enum class Stage
        {
            Compile,
            Link,
        };

        void reset()
        {
            type = Type::Unknown;
            stage = Stage::Compile;
            fileLine = 0;
        }
        static UnownedStringSlice getTypeText(Diagnostic::Type type);


        Type type;                      ///< The type of error
        Stage stage;                    ///< The stage the error came from
        String text;                    ///< The text of the error
        String code;                    ///< The compiler specific error code
        String filePath;                ///< The path the error originated from
        Int fileLine;                   ///< The line number the error came from
    };

    typedef uint32_t ProductFlags;
    struct ProductFlag
    {
        enum Enum : ProductFlags
        {
            Debug               = 0x1,                ///< Used by debugger during execution
            Execution           = 0x2,                ///< Required for execution
            Compile             = 0x4,                ///< A product *required* for compilation
            Miscellaneous       = 0x8,                ///< Anything else    
        };
        enum Mask : ProductFlags
        {
            All                 = 0xf,                ///< All the flags
        };
    };

    enum class Product
    {
        DebugRun,
        Run,
        CompileTemporary,
        All,
    };

    struct Output
    {
            /// Reset to an initial empty state
        void reset() { diagnostics.clear(); rawDiagnostics = String(); result = SLANG_OK; }
        
            /// Get the number of diagnostics by type
        Index getCountByType(Diagnostic::Type type) const;
            /// True if there are any diagnostics  of the type
        bool has(Diagnostic::Type type) const { return getCountByType(type) > 0; }

            /// Stores in outCounts, the amount of diagnostics for the stage of each type
        Int countByStage(Diagnostic::Stage stage, Index outCounts[Int(Diagnostic::Type::CountOf)]) const;

            /// Append a summary to out
        void appendSummary(StringBuilder& out) const;
            /// Appends a summary that just identifies if there is an error of a type (not a count)
        void appendSimplifiedSummary(StringBuilder& out) const;
        
            /// Remove all diagnostics of the type
        void removeByType(Diagnostic::Type type);

        String rawDiagnostics;

        SlangResult result;
        List<Diagnostic> diagnostics;
    };

        /// Get the desc of this compiler
    const Desc& getDesc() const { return m_desc;  }
        /// Compile using the specified options. The result is in resOut
    virtual SlangResult compile(const CompileOptions& options, Output& outOutput) = 0;
        /// Given the compilation options and the module name, determines the actual file name used for output
    virtual SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) = 0;
        /// Given options determines the paths to products produced (including the 'moduleFilePath').
        /// Note that does *not* guarentee all products were or should be produced. Just aims to include all that could
        /// be produced, such that can be removed on completion.
    virtual SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths) = 0;

        /// Return the compiler type as name
    static UnownedStringSlice getCompilerTypeAsText(CompilerType type);

protected:

    CPPCompiler(const Desc& desc) :
        m_desc(desc)
    {}

    Desc m_desc;
};

class CommandLineCPPCompiler : public CPPCompiler
{
public:
    typedef CPPCompiler Super;

    // CPPCompiler
    virtual SlangResult compile(const CompileOptions& options, Output& outOutput) SLANG_OVERRIDE;
    
    // Functions to be implemented for a specific CommandLine    
    virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) = 0;
    virtual SlangResult parseOutput(const ExecuteResult& exeResult, Output& output) = 0;

    CommandLineCPPCompiler(const Desc& desc, const String& exeName) :
        Super(desc)
    {
        m_cmdLine.setExecutableFilename(exeName);
    }

    CommandLineCPPCompiler(const Desc& desc, const CommandLine& cmdLine) :
        Super(desc),
        m_cmdLine(cmdLine)
    {}

    CommandLineCPPCompiler(const Desc& desc):Super(desc) {}

    CommandLine m_cmdLine;
};

class CPPCompilerSet : public RefObject
{
public:
    typedef RefObject Super;

    
        /// Find all the available compilers
    void getCompilerDescs(List<CPPCompiler::Desc>& outCompilerDescs) const;
        /// Returns list of all compilers
    void getCompilers(List<CPPCompiler*>& outCompilers) const;

        /// Get a compiler
    CPPCompiler* getCompiler(const CPPCompiler::Desc& compilerDesc) const;
  
        /// Will replace if there is one with same desc
    void addCompiler(CPPCompiler* compiler);

        /// Get a default compiler
    CPPCompiler* getDefaultCompiler() const { return m_defaultCompiler;  }
        /// Set the default compiler
    void setDefaultCompiler(CPPCompiler* compiler) { m_defaultCompiler = compiler;  }

        /// True if has a compiler of the specified type
    bool hasCompiler(CPPCompiler::CompilerType compilerType) const;

protected:

    Index _findIndex(const CPPCompiler::Desc& desc) const;

    RefPtr<CPPCompiler> m_defaultCompiler;
    // This could be a dictionary/map - but doing a linear search is going to be fine and it makes
    // somethings easier.
    List<RefPtr<CPPCompiler>> m_compilers;
};

/* Only purpose of having base-class here is to make all the CPPCompiler types available directly in derived Utils */
struct CPPCompilerBaseUtil
{
    typedef CPPCompiler::CompileOptions CompileOptions;
    typedef CPPCompiler::OptimizationLevel OptimizationLevel;
    typedef CPPCompiler::TargetType TargetType;
    typedef CPPCompiler::DebugInfoType DebugInfoType;
    typedef CPPCompiler::SourceType SourceType;
    typedef CPPCompiler::CompilerType CompilerType;

    typedef CPPCompiler::Diagnostic Diagnostic;
    typedef CPPCompiler::FloatingPointMode FloatingPointMode;
    typedef CPPCompiler::ProductFlag ProductFlag;
    typedef CPPCompiler::ProductFlags ProductFlags;
};

struct CPPCompilerUtil: public CPPCompilerBaseUtil
{
    enum class MatchType
    {
        MinGreaterEqual,
        MinAbsolute,
        Newest,
    };

    struct InitializeSetDesc
    {
        const String& getPath(CompilerType type) const { return paths[int(type)]; }
        void setPath(CompilerType type, const String& path) { paths[int(type)] = path; }

        String paths[int(CPPCompiler::CompilerType::CountOf)];
    };

        /// Find a compiler
    static CPPCompiler* findCompiler(const CPPCompilerSet* set, MatchType matchType, const CPPCompiler::Desc& desc);
    static CPPCompiler* findCompiler(const List<CPPCompiler*>& compilers, MatchType matchType, const CPPCompiler::Desc& desc);

        /// Find the compiler closest to the desc 
    static CPPCompiler* findClosestCompiler(const List<CPPCompiler*>& compilers, const CPPCompiler::Desc& desc);
    static CPPCompiler* findClosestCompiler(const CPPCompilerSet* set, const CPPCompiler::Desc& desc);

        /// Get the information on the compiler used to compile this source
    static const CPPCompiler::Desc& getCompiledWithDesc();

        /// Given a set, registers compilers found through standard means and determines a reasonable default compiler if possible
    static SlangResult initializeSet(const InitializeSetDesc& desc, CPPCompilerSet* set);    
};

}

#endif