summaryrefslogtreecommitdiffstats
path: root/source/core/slang-cpp-compiler.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-06-14 10:02:04 -0400
committerGitHub <noreply@github.com>2019-06-14 10:02:04 -0400
commit7461e95210e7420d0ddf681279813f394a6fd0d8 (patch)
treea1a80a802ce1c107a691d2b0e395c4ce97f46136 /source/core/slang-cpp-compiler.cpp
parent202f993e2ced2b2a3445b54a740e47d6d8091297 (diff)
Abstract CPPCompiler (#983)
* Work in progress to be able to invoke VS from within code. * First pass at windows version of refactor of OSProcessSpawner * Closer to getting VS path lookup working. * Make OSString assignable/ctor able * Work out program files directory directly, so don't have to expand %%. * WIP: Improve handling of process spawning. * Add support for splitting input by line. * * Correctly locates visual studio install * Added functionality to invoke vs via cmd * Add option to execute the command line. * Handle in ProcessUtil for windows -> WinHandle. * Rename files slang-win-visual-studio-util.cpp/.h and slang-process-util.h * First pass at unix/linux version of ProcessUtil. * Fix reading Visual Studio path from the registry. * Get compiling on linux with. * Fix vcvarsall.bat name * Use ProcessUtil to execute external code. * Remove OSProcessSpawner. * Remove includes for "os.h" where no longer needed. * Fix tabbing issue in premake5.lua Remove test code from slang-test-main.cpp * Fix premake4.lua tabbing issue. * Small fixes to slang-process-util.h Init ExecuteResult on Win execute. * Improve comments. * Fix bug in StringUtil::calcLines - with oddly terminated source input being able to read past end. Make slang-generate use StringUtil over it's own impl. * Fix off by one bug in working out Visual Studio version. * Fix bug in calculating Visual Studio Version * Fix compilation on linux with string parameter being passed to messageFormat. * Remove erroneous use of kOSError codes - use Result. * First effort to generate standard compiler options. * Initial efforts in compiling source code in test framework for VisualStudio. * Testing compiling c code on VisualStudio on Windows. * Fix warning on linux. * Fix clang on linux warning (and therefore failing) returning a StringBuilder as String. * Disable return-std-move on clang. * CommandLine arguments are now tagged if they are escaped or not. That it is the clients responsibility to escape command lines that cannot be automatically escaped. * Add checks on unix/linux that command line args are all unescaped. * WIP getting runtime GCC to work. * First pass compiler working on unix-like targets. * Added File::remove function. * Enable c-compile.c test on 'smoke'. * WIP abstracting the CPP compiler concept. * CPPCompilerSet and CPPCompilerUtil working on windows. Problem on unix. * Used stdError for parsing of invoke of compiler to figure out verison. * Removed some code that was no longer needed from slang-cpp-compiler.cpp
Diffstat (limited to 'source/core/slang-cpp-compiler.cpp')
-rw-r--r--source/core/slang-cpp-compiler.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/source/core/slang-cpp-compiler.cpp b/source/core/slang-cpp-compiler.cpp
new file mode 100644
index 000000000..ef679d780
--- /dev/null
+++ b/source/core/slang-cpp-compiler.cpp
@@ -0,0 +1,340 @@
+// slang-cpp-compiler.cpp
+#include "slang-cpp-compiler.h"
+
+#include "slang-common.h"
+#include "../../slang-com-helper.h"
+#include "slang-string-util.h"
+
+#if SLANG_VC
+# include "windows/slang-win-visual-studio-util.h"
+#else
+# include "unix/slang-unix-cpp-compiler-util.h"
+#endif
+
+namespace Slang
+{
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GenericCPPCompiler !!!!!!!!!!!!!!!!!!!!!!*/
+
+SlangResult GenericCPPCompiler::compile(const CompileOptions& options, ExecuteResult& outResult)
+{
+ CommandLine cmdLine;
+
+ // Calculate the command line options
+ m_func(options, cmdLine);
+
+ // Set the executable
+ cmdLine.setExecutableFilename(m_exeName);
+
+#if 0
+ // Test
+ {
+ String line = ProcessUtil::getCommandLineString(cmdLine);
+ printf("%s", line.getBuffer());
+ }
+#endif
+
+ return ProcessUtil::execute(cmdLine, outResult);
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CPPCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/
+
+static bool _isDigit(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static bool _isWhiteSpace(char c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+}
+
+/* static */SlangResult CPPCompilerUtil::parseGccFamilyVersion(const UnownedStringSlice& text, const UnownedStringSlice& versionPrefix, CPPCompiler::Desc& outDesc)
+{
+ List<UnownedStringSlice> lines;
+ StringUtil::calcLines(text, lines);
+
+ for (auto line : lines)
+ {
+ if (String(line).startsWith(versionPrefix))
+ {
+ UnownedStringSlice versionSlice(line.begin() + versionPrefix.size(), line.end());
+
+ List<Int> digits;
+
+ const char* cur = versionSlice.begin();
+ const char* end = versionSlice.end();
+
+ // Consume white space
+ while (cur < end && _isWhiteSpace(*cur)) cur++;
+
+ // Version is in format 0.0.0
+ while (true)
+ {
+ Int value = 0;
+ const char* start = cur;
+ while (cur < end && _isDigit(*cur))
+ {
+ value = value * 10 + (*cur - '0');
+ cur++;
+ }
+
+ if (cur <= start)
+ {
+ break;
+ }
+
+ digits.add(value);
+
+ if (cur < end && *cur == '.')
+ {
+ cur++;
+ }
+ }
+
+ if (digits.getCount() < 2)
+ {
+ return SLANG_FAIL;
+ }
+
+ outDesc.majorVersion = digits[0];
+ outDesc.minorVersion = digits[1];
+
+ return SLANG_OK;
+ }
+ }
+
+ return SLANG_FAIL;
+}
+
+SlangResult CPPCompilerUtil::calcGccFamilyVersion(const String& exeName, const UnownedStringSlice& versionPrefix, CPPCompiler::Desc& outDesc)
+{
+ CommandLine cmdLine;
+ cmdLine.setExecutableFilename(exeName);
+ cmdLine.addArg("-v");
+
+ ExecuteResult exeRes;
+ SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes));
+ return parseGccFamilyVersion(exeRes.standardError.getUnownedSlice(), versionPrefix, outDesc);
+}
+
+static CPPCompiler::Desc _calcCompiledWithDesc()
+{
+ CPPCompiler::Desc desc = {};
+
+#if SLANG_VC
+ desc = WinVisualStudioUtil::getDesc(WinVisualStudioUtil::getCompiledVersion());
+#elif SLANG_CLANG
+ desc.type = CPPCompiler::Type::Clang;
+#elif SLANG_SNC
+ desc.type = CPPCompiler::Type::SNC;
+#elif SLANG_GHS
+ desc.type = CPPCompiler::Type::GHS;
+#elif SLANG_GCC
+ desc.type = CPPCompiler::Type::GCC;
+#else
+ desc.type = CPPCompiler::Type::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::Type 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::Type::GCC || desc.type == CPPCompiler::Type::Clang)
+ {
+ CPPCompiler::Desc compatible = desc;
+ compatible.type = (compatible.type == CPPCompiler::Type::Clang) ? CPPCompiler::Type::GCC : CPPCompiler::Type::Clang;
+
+ compiler = findCompiler(compilers, MatchType::MinGreaterEqual, compatible);
+ if (compiler)
+ {
+ return compiler;
+ }
+ compiler = findCompiler(compilers, MatchType::MinAbsolute, compatible);
+ if (compiler)
+ {
+ return compiler;
+ }
+ }
+
+ return nullptr;
+}
+
+/* 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(CPPCompilerSet* set)
+{
+#if SLANG_WINDOWS_FAMILY
+ WinVisualStudioUtil::find(set);
+#else
+ {
+ CPPCompiler::Desc desc(CPPCompiler::Type::Clang);
+ if (SLANG_SUCCEEDED(calcGccFamilyVersion("clang", UnownedStringSlice::fromLiteral("clang version"), desc)))
+ {
+ RefPtr<CPPCompiler> compiler(new GenericCPPCompiler(desc, "clang", &UnixCPPCompilerUtil::calcArgs));
+ set->addCompiler(compiler);
+ }
+ }
+ {
+ CPPCompiler::Desc desc(CPPCompiler::Type::GCC);
+ if (SLANG_SUCCEEDED(calcGccFamilyVersion("g++", UnownedStringSlice::fromLiteral("gcc version"), desc)))
+ {
+ RefPtr<CPPCompiler> compiler(new GenericCPPCompiler(desc, "g++", &UnixCPPCompilerUtil::calcArgs));
+ set->addCompiler(compiler);
+ }
+ }
+#endif
+
+ // 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());
+}
+
+void CPPCompilerSet::addCompiler(CPPCompiler* compiler)
+{
+ const Index index = _findIndex(compiler->getDesc());
+ if (index >= 0)
+ {
+ m_compilers[index] = compiler;
+ }
+ else
+ {
+ m_compilers.add(compiler);
+ }
+}
+
+}