summaryrefslogtreecommitdiff
path: root/source/core/slang-cpp-compiler.h
blob: 60b534556f3082b3f9cb022c22c44f57b92b7f9f (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
#ifndef SLANG_CPP_COMPILER_H
#define SLANG_CPP_COMPILER_H

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

#include "slang-process-util.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;  }

            /// 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
    {
        Normal,             ///< Normal optimization
        Debug,              ///< General has no optimizations
    };

    enum DebugInfoType
    {
        None,               ///< Binary has no debug information
        Maximum,            ///< Has maximum debug information
        Normal,             ///< Has normal debug information
    };
    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,
            };
        };

        OptimizationLevel optimizationLevel = OptimizationLevel::Debug;
        DebugInfoType debugInfoType = DebugInfoType::Normal;
        TargetType targetType = TargetType::Executable;
        SourceType sourceType = SourceType::CPP;

        Flags flags = Flag::EnableExceptionHandling;

        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 OutputMessage
    {
        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(OutputMessage::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
    };

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

            /// Stores in outCounts, the amount of messages for the stage of each type
        Int countByStage(OutputMessage::Stage stage, Index outCounts[Int(OutputMessage::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 messages of the type
        void removeByType(OutputMessage::Type type);

        SlangResult result;
        List<OutputMessage> messages;
    };

        /// 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;

protected:

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

    Desc m_desc;
};

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

    typedef void(*CalcArgsFunc)(const CPPCompiler::CompileOptions& options, CommandLine& cmdLine);
    typedef SlangResult(*ParseOutputFunc)(const ExecuteResult& exeResult, Output& output);

    virtual SlangResult compile(const CompileOptions& options, Output& outOutput) SLANG_OVERRIDE;

    GenericCPPCompiler(const Desc& desc, const String& exeName, CalcArgsFunc calcArgsFunc, ParseOutputFunc parseOutputFunc) :
        Super(desc),
        m_calcArgsFunc(calcArgsFunc),
        m_parseOutputFunc(parseOutputFunc)
    {
        m_cmdLine.setExecutableFilename(exeName);
    }

    GenericCPPCompiler(const Desc& desc, const CommandLine& cmdLine, CalcArgsFunc calcArgsFunc, ParseOutputFunc parseOutputFunc) :
        Super(desc),
        m_cmdLine(cmdLine),
        m_calcArgsFunc(calcArgsFunc),
        m_parseOutputFunc(parseOutputFunc)
    {}

    CalcArgsFunc m_calcArgsFunc;
    ParseOutputFunc m_parseOutputFunc;
    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;  }

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;
};

struct CPPCompilerUtil
{
    typedef CPPCompiler::CompileOptions CompileOptions;
    typedef CPPCompiler::OptimizationLevel OptimizationLevel;
    typedef CPPCompiler::TargetType TargetType;
    typedef CPPCompiler::DebugInfoType DebugInfoType;
    typedef CPPCompiler::SourceType SourceType;

    enum class MatchType
    {
        MinGreaterEqual,
        MinAbsolute,
        Newest,
    };

        /// 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(CPPCompilerSet* set);
};


}

#endif