diff options
Diffstat (limited to 'source/core')
| -rw-r--r-- | source/core/core.vcxproj | 6 | ||||
| -rw-r--r-- | source/core/core.vcxproj.filters | 12 | ||||
| -rw-r--r-- | source/core/slang-blob.cpp | 14 | ||||
| -rw-r--r-- | source/core/slang-blob.h | 126 | ||||
| -rw-r--r-- | source/core/slang-cpp-compiler.cpp | 436 | ||||
| -rw-r--r-- | source/core/slang-cpp-compiler.h | 343 | ||||
| -rw-r--r-- | source/core/slang-downstream-compiler.cpp | 558 | ||||
| -rw-r--r-- | source/core/slang-downstream-compiler.h | 403 | ||||
| -rw-r--r-- | source/core/slang-gcc-compiler-util.cpp | 41 | ||||
| -rw-r--r-- | source/core/slang-gcc-compiler-util.h | 20 | ||||
| -rw-r--r-- | source/core/slang-hex-dump-util.cpp | 112 | ||||
| -rw-r--r-- | source/core/slang-hex-dump-util.h | 6 | ||||
| -rw-r--r-- | source/core/slang-io.h | 20 | ||||
| -rw-r--r-- | source/core/slang-shared-library.h | 2 | ||||
| -rw-r--r-- | source/core/slang-string-util.cpp | 13 | ||||
| -rw-r--r-- | source/core/slang-string-util.h | 24 | ||||
| -rw-r--r-- | source/core/slang-visual-studio-compiler-util.cpp | 29 | ||||
| -rw-r--r-- | source/core/slang-visual-studio-compiler-util.h | 16 | ||||
| -rw-r--r-- | source/core/windows/slang-win-visual-studio-util.cpp | 4 | ||||
| -rw-r--r-- | source/core/windows/slang-win-visual-studio-util.h | 10 |
20 files changed, 1275 insertions, 920 deletions
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index e0cc33569..b0f33f2a2 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -174,10 +174,11 @@ <ClInclude Include="slang-array-view.h" /> <ClInclude Include="slang-array.h" /> <ClInclude Include="slang-basic.h" /> + <ClInclude Include="slang-blob.h" /> <ClInclude Include="slang-byte-encode-util.h" /> <ClInclude Include="slang-common.h" /> - <ClInclude Include="slang-cpp-compiler.h" /> <ClInclude Include="slang-dictionary.h" /> + <ClInclude Include="slang-downstream-compiler.h" /> <ClInclude Include="slang-exception.h" /> <ClInclude Include="slang-free-list.h" /> <ClInclude Include="slang-gcc-compiler-util.h" /> @@ -212,8 +213,9 @@ <ClInclude Include="windows\slang-win-visual-studio-util.h" /> </ItemGroup> <ItemGroup> + <ClCompile Include="slang-blob.cpp" /> <ClCompile Include="slang-byte-encode-util.cpp" /> - <ClCompile Include="slang-cpp-compiler.cpp" /> + <ClCompile Include="slang-downstream-compiler.cpp" /> <ClCompile Include="slang-free-list.cpp" /> <ClCompile Include="slang-gcc-compiler-util.cpp" /> <ClCompile Include="slang-hex-dump-util.cpp" /> diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters index 6042a1c22..44d199771 100644 --- a/source/core/core.vcxproj.filters +++ b/source/core/core.vcxproj.filters @@ -21,16 +21,19 @@ <ClInclude Include="slang-basic.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-blob.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-byte-encode-util.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="slang-common.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="slang-cpp-compiler.h"> + <ClInclude Include="slang-dictionary.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="slang-dictionary.h"> + <ClInclude Include="slang-downstream-compiler.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="slang-exception.h"> @@ -131,10 +134,13 @@ </ClInclude> </ItemGroup> <ItemGroup> + <ClCompile Include="slang-blob.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-byte-encode-util.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="slang-cpp-compiler.cpp"> + <ClCompile Include="slang-downstream-compiler.cpp"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="slang-free-list.cpp"> diff --git a/source/core/slang-blob.cpp b/source/core/slang-blob.cpp new file mode 100644 index 000000000..4421db09a --- /dev/null +++ b/source/core/slang-blob.cpp @@ -0,0 +1,14 @@ +#include "slang-blob.h" + +namespace Slang { + +// Allocate static const storage for the various interface IDs that the Slang API needs to expose +static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; +static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob; + +ISlangUnknown* BlobBase::getInterface(const Guid& guid) +{ + return (guid == IID_ISlangUnknown || guid == IID_ISlangBlob) ? static_cast<ISlangBlob*>(this) : nullptr; +} + +} // namespace Slang diff --git a/source/core/slang-blob.h b/source/core/slang-blob.h new file mode 100644 index 000000000..aab131a36 --- /dev/null +++ b/source/core/slang-blob.h @@ -0,0 +1,126 @@ +#ifndef SLANG_CORE_BLOB_H +#define SLANG_CORE_BLOB_H + +#include "../../slang.h" + +#include "slang-string.h" +#include "slang-list.h" + +#include <stdarg.h> + +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +namespace Slang { + +/** Base class for simple blobs. +*/ +class BlobBase : public ISlangBlob, public RefObject +{ +public: + // ISlangUnknown + SLANG_REF_OBJECT_IUNKNOWN_ALL + +protected: + ISlangUnknown* getInterface(const Guid& guid); +}; + +/** A blob that uses a `String` for its storage. +*/ +class StringBlob : public BlobBase +{ +public: + // ISlangBlob + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_string.getBuffer(); } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_string.getLength(); } + + /// Get the contained string + SLANG_FORCE_INLINE const String& getString() const { return m_string; } + + explicit StringBlob(String const& string) + : m_string(string) + {} + +protected: + String m_string; +}; + +class ListBlob : public BlobBase +{ +public: + typedef BlobBase Super; + typedef ListBlob ThisType; + + // ISlangBlob + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data.getBuffer(); } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getCount(); } + + ListBlob() {} + + ListBlob(const List<uint8_t>& data): m_data(data) {} + // Move ctor + ListBlob(List<uint8_t>&& data): m_data(data) {} + + static RefPtr<ListBlob> moveCreate(List<uint8_t>& data) { return new ListBlob(_Move(data)); } + + List<uint8_t> m_data; + +protected: + void operator=(const ThisType& rhs) = delete; +}; + +/** A blob that manages some raw data that it owns. +*/ +class RawBlob : public BlobBase +{ +public: + // ISlangBlob + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data; } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_size; } + + // Ctor + RawBlob(const void* data, size_t size) : + m_size(size) + { + m_data = malloc(size); + memcpy(m_data, data, size); + } + ~RawBlob() + { + free(m_data); + } + +protected: + void* m_data; + size_t m_size; +}; + +/// Create a blob that will retain (a copy of) raw data. +/// +inline ComPtr<ISlangBlob> createRawBlob(void const* inData, size_t size) +{ + return ComPtr<ISlangBlob>(new RawBlob(inData, size)); +} + +class ScopeRefObjectBlob : public BlobBase +{ +public: + // ISlangBlob + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_blob->getBufferPointer(); } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_blob->getBufferSize(); } + + // Ctor + ScopeRefObjectBlob(ISlangBlob* blob, RefObject* scope) : + m_blob(blob), + m_scope(scope) + { + } + +protected: + RefPtr<RefObject> m_scope; + ComPtr<ISlangBlob> m_blob; +}; + +} // namespace Slang + +#endif // SLANG_CORE_BLOB_H diff --git a/source/core/slang-cpp-compiler.cpp b/source/core/slang-cpp-compiler.cpp deleted file mode 100644 index 7ae474fe7..000000000 --- a/source/core/slang-cpp-compiler.cpp +++ /dev/null @@ -1,436 +0,0 @@ -// slang-cpp-compiler.cpp -#include "slang-cpp-compiler.h" - -#include "slang-common.h" -#include "../../slang-com-helper.h" -#include "slang-string-util.h" - -#include "slang-io.h" -#include "slang-shared-library.h" - -// if Visual Studio import the visual studio platform specific header -#if SLANG_VC -# include "windows/slang-win-visual-studio-util.h" -#endif - -#include "slang-visual-studio-compiler-util.h" -#include "slang-gcc-compiler-util.h" - -namespace Slang -{ - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ - -void CPPCompiler::Desc::appendAsText(StringBuilder& out) const -{ - out << getCompilerTypeAsText(type); - out << " "; - out << majorVersion; - out << "."; - out << minorVersion; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompiler::OutputMessage !!!!!!!!!!!!!!!!!!!!!!*/ - -/* static */UnownedStringSlice CPPCompiler::Diagnostic::getTypeText(Diagnostic::Type type) -{ - typedef Diagnostic::Type Type; - switch (type) - { - default: return UnownedStringSlice::fromLiteral("Unknown"); - case Type::Info: return UnownedStringSlice::fromLiteral("Info"); - case Type::Warning: return UnownedStringSlice::fromLiteral("Warning"); - case Type::Error: return UnownedStringSlice::fromLiteral("Error"); - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompiler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ - -/* static */UnownedStringSlice CPPCompiler::getCompilerTypeAsText(CompilerType type) -{ - switch (type) - { - default: - case CompilerType::Unknown: return UnownedStringSlice::fromLiteral("Unknown"); - case CompilerType::VisualStudio:return UnownedStringSlice::fromLiteral("Visual Studio"); - case CompilerType::GCC: return UnownedStringSlice::fromLiteral("GCC"); - case CompilerType::Clang: return UnownedStringSlice::fromLiteral("Clang"); - case CompilerType::SNC: return UnownedStringSlice::fromLiteral("SNC"); - case CompilerType::GHS: return UnownedStringSlice::fromLiteral("GHS"); - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompiler::Output !!!!!!!!!!!!!!!!!!!!!!*/ - -Index CPPCompiler::Output::getCountByType(Diagnostic::Type type) const -{ - Index count = 0; - for (const auto& msg : diagnostics) - { - count += Index(msg.type == type); - } - return count; -} - -Int CPPCompiler::Output::countByStage(Diagnostic::Stage stage, Index counts[Int(Diagnostic::Type::CountOf)]) const -{ - Int count = 0; - ::memset(counts, 0, sizeof(Index) * Int(Diagnostic::Type::CountOf)); - for (const auto& diagnostic : diagnostics) - { - if (diagnostic.stage == stage) - { - count++; - counts[Index(diagnostic.type)]++; - } - } - return count++; -} - -static void _appendCounts(const Index counts[Int(CPPCompiler::Diagnostic::Type::CountOf)], StringBuilder& out) -{ - typedef CPPCompiler::Diagnostic::Type Type; - - for (Index i = 0; i < Int(Type::CountOf); i++) - { - if (counts[i] > 0) - { - out << CPPCompiler::Diagnostic::getTypeText(Type(i)) << "(" << counts[i] << ") "; - } - } -} - -static void _appendSimplified(const Index counts[Int(CPPCompiler::Diagnostic::Type::CountOf)], StringBuilder& out) -{ - typedef CPPCompiler::Diagnostic::Type Type; - for (Index i = 0; i < Int(Type::CountOf); i++) - { - if (counts[i] > 0) - { - out << CPPCompiler::Diagnostic::getTypeText(Type(i)) << " "; - } - } -} - -void CPPCompiler::Output::appendSummary(StringBuilder& out) const -{ - Index counts[Int(Diagnostic::Type::CountOf)]; - if (countByStage(Diagnostic::Stage::Compile, counts) > 0) - { - out << "Compile: "; - _appendCounts(counts, out); - out << "\n"; - } - if (countByStage(Diagnostic::Stage::Link, counts) > 0) - { - out << "Link: "; - _appendCounts(counts, out); - out << "\n"; - } -} - -void CPPCompiler::Output::appendSimplifiedSummary(StringBuilder& out) const -{ - Index counts[Int(Diagnostic::Type::CountOf)]; - if (countByStage(Diagnostic::Stage::Compile, counts) > 0) - { - out << "Compile: "; - _appendSimplified(counts, out); - out << "\n"; - } - if (countByStage(Diagnostic::Stage::Link, counts) > 0) - { - out << "Link: "; - _appendSimplified(counts, out); - out << "\n"; - } -} - -void CPPCompiler::Output::removeByType(Diagnostic::Type type) -{ - Index count = diagnostics.getCount(); - for (Index i = 0; i < count; ++i) - { - if (diagnostics[i].type == type) - { - diagnostics.removeAt(i); - i--; - count--; - } - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineCPPCompiler !!!!!!!!!!!!!!!!!!!!!!*/ - -SlangResult CommandLineCPPCompiler::compile(const CompileOptions& options, Output& outOutput) -{ - outOutput.reset(); - - // Copy the command line options - CommandLine cmdLine(m_cmdLine); - - // Append command line args to the end of cmdLine using the target specific function for the specified options - SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); - - ExecuteResult exeRes; - -#if 0 - // Test - { - String line = ProcessUtil::getCommandLineString(cmdLine); - printf("%s", line.getBuffer()); - } -#endif - - SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); - -#if 0 - { - printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode)); - } -#endif - - return parseOutput(exeRes, outOutput); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/ - -static CPPCompiler::Desc _calcCompiledWithDesc() -{ - CPPCompiler::Desc desc = {}; - -#if SLANG_VC - desc = WinVisualStudioUtil::getDesc(WinVisualStudioUtil::getCompiledVersion()); -#elif SLANG_CLANG - desc.type = CPPCompiler::CompilerType::Clang; - desc.majorVersion = Int(__clang_major__); - desc.minorVersion = Int(__clang_minor__); -#elif SLANG_SNC - desc.type = CPPCompiler::CompilerType::SNC; -#elif SLANG_GHS - desc.type = CPPCompiler::CompilerType::GHS; -#elif SLANG_GCC - desc.type = CPPCompiler::CompilerType::GCC; - desc.majorVersion = Int(__GNUC__); - desc.minorVersion = Int(__GNUC_MINOR__); -#else - desc.type = CPPCompiler::CompilerType::Unknown; -#endif - - return desc; -} - -const CPPCompiler::Desc& CPPCompilerUtil::getCompiledWithDesc() -{ - static CPPCompiler::Desc s_desc = _calcCompiledWithDesc(); - return s_desc; -} - -/* static */CPPCompiler* CPPCompilerUtil::findCompiler(const CPPCompilerSet* set, MatchType matchType, const CPPCompiler::Desc& desc) -{ - List<CPPCompiler*> compilers; - set->getCompilers(compilers); - return findCompiler(compilers, matchType, desc); -} - -/* static */CPPCompiler* CPPCompilerUtil::findCompiler(const List<CPPCompiler*>& compilers, MatchType matchType, const CPPCompiler::Desc& desc) -{ - Int bestIndex = -1; - - const CPPCompiler::CompilerType type = desc.type; - - Int maxVersionValue = 0; - Int minVersionDiff = 0x7fffffff; - - const auto descVersionValue = desc.getVersionValue(); - - for (Index i = 0; i < compilers.getCount(); ++i) - { - CPPCompiler* compiler = compilers[i]; - auto compilerDesc = compiler->getDesc(); - - if (type == compilerDesc.type) - { - const Int versionValue = compilerDesc.getVersionValue(); - switch (matchType) - { - case MatchType::MinGreaterEqual: - { - auto diff = descVersionValue - versionValue; - if (diff >= 0 && diff < minVersionDiff) - { - bestIndex = i; - minVersionDiff = diff; - } - break; - } - case MatchType::MinAbsolute: - { - auto diff = descVersionValue - versionValue; - diff = (diff >= 0) ? diff : -diff; - if (diff < minVersionDiff) - { - bestIndex = i; - minVersionDiff = diff; - } - break; - } - case MatchType::Newest: - { - if (versionValue > maxVersionValue) - { - maxVersionValue = versionValue; - bestIndex = i; - } - break; - } - } - } - } - - return (bestIndex >= 0) ? compilers[bestIndex] : nullptr; -} - -/* static */CPPCompiler* CPPCompilerUtil::findClosestCompiler(const List<CPPCompiler*>& compilers, const CPPCompiler::Desc& desc) -{ - CPPCompiler* compiler; - - compiler = findCompiler(compilers, MatchType::MinGreaterEqual, desc); - if (compiler) - { - return compiler; - } - compiler = findCompiler(compilers, MatchType::MinAbsolute, desc); - if (compiler) - { - return compiler; - } - - // If we are gcc, we can try clang and vice versa - if (desc.type == CPPCompiler::CompilerType::GCC || desc.type == CPPCompiler::CompilerType::Clang) - { - CPPCompiler::Desc compatible = desc; - compatible.type = (compatible.type == CPPCompiler::CompilerType::Clang) ? CPPCompiler::CompilerType::GCC : CPPCompiler::CompilerType::Clang; - - compiler = findCompiler(compilers, MatchType::MinGreaterEqual, compatible); - if (compiler) - { - return compiler; - } - compiler = findCompiler(compilers, MatchType::MinAbsolute, compatible); - if (compiler) - { - return compiler; - } - } - - return nullptr; -} - -static void _addGCCFamilyCompiler(const String& path, const String& inExeName, CPPCompilerSet* compilerSet) -{ - String exeName(inExeName); - if (path.getLength() > 0) - { - exeName = Path::combine(path, inExeName); - } - - CPPCompiler::Desc desc; - if (SLANG_SUCCEEDED(GCCCompilerUtil::calcVersion(exeName, desc))) - { - RefPtr<CommandLineCPPCompiler> compiler(new GCCCPPCompiler(desc)); - compiler->m_cmdLine.setExecutableFilename(exeName); - compilerSet->addCompiler(compiler); - } -} - -/* static */CPPCompiler* CPPCompilerUtil::findClosestCompiler(const CPPCompilerSet* set, const CPPCompiler::Desc& desc) -{ - CPPCompiler* compiler = set->getCompiler(desc); - if (compiler) - { - return compiler; - } - List<CPPCompiler*> compilers; - set->getCompilers(compilers); - return findClosestCompiler(compilers, desc); -} - -/* static */SlangResult CPPCompilerUtil::initializeSet(const InitializeSetDesc& desc, CPPCompilerSet* set) -{ -#if SLANG_WINDOWS_FAMILY - WinVisualStudioUtil::find(set); -#endif - - _addGCCFamilyCompiler(desc.getPath(CompilerType::Clang), "clang", set); - _addGCCFamilyCompiler(desc.getPath(CompilerType::GCC), "g++", set); - - // Set the default to the compiler closest to how this source was compiled - set->setDefaultCompiler(findClosestCompiler(set, getCompiledWithDesc())); - return SLANG_OK; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompilerFactory !!!!!!!!!!!!!!!!!!!!!!*/ - - -void CPPCompilerSet::getCompilerDescs(List<CPPCompiler::Desc>& outCompilerDescs) const -{ - outCompilerDescs.clear(); - for (CPPCompiler* compiler : m_compilers) - { - outCompilerDescs.add(compiler->getDesc()); - } -} - -Index CPPCompilerSet::_findIndex(const CPPCompiler::Desc& desc) const -{ - const Index count = m_compilers.getCount(); - for (Index i = 0; i < count; ++i) - { - if (m_compilers[i]->getDesc() == desc) - { - return i; - } - } - return -1; -} - -CPPCompiler* CPPCompilerSet::getCompiler(const CPPCompiler::Desc& compilerDesc) const -{ - const Index index = _findIndex(compilerDesc); - return index >= 0 ? m_compilers[index] : nullptr; -} - -void CPPCompilerSet::getCompilers(List<CPPCompiler*>& outCompilers) const -{ - outCompilers.clear(); - outCompilers.addRange((CPPCompiler*const*)m_compilers.begin(), m_compilers.getCount()); -} - -bool CPPCompilerSet::hasCompiler(CPPCompiler::CompilerType compilerType) const -{ - for (CPPCompiler* compiler : m_compilers) - { - const auto& desc = compiler->getDesc(); - if (desc.type == compilerType) - { - return true; - } - } - return false; -} - -void CPPCompilerSet::addCompiler(CPPCompiler* compiler) -{ - const Index index = _findIndex(compiler->getDesc()); - if (index >= 0) - { - m_compilers[index] = compiler; - } - else - { - m_compilers.add(compiler); - } -} - -} diff --git a/source/core/slang-cpp-compiler.h b/source/core/slang-cpp-compiler.h deleted file mode 100644 index f1592d240..000000000 --- a/source/core/slang-cpp-compiler.h +++ /dev/null @@ -1,343 +0,0 @@ -#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 diff --git a/source/core/slang-downstream-compiler.cpp b/source/core/slang-downstream-compiler.cpp new file mode 100644 index 000000000..52ec2fcd7 --- /dev/null +++ b/source/core/slang-downstream-compiler.cpp @@ -0,0 +1,558 @@ +// slang-downstream-compiler.cpp +#include "slang-downstream-compiler.h" + +#include "slang-common.h" +#include "../../slang-com-helper.h" +#include "slang-string-util.h" + +#include "slang-io.h" +#include "slang-shared-library.h" +#include "slang-blob.h" + +// if Visual Studio import the visual studio platform specific header +#if SLANG_VC +# include "windows/slang-win-visual-studio-util.h" +#endif + +#include "slang-visual-studio-compiler-util.h" +#include "slang-gcc-compiler-util.h" + +namespace Slang +{ + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ + +void DownstreamCompiler::Desc::appendAsText(StringBuilder& out) const +{ + out << getCompilerTypeAsText(type); + out << " "; + out << majorVersion; + out << "."; + out << minorVersion; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostic !!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* static */UnownedStringSlice DownstreamDiagnostic::getTypeText(Type type) +{ + switch (type) + { + default: return UnownedStringSlice::fromLiteral("Unknown"); + case Type::Info: return UnownedStringSlice::fromLiteral("Info"); + case Type::Warning: return UnownedStringSlice::fromLiteral("Warning"); + case Type::Error: return UnownedStringSlice::fromLiteral("Error"); + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* static */UnownedStringSlice DownstreamCompiler::getCompilerTypeAsText(CompilerType type) +{ + switch (type) + { + default: + case CompilerType::Unknown: return UnownedStringSlice::fromLiteral("Unknown"); + case CompilerType::VisualStudio:return UnownedStringSlice::fromLiteral("Visual Studio"); + case CompilerType::GCC: return UnownedStringSlice::fromLiteral("GCC"); + case CompilerType::Clang: return UnownedStringSlice::fromLiteral("Clang"); + case CompilerType::SNC: return UnownedStringSlice::fromLiteral("SNC"); + case CompilerType::GHS: return UnownedStringSlice::fromLiteral("GHS"); + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostics !!!!!!!!!!!!!!!!!!!!!!*/ + +Index DownstreamDiagnostics::getCountByType(Diagnostic::Type type) const +{ + Index count = 0; + for (const auto& msg : diagnostics) + { + count += Index(msg.type == type); + } + return count; +} + +Int DownstreamDiagnostics::countByStage(Diagnostic::Stage stage, Index counts[Int(Diagnostic::Type::CountOf)]) const +{ + Int count = 0; + ::memset(counts, 0, sizeof(Index) * Int(Diagnostic::Type::CountOf)); + for (const auto& diagnostic : diagnostics) + { + if (diagnostic.stage == stage) + { + count++; + counts[Index(diagnostic.type)]++; + } + } + return count++; +} + +static void _appendCounts(const Index counts[Int(DownstreamDiagnostic::Type::CountOf)], StringBuilder& out) +{ + typedef DownstreamDiagnostic::Type Type; + + for (Index i = 0; i < Int(Type::CountOf); i++) + { + if (counts[i] > 0) + { + out << DownstreamDiagnostic::getTypeText(Type(i)) << "(" << counts[i] << ") "; + } + } +} + +static void _appendSimplified(const Index counts[Int(DownstreamDiagnostic::Type::CountOf)], StringBuilder& out) +{ + typedef DownstreamDiagnostic::Type Type; + for (Index i = 0; i < Int(Type::CountOf); i++) + { + if (counts[i] > 0) + { + out << DownstreamDiagnostic::getTypeText(Type(i)) << " "; + } + } +} + +void DownstreamDiagnostics::appendSummary(StringBuilder& out) const +{ + Index counts[Int(Diagnostic::Type::CountOf)]; + if (countByStage(Diagnostic::Stage::Compile, counts) > 0) + { + out << "Compile: "; + _appendCounts(counts, out); + out << "\n"; + } + if (countByStage(Diagnostic::Stage::Link, counts) > 0) + { + out << "Link: "; + _appendCounts(counts, out); + out << "\n"; + } +} + +void DownstreamDiagnostics::appendSimplifiedSummary(StringBuilder& out) const +{ + Index counts[Int(Diagnostic::Type::CountOf)]; + if (countByStage(Diagnostic::Stage::Compile, counts) > 0) + { + out << "Compile: "; + _appendSimplified(counts, out); + out << "\n"; + } + if (countByStage(Diagnostic::Stage::Link, counts) > 0) + { + out << "Link: "; + _appendSimplified(counts, out); + out << "\n"; + } +} + +void DownstreamDiagnostics::removeByType(Diagnostic::Type type) +{ + Index count = diagnostics.getCount(); + for (Index i = 0; i < count; ++i) + { + if (diagnostics[i].type == type) + { + diagnostics.removeAt(i); + i--; + count--; + } + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompileResult !!!!!!!!!!!!!!!!!!!!!!*/ + +SlangResult CommandLineDownstreamCompileResult::getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) +{ + if (m_hostCallableSharedLibrary) + { + outLibrary = m_hostCallableSharedLibrary; + return SLANG_OK; + } + + // Okay we want to load + // Try loading the shared library + SharedLibrary::Handle handle; + if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(m_moduleFilePath.getBuffer(), handle))) + { + return SLANG_FAIL; + } + // The shared library needs to keep temp files in scope + RefPtr<TemporarySharedLibrary> sharedLib(new TemporarySharedLibrary(handle, m_moduleFilePath)); + sharedLib->m_temporaryFileSet = m_temporaryFiles; + + m_hostCallableSharedLibrary = sharedLib; + outLibrary = m_hostCallableSharedLibrary; + return SLANG_OK; +} + +SlangResult CommandLineDownstreamCompileResult::getBinary(ComPtr<ISlangBlob>& outBlob) +{ + if (m_binaryBlob) + { + outBlob = m_binaryBlob; + return SLANG_OK; + } + + // Read the binary + try + { + // Read the contents of the binary + List<uint8_t> contents = File::readAllBytes(m_moduleFilePath); + + m_binaryBlob = new ScopeRefObjectBlob(ListBlob::moveCreate(contents), m_temporaryFiles); + outBlob = m_binaryBlob; + return SLANG_OK; + } + catch (const Slang::IOException&) + { + return SLANG_FAIL; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/ + +SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, RefPtr<DownstreamCompileResult>& out) +{ + // Copy the command line options + CommandLine cmdLine(m_cmdLine); + + CompileOptions options(inOptions); + + // Find all the files that will be produced + RefPtr<TemporaryFileSet> productFileSet(new TemporaryFileSet); + + if (options.modulePath.getLength() == 0 || options.sourceContents.getLength() != 0) + { + String modulePath = options.modulePath; + + // If there is no module path, generate one. + if (modulePath.getLength() == 0) + { + SLANG_RETURN_ON_FAIL(File::generateTemporary(UnownedStringSlice::fromLiteral("slang-generated"), modulePath)); + options.modulePath = modulePath; + } + + if (options.sourceContents.getLength() != 0) + { + String compileSourcePath = modulePath; + + // NOTE: Strictly speaking producing filenames by modifying the generateTemporary path that may introduce a temp filename clash, but in practice is extraordinary unlikely + compileSourcePath.append("-src"); + + // Make the temporary filename have the appropriate extension. + if (options.sourceType == DownstreamCompiler::SourceType::C) + { + compileSourcePath.append(".c"); + } + else + { + compileSourcePath.append(".cpp"); + } + + // Write it out + try + { + productFileSet->add(compileSourcePath); + + File::writeAllText(compileSourcePath, options.sourceContents); + } + catch (...) + { + return SLANG_FAIL; + } + + // Add it as a source file + options.sourceFiles.add(compileSourcePath); + + // There is no source contents + options.sourceContents = String(); + } + } + + // Append command line args to the end of cmdLine using the target specific function for the specified options + SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + + String moduleFilePath; + + { + StringBuilder builder; + SLANG_RETURN_ON_FAIL(calcModuleFilePath(options, builder)); + moduleFilePath = builder.ProduceString(); + } + + { + List<String> paths; + SLANG_RETURN_ON_FAIL(calcCompileProducts(options, DownstreamCompiler::ProductFlag::All, paths)); + productFileSet->add(paths); + } + + ExecuteResult exeRes; + +#if 0 + // Test + { + String line = ProcessUtil::getCommandLineString(cmdLine); + printf("%s", line.getBuffer()); + } +#endif + + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); + +#if 0 + { + printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode)); + } +#endif + + DownstreamDiagnostics diagnostics; + SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); + + + out = new CommandLineDownstreamCompileResult(diagnostics, moduleFilePath, productFileSet); + + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ + +static DownstreamCompiler::Desc _calcCompiledWithDesc() +{ + DownstreamCompiler::Desc desc = {}; + +#if SLANG_VC + desc = WinVisualStudioUtil::getDesc(WinVisualStudioUtil::getCompiledVersion()); +#elif SLANG_CLANG + desc.type = DownstreamCompiler::CompilerType::Clang; + desc.majorVersion = Int(__clang_major__); + desc.minorVersion = Int(__clang_minor__); +#elif SLANG_SNC + desc.type = DownstreamCompiler::CompilerType::SNC; +#elif SLANG_GHS + desc.type = DownstreamCompiler::CompilerType::GHS; +#elif SLANG_GCC + desc.type = DownstreamCompiler::CompilerType::GCC; + desc.majorVersion = Int(__GNUC__); + desc.minorVersion = Int(__GNUC_MINOR__); +#else + desc.type = DownstreamCompiler::CompilerType::Unknown; +#endif + + return desc; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/ + +const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() +{ + static DownstreamCompiler::Desc s_desc = _calcCompiledWithDesc(); + return s_desc; +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompiler::Desc& desc) +{ + List<DownstreamCompiler*> compilers; + set->getCompilers(compilers); + return findCompiler(compilers, matchType, desc); +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List<DownstreamCompiler*>& compilers, MatchType matchType, const DownstreamCompiler::Desc& desc) +{ + Int bestIndex = -1; + + const DownstreamCompiler::CompilerType type = desc.type; + + Int maxVersionValue = 0; + Int minVersionDiff = 0x7fffffff; + + const auto descVersionValue = desc.getVersionValue(); + + for (Index i = 0; i < compilers.getCount(); ++i) + { + DownstreamCompiler* compiler = compilers[i]; + auto compilerDesc = compiler->getDesc(); + + if (type == compilerDesc.type) + { + const Int versionValue = compilerDesc.getVersionValue(); + switch (matchType) + { + case MatchType::MinGreaterEqual: + { + auto diff = descVersionValue - versionValue; + if (diff >= 0 && diff < minVersionDiff) + { + bestIndex = i; + minVersionDiff = diff; + } + break; + } + case MatchType::MinAbsolute: + { + auto diff = descVersionValue - versionValue; + diff = (diff >= 0) ? diff : -diff; + if (diff < minVersionDiff) + { + bestIndex = i; + minVersionDiff = diff; + } + break; + } + case MatchType::Newest: + { + if (versionValue > maxVersionValue) + { + maxVersionValue = versionValue; + bestIndex = i; + } + break; + } + } + } + } + + return (bestIndex >= 0) ? compilers[bestIndex] : nullptr; +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc) +{ + DownstreamCompiler* compiler; + + compiler = findCompiler(compilers, MatchType::MinGreaterEqual, desc); + if (compiler) + { + return compiler; + } + compiler = findCompiler(compilers, MatchType::MinAbsolute, desc); + if (compiler) + { + return compiler; + } + + // If we are gcc, we can try clang and vice versa + if (desc.type == DownstreamCompiler::CompilerType::GCC || desc.type == DownstreamCompiler::CompilerType::Clang) + { + DownstreamCompiler::Desc compatible = desc; + compatible.type = (compatible.type == DownstreamCompiler::CompilerType::Clang) ? DownstreamCompiler::CompilerType::GCC : DownstreamCompiler::CompilerType::Clang; + + compiler = findCompiler(compilers, MatchType::MinGreaterEqual, compatible); + if (compiler) + { + return compiler; + } + compiler = findCompiler(compilers, MatchType::MinAbsolute, compatible); + if (compiler) + { + return compiler; + } + } + + return nullptr; +} + +static void _addGCCFamilyCompiler(const String& path, const String& inExeName, DownstreamCompilerSet* compilerSet) +{ + String exeName(inExeName); + if (path.getLength() > 0) + { + exeName = Path::combine(path, inExeName); + } + + DownstreamCompiler::Desc desc; + if (SLANG_SUCCEEDED(GCCDownstreamCompilerUtil::calcVersion(exeName, desc))) + { + RefPtr<CommandLineDownstreamCompiler> compiler(new GCCDownstreamCompiler(desc)); + compiler->m_cmdLine.setExecutableFilename(exeName); + compilerSet->addCompiler(compiler); + } +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompiler::Desc& desc) +{ + DownstreamCompiler* compiler = set->getCompiler(desc); + if (compiler) + { + return compiler; + } + List<DownstreamCompiler*> compilers; + set->getCompilers(compilers); + return findClosestCompiler(compilers, desc); +} + +/* static */SlangResult DownstreamCompilerUtil::initializeSet(const InitializeSetDesc& desc, DownstreamCompilerSet* set) +{ +#if SLANG_WINDOWS_FAMILY + WinVisualStudioUtil::find(set); +#endif + + _addGCCFamilyCompiler(desc.getPath(CompilerType::Clang), "clang", set); + _addGCCFamilyCompiler(desc.getPath(CompilerType::GCC), "g++", set); + + // Set the default to the compiler closest to how this source was compiled + set->setDefaultCompiler(findClosestCompiler(set, getCompiledWithDesc())); + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerSet !!!!!!!!!!!!!!!!!!!!!!*/ + +void DownstreamCompilerSet::getCompilerDescs(List<DownstreamCompiler::Desc>& outCompilerDescs) const +{ + outCompilerDescs.clear(); + for (DownstreamCompiler* compiler : m_compilers) + { + outCompilerDescs.add(compiler->getDesc()); + } +} + +Index DownstreamCompilerSet::_findIndex(const DownstreamCompiler::Desc& desc) const +{ + const Index count = m_compilers.getCount(); + for (Index i = 0; i < count; ++i) + { + if (m_compilers[i]->getDesc() == desc) + { + return i; + } + } + return -1; +} + +DownstreamCompiler* DownstreamCompilerSet::getCompiler(const DownstreamCompiler::Desc& compilerDesc) const +{ + const Index index = _findIndex(compilerDesc); + return index >= 0 ? m_compilers[index] : nullptr; +} + +void DownstreamCompilerSet::getCompilers(List<DownstreamCompiler*>& outCompilers) const +{ + outCompilers.clear(); + outCompilers.addRange((DownstreamCompiler*const*)m_compilers.begin(), m_compilers.getCount()); +} + +bool DownstreamCompilerSet::hasCompiler(DownstreamCompiler::CompilerType compilerType) const +{ + for (DownstreamCompiler* compiler : m_compilers) + { + const auto& desc = compiler->getDesc(); + if (desc.type == compilerType) + { + return true; + } + } + return false; +} + +void DownstreamCompilerSet::addCompiler(DownstreamCompiler* compiler) +{ + const Index index = _findIndex(compiler->getDesc()); + if (index >= 0) + { + m_compilers[index] = compiler; + } + else + { + m_compilers.add(compiler); + } +} + +} diff --git a/source/core/slang-downstream-compiler.h b/source/core/slang-downstream-compiler.h new file mode 100644 index 000000000..12cf54a91 --- /dev/null +++ b/source/core/slang-downstream-compiler.h @@ -0,0 +1,403 @@ +#ifndef SLANG_DOWNSTREAM_COMPILER_H +#define SLANG_DOWNSTREAM_COMPILER_H + +#include "slang-common.h" +#include "slang-string.h" + +#include "slang-process-util.h" + +#include "slang-platform.h" + +#include "slang-io.h" + +#include "../../slang-com-ptr.h" + +namespace Slang +{ + +struct DownstreamDiagnostic +{ + 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(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 DownstreamDiagnostics +{ + typedef DownstreamDiagnostic Diagnostic; + + /// 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; +}; + +class DownstreamCompileResult : public RefObject +{ +public: + + virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) = 0; + virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) = 0; + + const DownstreamDiagnostics& getDiagnostics() const { return m_diagnostics; } + + /// Ctor + DownstreamCompileResult(const DownstreamDiagnostics& diagnostics): + m_diagnostics(diagnostics) + {} + +protected: + DownstreamDiagnostics m_diagnostics; +}; + +class DownstreamCompiler: public RefObject +{ +public: + typedef RefObject Super; + + typedef DownstreamCompileResult CompileResult; + + 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; + + /// The path/name of the output module. Should not have the extension, as that will be added for each of the target types. + /// If not set a module path will be internally generated internally on a command line based compiler + String modulePath; + + List<Define> defines; + + /// The contents of the source to compile. This can be empty is sourceFiles is set. + /// If the compiler is a commandLine file this source will be written to a temporary file. + String sourceContents; + /// The names/paths of source to compile. This can be empty if sourceContents is set. + List<String> sourceFiles; + + List<String> includePaths; + List<String> libraryPaths; + }; + + 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, + }; + + /// 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, RefPtr<DownstreamCompileResult>& outResult) = 0; + + /// Return the compiler type as name + static UnownedStringSlice getCompilerTypeAsText(CompilerType type); + +protected: + + DownstreamCompiler(const Desc& desc) : + m_desc(desc) + {} + + Desc m_desc; +}; + +class CommandLineDownstreamCompileResult : public DownstreamCompileResult +{ +public: + typedef DownstreamCompileResult Super; + + virtual SlangResult getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) SLANG_OVERRIDE; + virtual SlangResult getBinary(ComPtr<ISlangBlob>& outBlob) SLANG_OVERRIDE; + + CommandLineDownstreamCompileResult(const DownstreamDiagnostics& diagnostics, const String& moduleFilePath, TemporaryFileSet* temporaryFileSet) : + Super(diagnostics), + m_moduleFilePath(moduleFilePath), + m_temporaryFiles(temporaryFileSet) + { + } + + RefPtr<TemporaryFileSet> m_temporaryFiles; + +protected: + + String m_moduleFilePath; + DownstreamCompiler::CompileOptions m_options; + ComPtr<ISlangBlob> m_binaryBlob; + /// Cache of the shared library if appropriate + ComPtr<ISlangSharedLibrary> m_hostCallableSharedLibrary; +}; + +class CommandLineDownstreamCompiler : public DownstreamCompiler +{ +public: + typedef DownstreamCompiler Super; + + // DownstreamCompiler + virtual SlangResult compile(const CompileOptions& options, RefPtr<DownstreamCompileResult>& outResult) SLANG_OVERRIDE; + + // Functions to be implemented for a specific CommandLine + + /// 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; + + virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) = 0; + virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) = 0; + + CommandLineDownstreamCompiler(const Desc& desc, const String& exeName) : + Super(desc) + { + m_cmdLine.setExecutableFilename(exeName); + } + + CommandLineDownstreamCompiler(const Desc& desc, const CommandLine& cmdLine) : + Super(desc), + m_cmdLine(cmdLine) + {} + + CommandLineDownstreamCompiler(const Desc& desc):Super(desc) {} + + CommandLine m_cmdLine; +}; + +class DownstreamCompilerSet : public RefObject +{ +public: + typedef RefObject Super; + + /// Find all the available compilers + void getCompilerDescs(List<DownstreamCompiler::Desc>& outCompilerDescs) const; + /// Returns list of all compilers + void getCompilers(List<DownstreamCompiler*>& outCompilers) const; + + /// Get a compiler + DownstreamCompiler* getCompiler(const DownstreamCompiler::Desc& compilerDesc) const; + + /// Will replace if there is one with same desc + void addCompiler(DownstreamCompiler* compiler); + + /// Get a default compiler + DownstreamCompiler* getDefaultCompiler() const { return m_defaultCompiler; } + /// Set the default compiler + void setDefaultCompiler(DownstreamCompiler* compiler) { m_defaultCompiler = compiler; } + + /// True if has a compiler of the specified type + bool hasCompiler(DownstreamCompiler::CompilerType compilerType) const; + +protected: + + Index _findIndex(const DownstreamCompiler::Desc& desc) const; + + RefPtr<DownstreamCompiler> 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<DownstreamCompiler>> m_compilers; +}; + +/* Only purpose of having base-class here is to make all the DownstreamCompiler types available directly in derived Utils */ +struct DownstreamCompilerBaseUtil +{ + typedef DownstreamCompiler::CompileOptions CompileOptions; + typedef DownstreamCompiler::OptimizationLevel OptimizationLevel; + typedef DownstreamCompiler::TargetType TargetType; + typedef DownstreamCompiler::DebugInfoType DebugInfoType; + typedef DownstreamCompiler::SourceType SourceType; + typedef DownstreamCompiler::CompilerType CompilerType; + + typedef DownstreamDiagnostics::Diagnostic Diagnostic; + + typedef DownstreamCompiler::FloatingPointMode FloatingPointMode; + typedef DownstreamCompiler::ProductFlag ProductFlag; + typedef DownstreamCompiler::ProductFlags ProductFlags; +}; + +struct DownstreamCompilerUtil: public DownstreamCompilerBaseUtil +{ + 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(DownstreamCompiler::CompilerType::CountOf)]; + }; + + /// Find a compiler + static DownstreamCompiler* findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompiler::Desc& desc); + static DownstreamCompiler* findCompiler(const List<DownstreamCompiler*>& compilers, MatchType matchType, const DownstreamCompiler::Desc& desc); + + /// Find the compiler closest to the desc + static DownstreamCompiler* findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc); + static DownstreamCompiler* findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompiler::Desc& desc); + + /// Get the information on the compiler used to compile this source + static const DownstreamCompiler::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, DownstreamCompilerSet* set); +}; + +} + +#endif diff --git a/source/core/slang-gcc-compiler-util.cpp b/source/core/slang-gcc-compiler-util.cpp index 7838ca25b..ba077e0c5 100644 --- a/source/core/slang-gcc-compiler-util.cpp +++ b/source/core/slang-gcc-compiler-util.cpp @@ -11,7 +11,7 @@ namespace Slang { -/* static */SlangResult GCCCompilerUtil::parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, CPPCompiler::Desc& outDesc) +/* static */SlangResult GCCDownstreamCompilerUtil::parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, DownstreamCompiler::Desc& outDesc) { List<UnownedStringSlice> lines; StringUtil::calcLines(text, lines); @@ -55,7 +55,7 @@ namespace Slang return SLANG_FAIL; } -SlangResult GCCCompilerUtil::calcVersion(const String& exeName, CPPCompiler::Desc& outDesc) +SlangResult GCCDownstreamCompilerUtil::calcVersion(const String& exeName, DownstreamCompiler::Desc& outDesc) { CommandLine cmdLine; cmdLine.setExecutableFilename(exeName); @@ -70,11 +70,11 @@ SlangResult GCCCompilerUtil::calcVersion(const String& exeName, CPPCompiler::Des UnownedStringSlice::fromLiteral("gcc version"), UnownedStringSlice::fromLiteral("Apple LLVM version"), }; - const CPPCompiler::CompilerType types[] = + const DownstreamCompiler::CompilerType types[] = { - CPPCompiler::CompilerType::Clang, - CPPCompiler::CompilerType::GCC, - CPPCompiler::CompilerType::Clang, + DownstreamCompiler::CompilerType::Clang, + DownstreamCompiler::CompilerType::GCC, + DownstreamCompiler::CompilerType::Clang, }; SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(prefixes) == SLANG_COUNT_OF(types)); @@ -92,9 +92,9 @@ SlangResult GCCCompilerUtil::calcVersion(const String& exeName, CPPCompiler::Des return SLANG_FAIL; } -static SlangResult _parseErrorType(const UnownedStringSlice& in, CPPCompiler::Diagnostic::Type& outType) +static SlangResult _parseErrorType(const UnownedStringSlice& in, DownstreamDiagnostic::Type& outType) { - typedef CPPCompiler::Diagnostic::Type Type; + typedef DownstreamDiagnostic::Type Type; if (in == "error" || in == "fatal error") { @@ -127,9 +127,9 @@ enum class LineParseResult } // anonymous -static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParseResult& outLineParseResult, CPPCompiler::Diagnostic& outDiagnostic) +static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParseResult& outLineParseResult, DownstreamDiagnostic& outDiagnostic) { - typedef CPPCompiler::Diagnostic Diagnostic; + typedef DownstreamDiagnostic Diagnostic; typedef Diagnostic::Type Type; // Set to default case @@ -231,7 +231,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse } else if (text.startsWith("ld returned")) { - outDiagnostic.stage = CPPCompiler::Diagnostic::Stage::Link; + outDiagnostic.stage = DownstreamDiagnostic::Stage::Link; SLANG_RETURN_ON_FAIL(_parseErrorType(split[1].trim(), outDiagnostic.type)); outDiagnostic.text = line; outLineParseResult = LineParseResult::Single; @@ -285,7 +285,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse return SLANG_OK; } -/* static */SlangResult GCCCompilerUtil::parseOutput(const ExecuteResult& exeRes, CPPCompiler::Output& outOutput) +/* static */SlangResult GCCDownstreamCompilerUtil::parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput) { LineParseResult prevLineResult = LineParseResult::Ignore; @@ -294,7 +294,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse for (auto line : LineParser(exeRes.standardError.getUnownedSlice())) { - CPPCompiler::Diagnostic diagnostic; + Diagnostic diagnostic; diagnostic.reset(); LineParseResult lineRes; @@ -341,7 +341,7 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse } } - if (outOutput.has(CPPCompiler::Diagnostic::Type::Error) || exeRes.resultCode != 0) + if (outOutput.has(Diagnostic::Type::Error) || exeRes.resultCode != 0) { outOutput.result = SLANG_FAIL; } @@ -349,8 +349,10 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse return SLANG_OK; } -/* static */ SlangResult GCCCompilerUtil::calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) +/* static */ SlangResult GCCDownstreamCompilerUtil::calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) { + SLANG_ASSERT(options.modulePath.getLength()); + outPath.Clear(); switch (options.targetType) @@ -381,8 +383,10 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse return SLANG_FAIL; } -/* static */SlangResult GCCCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths) +/* static */SlangResult GCCDownstreamCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths) { + SLANG_ASSERT(options.modulePath.getLength()); + outPaths.clear(); if (flags & ProductFlag::Execution) @@ -395,8 +399,11 @@ static SlangResult _parseGCCFamilyLine(const UnownedStringSlice& line, LineParse return SLANG_OK; } -/* static */SlangResult GCCCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) +/* static */SlangResult GCCDownstreamCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) { + SLANG_ASSERT(options.sourceContents.getLength() == 0); + SLANG_ASSERT(options.modulePath.getLength()); + PlatformKind platformKind = (options.platform == PlatformKind::Unknown) ? PlatformUtil::getPlatformKind() : options.platform; if (options.sourceType == SourceType::CPP) diff --git a/source/core/slang-gcc-compiler-util.h b/source/core/slang-gcc-compiler-util.h index df3cb8a4b..ead527e0d 100644 --- a/source/core/slang-gcc-compiler-util.h +++ b/source/core/slang-gcc-compiler-util.h @@ -1,25 +1,25 @@ #ifndef SLANG_GCC_COMPILER_UTIL_H #define SLANG_GCC_COMPILER_UTIL_H -#include "slang-cpp-compiler.h" +#include "slang-downstream-compiler.h" namespace Slang { /* Utility for processing input and output of gcc-like compilers, including clang */ -struct GCCCompilerUtil : public CPPCompilerBaseUtil +struct GCCDownstreamCompilerUtil : public DownstreamCompilerBaseUtil { /// Extracts version number into desc from text (assumes gcc/clang -v layout with a line with version) - static SlangResult parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, CPPCompiler::Desc& outDesc); + static SlangResult parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, DownstreamCompiler::Desc& outDesc); /// Runs the exeName, and extracts the version info into outDesc - static SlangResult calcVersion(const String& exeName, CPPCompiler::Desc& outDesc); + static SlangResult calcVersion(const String& exeName, DownstreamCompiler::Desc& outDesc); /// Calculate gcc family compilers (including clang) cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); /// Parse ExecuteResult into Output - static SlangResult parseOutput(const ExecuteResult& exeRes, CPPCompiler::Output& outOutput); + static SlangResult parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput); /// Calculate the output module filename static SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath); @@ -28,19 +28,19 @@ struct GCCCompilerUtil : public CPPCompilerBaseUtil static SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths); }; -class GCCCPPCompiler : public CommandLineCPPCompiler +class GCCDownstreamCompiler : public CommandLineDownstreamCompiler { public: - typedef CommandLineCPPCompiler Super; - typedef GCCCompilerUtil Util; + typedef CommandLineDownstreamCompiler Super; + typedef GCCDownstreamCompilerUtil Util; // CommandLineCPPCompiler impl - just forwards to the Util virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, Output& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } + virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } virtual SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) SLANG_OVERRIDE { return Util::calcModuleFilePath(options, outPath); } virtual SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths) SLANG_OVERRIDE { return Util::calcCompileProducts(options, flags, outPaths); } - GCCCPPCompiler(const Desc& desc):Super(desc) {} + GCCDownstreamCompiler(const Desc& desc):Super(desc) {} }; } diff --git a/source/core/slang-hex-dump-util.cpp b/source/core/slang-hex-dump-util.cpp index 4a3d4ce06..1583d8461 100644 --- a/source/core/slang-hex-dump-util.cpp +++ b/source/core/slang-hex-dump-util.cpp @@ -6,6 +6,7 @@ #include "slang-writer.h" #include "../../slang-com-helper.h" +#include "slang-hash.h" namespace Slang { @@ -16,11 +17,19 @@ static const char s_hex[] = "0123456789abcdef"; /* static */SlangResult HexDumpUtil::dumpWithMarkers(const List<uint8_t>& data, int maxBytesPerLine, ISlangWriter* writer) { + return dumpWithMarkers(data.getBuffer(), data.getCount(), maxBytesPerLine, writer); +} + +/* static */SlangResult HexDumpUtil::dumpWithMarkers(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer) +{ WriterHelper helper(writer); SLANG_RETURN_ON_FAIL(helper.write(s_start.begin(), s_start.size())); - SLANG_RETURN_ON_FAIL(helper.print(" (%zu)\n", size_t(data.getCount()))); + SLANG_RETURN_ON_FAIL(helper.print(" %zu", dataCount)); - SLANG_RETURN_ON_FAIL(dump(data, maxBytesPerLine, writer)); + const int hash = GetHashCode((const char*)data, dataCount); + SLANG_RETURN_ON_FAIL(helper.print(" %d\n", hash )); + + SLANG_RETURN_ON_FAIL(dump(data, dataCount, maxBytesPerLine, writer)); SLANG_RETURN_ON_FAIL(helper.write(s_end.begin(), s_end.size())); SLANG_RETURN_ON_FAIL(helper.put("\n")); @@ -38,14 +47,19 @@ static const char s_hex[] = "0123456789abcdef"; writer->write(c, 8); } + /* static */SlangResult HexDumpUtil::dump(const List<uint8_t>& data, int maxBytesPerLine, ISlangWriter* writer) { - int maxCharsPerLine = 2 * maxBytesPerLine + 1 + maxBytesPerLine + 1; + return dump(data.getBuffer(), data.getCount(), maxBytesPerLine, writer); +} - const uint8_t* cur = data.begin(); - const uint8_t* end = data.end(); +/* static */SlangResult HexDumpUtil::dump(const uint8_t* data, size_t dataCount, int maxBytesPerLine, ISlangWriter* writer) +{ + int maxCharsPerLine = 2 * maxBytesPerLine + 1 + maxBytesPerLine + 1; - + const uint8_t* cur = data; + const uint8_t* end = data + dataCount; + while (cur < end) { size_t count = size_t(end - cur); @@ -112,34 +126,16 @@ static int _parseHexDigit(char c) { outBytes.clear(); - bool inHex = false; - LineParser lineParser(lines); for (const auto& line : lineParser) { - if (!inHex) - { - if (line.startsWith(s_start)) - { - inHex = true; - continue; - } - } - else - { - if (line.startsWith(s_end)) - { - break; - } - } - const char* cur = line.begin(); const char* end = line.end(); while(cur + 2 <= end) { const char c = cur[0]; - if (c == ' ' || c== '\n' || c == '\r' || c == '\t') + if (c == ' ' || c == '\n' || c == '\r' || c == '\t') { // Skip to next line break; @@ -160,35 +156,59 @@ static int _parseHexDigit(char c) return SLANG_OK; } +static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& ioRemaining, UnownedStringSlice& outLine) +{ + // Find the start line + UnownedStringSlice line; + while (StringUtil::extractLine(ioRemaining, line)) + { + if (line.startsWith(find)) + { + outLine = line; + return SLANG_OK; + } + } + return SLANG_FAIL; +} + +/* static */SlangResult HexDumpUtil::findStartAndEndLines(const UnownedStringSlice& lines, UnownedStringSlice& outStart, UnownedStringSlice& outEnd) +{ + UnownedStringSlice remaining(lines); + SLANG_RETURN_ON_FAIL(_findLine(s_start, remaining, outStart)); + SLANG_RETURN_ON_FAIL(_findLine(s_end, remaining, outEnd)); + return SLANG_OK; +} + /* static */SlangResult HexDumpUtil::parseWithMarkers(const UnownedStringSlice& lines, List<uint8_t>& outBytes) { - UnownedStringSlice remaining(lines), line; + UnownedStringSlice startLine, endLine; + SLANG_RETURN_ON_FAIL(findStartAndEndLines(lines, startLine, endLine)); - while(StringUtil::extractLine(remaining, line)) + int hash; + size_t size; { - if (line.startsWith(s_start)) + // Get the size and the hash + List<UnownedStringSlice> slices; + StringUtil::split(startLine, ' ', slices); + if (slices.getCount() != 3) { - // Extract next line - if (!StringUtil::extractLine(remaining, line)) - { - return SLANG_FAIL; - } - // It's the start line - UnownedStringSlice startLine = line; - - // Look for the ending line - do - { - if (line.startsWith(s_end)) - { - return parse(UnownedStringSlice(startLine.begin(), line.begin()), outBytes); - } - } - while ( StringUtil::extractLine(remaining, line)); + return SLANG_FAIL; } + // Extract the size + size = StringToInt(String(slices[1])); + hash = int(StringToInt(String(slices[2]))); } - return SLANG_FAIL; + SLANG_RETURN_ON_FAIL(parse(UnownedStringSlice(startLine.end(), endLine.begin()), outBytes)); + + // Calc the hash + const int readHash = GetHashCode((const char*)outBytes.begin(), outBytes.getCount()); + + if (readHash != hash || size_t(outBytes.getCount()) != size) + { + return SLANG_FAIL; + } + return SLANG_OK; } } diff --git a/source/core/slang-hex-dump-util.h b/source/core/slang-hex-dump-util.h index fefe84a17..f38bfde78 100644 --- a/source/core/slang-hex-dump-util.h +++ b/source/core/slang-hex-dump-util.h @@ -15,15 +15,21 @@ struct HexDumpUtil /// Dump data to writer, with lines starting with hex data static SlangResult dump(const List<uint8_t>& data, int numBytesPerLine, ISlangWriter* writer); + static SlangResult dump(const uint8_t* data, size_t dataCount, int numBytesPerLine, ISlangWriter* writer); + /// Dump a single value static void dump(uint32_t value, ISlangWriter* writer); static SlangResult dumpWithMarkers(const List<uint8_t>& data, int numBytesPerLine, ISlangWriter* writer); + static SlangResult dumpWithMarkers(const uint8_t* data, size_t dataSize, int numBytesPerLine, ISlangWriter* writer); + /// Parses lines formatted by dump, back into bytes static SlangResult parse(const UnownedStringSlice& lines, List<uint8_t>& outBytes); static SlangResult parseWithMarkers(const UnownedStringSlice& lines, List<uint8_t>& outBytes); + + static SlangResult findStartAndEndLines(const UnownedStringSlice& lines, UnownedStringSlice& outStart, UnownedStringSlice& outEnd); }; } diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 758a05edb..a42a6991b 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -91,8 +91,12 @@ namespace Slang }; // Helper class to clean up temporary files on dtor - struct TemporaryFileSet + class TemporaryFileSet: public RefObject { + public: + typedef RefObject Super; + typedef TemporaryFileSet ThisType; + void remove(const String& path) { if (const Index index = m_paths.indexOf(path) >= 0) @@ -119,6 +123,12 @@ namespace Slang { m_paths.clear(); } + + void swapWith(ThisType& rhs) + { + m_paths.swapWith(rhs.m_paths); + } + ~TemporaryFileSet() { for (const auto& path : m_paths) @@ -126,7 +136,15 @@ namespace Slang File::remove(path); } } + /// Default Ctor + TemporaryFileSet() {} + List<String> m_paths; + + private: + // Disable ctor/assignment + TemporaryFileSet(const ThisType& rhs) = delete; + void operator=(const ThisType& rhs) = delete; }; } diff --git a/source/core/slang-shared-library.h b/source/core/slang-shared-library.h index 675ee5cae..517292908 100644 --- a/source/core/slang-shared-library.h +++ b/source/core/slang-shared-library.h @@ -103,7 +103,7 @@ public: virtual ~TemporarySharedLibrary(); /// Any files specified in this set will be deleted on exit - TemporaryFileSet m_temporaryFileSet; + RefPtr<TemporaryFileSet> m_temporaryFileSet; protected: String m_path; diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp index 4295a2c52..cd79ffce7 100644 --- a/source/core/slang-string-util.cpp +++ b/source/core/slang-string-util.cpp @@ -1,17 +1,8 @@ #include "slang-string-util.h" -namespace Slang { - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringBlob !!!!!!!!!!!!!!!!!!!!!!!!!!! - -// Allocate static const storage for the various interface IDs that the Slang API needs to expose -static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; -static const Guid IID_ISlangBlob = SLANG_UUID_ISlangBlob; +#include "slang-blob.h" -/* static */ISlangUnknown* StringBlob::getInterface(const Guid& guid) -{ - return (guid == IID_ISlangUnknown || guid == IID_ISlangBlob) ? static_cast<ISlangBlob*>(this) : nullptr; -} +namespace Slang { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index 77b7ca2a3..16588bd35 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -11,30 +11,6 @@ namespace Slang { -/** A blob that uses a `String` for its storage. -*/ -class StringBlob : public ISlangBlob, public RefObject -{ -public: - // ISlangUnknown - SLANG_REF_OBJECT_IUNKNOWN_ALL - - // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_string.getBuffer(); } - SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_string.getLength(); } - - /// Get the contained string - SLANG_FORCE_INLINE const String& getString() const { return m_string; } - - explicit StringBlob(String const& string) - : m_string(string) - {} - -protected: - ISlangUnknown* getInterface(const Guid& guid); - String m_string; -}; - struct StringUtil { /// Split in, by specified splitChar into slices out diff --git a/source/core/slang-visual-studio-compiler-util.cpp b/source/core/slang-visual-studio-compiler-util.cpp index 8b4598b43..8797c3384 100644 --- a/source/core/slang-visual-studio-compiler-util.cpp +++ b/source/core/slang-visual-studio-compiler-util.cpp @@ -12,6 +12,8 @@ namespace Slang /* static */ SlangResult VisualStudioCompilerUtil::calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) { + SLANG_ASSERT(options.modulePath.getLength()); + outPath.Clear(); switch (options.targetType) @@ -39,6 +41,8 @@ namespace Slang /* static */SlangResult VisualStudioCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths) { + SLANG_ASSERT(options.modulePath.getLength()); + outPaths.clear(); if (flags & ProductFlag::Execution) @@ -72,6 +76,9 @@ namespace Slang /* static */SlangResult VisualStudioCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) { + SLANG_ASSERT(options.sourceContents.getLength() == 0); + SLANG_ASSERT(options.modulePath.getLength()); + // https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=vs-2019 cmdLine.addArg("/nologo"); @@ -242,9 +249,9 @@ namespace Slang return SLANG_OK; } -static SlangResult _parseErrorType(const UnownedStringSlice& in, CPPCompiler::Diagnostic::Type& outType) +static SlangResult _parseErrorType(const UnownedStringSlice& in, DownstreamDiagnostics::Diagnostic::Type& outType) { - typedef CPPCompiler::Diagnostic::Type Type; + typedef DownstreamDiagnostics::Diagnostic::Type Type; if (in == "error" || in == "fatal error") { @@ -265,9 +272,9 @@ static SlangResult _parseErrorType(const UnownedStringSlice& in, CPPCompiler::Di return SLANG_OK; } -static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, CPPCompiler::Diagnostic& outDiagnostic) +static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, DownstreamDiagnostics::Diagnostic& outDiagnostic) { - typedef CPPCompiler::Diagnostic Diagnostic; + typedef DownstreamDiagnostics::Diagnostic Diagnostic; UnownedStringSlice linkPrefix = UnownedStringSlice::fromLiteral("LINK :"); if (line.startsWith(linkPrefix)) @@ -389,11 +396,11 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, CPPCom return SLANG_OK; } -/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, CPPCompiler::Output& outOutput) +/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outDiagnostics) { - outOutput.reset(); + outDiagnostics.reset(); - outOutput.rawDiagnostics = exeRes.standardOutput; + outDiagnostics.rawDiagnostics = exeRes.standardOutput; for (auto line : LineParser(exeRes.standardOutput.getUnownedSlice())) { @@ -402,17 +409,17 @@ static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, CPPCom fprintf(stdout, "\n"); #endif - CPPCompiler::Diagnostic diagnostic; + Diagnostic diagnostic; if (SLANG_SUCCEEDED(_parseVisualStudioLine(line, diagnostic))) { - outOutput.diagnostics.add(diagnostic); + outDiagnostics.diagnostics.add(diagnostic); } } // if it has a compilation error.. set on output - if (outOutput.has(CPPCompiler::Diagnostic::Type::Error)) + if (outDiagnostics.has(Diagnostic::Type::Error)) { - outOutput.result = SLANG_FAIL; + outDiagnostics.result = SLANG_FAIL; } return SLANG_OK; diff --git a/source/core/slang-visual-studio-compiler-util.h b/source/core/slang-visual-studio-compiler-util.h index 1e2fbb318..3571f4b42 100644 --- a/source/core/slang-visual-studio-compiler-util.h +++ b/source/core/slang-visual-studio-compiler-util.h @@ -1,37 +1,37 @@ #ifndef SLANG_VISUAL_STUDIO_COMPILER_UTIL_H #define SLANG_VISUAL_STUDIO_COMPILER_UTIL_H -#include "slang-cpp-compiler.h" +#include "slang-downstream-compiler.h" namespace Slang { -struct VisualStudioCompilerUtil : public CPPCompilerBaseUtil +struct VisualStudioCompilerUtil : public DownstreamCompilerBaseUtil { /// Calculate Visual Studio family compilers cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); /// Parse Visual Studio exeRes into CPPCompiler::Output - static SlangResult parseOutput(const ExecuteResult& exeRes, CPPCompiler::Output& outOutput); + static SlangResult parseOutput(const ExecuteResult& exeRes, DownstreamDiagnostics& outOutput); static SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath); static SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, List<String>& outPaths); }; -class VisualStudioCPPCompiler : public CommandLineCPPCompiler +class VisualStudioDownstreamCompiler : public CommandLineDownstreamCompiler { public: - typedef CommandLineCPPCompiler Super; + typedef CommandLineDownstreamCompiler Super; typedef VisualStudioCompilerUtil Util; - // CommandLineCPPCompiler impl - just forwards to the Util + // CommandLineDownstreamCompiler impl - just forwards to the Util virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, Output& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } + virtual SlangResult parseOutput(const ExecuteResult& exeResult, DownstreamDiagnostics& output) SLANG_OVERRIDE { return Util::parseOutput(exeResult, output); } virtual SlangResult calcModuleFilePath(const CompileOptions& options, StringBuilder& outPath) SLANG_OVERRIDE { return Util::calcModuleFilePath(options, outPath); } virtual SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags productFlags, List<String>& outPaths) SLANG_OVERRIDE { return Util::calcCompileProducts(options, productFlags, outPaths); } - VisualStudioCPPCompiler(const Desc& desc):Super(desc) {} + VisualStudioDownstreamCompiler(const Desc& desc):Super(desc) {} }; diff --git a/source/core/windows/slang-win-visual-studio-util.cpp b/source/core/windows/slang-win-visual-studio-util.cpp index 260f3f56f..078406d99 100644 --- a/source/core/windows/slang-win-visual-studio-util.cpp +++ b/source/core/windows/slang-win-visual-studio-util.cpp @@ -278,7 +278,7 @@ static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& out return SLANG_FAIL; } -/* static */SlangResult WinVisualStudioUtil::find(CPPCompilerSet* set) +/* static */SlangResult WinVisualStudioUtil::find(DownstreamCompilerSet* set) { const int versionCount = SLANG_COUNT_OF(s_versionInfos); @@ -290,7 +290,7 @@ static SlangResult _find(int versionIndex, WinVisualStudioUtil::VersionPath& out VersionPath versionPath; if (!set->getCompiler(desc) && SLANG_SUCCEEDED(_find(i, versionPath))) { - RefPtr<CommandLineCPPCompiler> compiler = new VisualStudioCPPCompiler(desc); + RefPtr<CommandLineDownstreamCompiler> compiler = new VisualStudioDownstreamCompiler(desc); calcExecuteCompilerArgs(versionPath, compiler->m_cmdLine); set->addCompiler(compiler); } diff --git a/source/core/windows/slang-win-visual-studio-util.h b/source/core/windows/slang-win-visual-studio-util.h index 34be8473d..1122fccb7 100644 --- a/source/core/windows/slang-win-visual-studio-util.h +++ b/source/core/windows/slang-win-visual-studio-util.h @@ -6,7 +6,7 @@ #include "../slang-process-util.h" -#include "../slang-cpp-compiler.h" +#include "../slang-downstream-compiler.h" namespace Slang { @@ -31,7 +31,7 @@ struct WinVisualStudioUtil static SlangResult find(Version version, VersionPath& outPath); /// Find and add to the set (if not already there) - static SlangResult find(CPPCompilerSet* set); + static SlangResult find(DownstreamCompilerSet* set); /// Create the cmdLine to start compiler for specified path static void calcExecuteCompilerArgs(const VersionPath& versionPath, CommandLine& outCmdLine); @@ -52,10 +52,10 @@ struct WinVisualStudioUtil static void append(Version version, StringBuilder& outBuilder); /// Get version as desc - static CPPCompiler::Desc getDesc(Version version) + static DownstreamCompiler::Desc getDesc(Version version) { - CPPCompiler::Desc desc; - desc.type = CPPCompiler::CompilerType::VisualStudio; + DownstreamCompiler::Desc desc; + desc.type = DownstreamCompiler::CompilerType::VisualStudio; desc.majorVersion = Int(version) / 10; desc.minorVersion = Int(version) % 10; return desc; |
