summaryrefslogtreecommitdiff
path: root/source/core/slang-visual-studio-compiler-util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/slang-visual-studio-compiler-util.cpp')
-rw-r--r--source/core/slang-visual-studio-compiler-util.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/source/core/slang-visual-studio-compiler-util.cpp b/source/core/slang-visual-studio-compiler-util.cpp
new file mode 100644
index 000000000..20d655e78
--- /dev/null
+++ b/source/core/slang-visual-studio-compiler-util.cpp
@@ -0,0 +1,300 @@
+// slang-visual-studio-compiler-util.cpp
+#include "slang-visual-studio-compiler-util.h"
+
+#include "slang-common.h"
+#include "../../slang-com-helper.h"
+#include "slang-string-util.h"
+
+#include "slang-io.h"
+
+namespace Slang
+{
+
+/* static */void VisualStudioCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine)
+{
+ // https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=vs-2019
+
+ cmdLine.addArg("/nologo");
+ // Generate complete debugging information
+ cmdLine.addArg("/Zi");
+ // Display full path of source files in diagnostics
+ cmdLine.addArg("/FC");
+
+ if (options.flags & CompileOptions::Flag::EnableExceptionHandling)
+ {
+ if (options.sourceType == SourceType::CPP)
+ {
+ // https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=vs-2019
+ // Assumes c functions cannot throw
+ cmdLine.addArg("/EHsc");
+ }
+ }
+
+ switch (options.optimizationLevel)
+ {
+ case OptimizationLevel::Debug:
+ {
+ // No optimization
+ cmdLine.addArg("/Od");
+
+ cmdLine.addArg("/MDd");
+ break;
+ }
+ case OptimizationLevel::Normal:
+ {
+ cmdLine.addArg("/O2");
+ // Multithreaded DLL
+ cmdLine.addArg("/MD");
+ break;
+ }
+ default: break;
+ }
+
+ // /Fd - followed by name of the pdb file
+ if (options.debugInfoType != DebugInfoType::None)
+ {
+ cmdLine.addPrefixPathArg("/Fd", options.modulePath, ".pdb");
+ }
+
+ switch (options.targetType)
+ {
+ case TargetType::SharedLibrary:
+ {
+ // Create dynamic link library
+ if (options.optimizationLevel == OptimizationLevel::Debug)
+ {
+ cmdLine.addArg("/LDd");
+ }
+ else
+ {
+ cmdLine.addArg("/LD");
+ }
+
+ cmdLine.addPrefixPathArg("/Fe", options.modulePath, ".dll");
+ break;
+ }
+ case TargetType::Executable:
+ {
+ cmdLine.addPrefixPathArg("/Fe", options.modulePath, ".exe");
+ break;
+ }
+ default: break;
+ }
+
+ // Object file specify it's location - needed if we are out
+ cmdLine.addPrefixPathArg("/Fo", options.modulePath, ".obj");
+
+ // Add defines
+ for (const auto& define : options.defines)
+ {
+ StringBuilder builder;
+ builder << define.nameWithSig;
+ if (define.value.getLength())
+ {
+ builder << "=" << define.value;
+ }
+
+ cmdLine.addArg(builder);
+ }
+
+ // Add includes
+ for (const auto& include : options.includePaths)
+ {
+ cmdLine.addArg("/I");
+ cmdLine.addArg(include);
+ }
+
+ // https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=vs-2019
+ // /Eha - Specifies the model of exception handling. (a, s, c, r are options)
+
+ // Files to compile
+ for (const auto& sourceFile : options.sourceFiles)
+ {
+ cmdLine.addArg(sourceFile);
+ }
+
+ // Link options (parameters past /link go to linker)
+ cmdLine.addArg("/link");
+
+ for (const auto& libPath : options.libraryPaths)
+ {
+ // Note that any escaping of the path is handled in the ProcessUtil::
+ cmdLine.addPrefixPathArg("/LIBPATH:", libPath);
+ }
+}
+
+static SlangResult _parseErrorType(const UnownedStringSlice& in, CPPCompiler::OutputMessage::Type& outType)
+{
+ typedef CPPCompiler::OutputMessage::Type Type;
+
+ if (in == "error" || in == "fatal error")
+ {
+ outType = Type::Error;
+ }
+ else if (in == "warning")
+ {
+ outType = Type::Warning;
+ }
+ else if (in == "info")
+ {
+ outType = Type::Info;
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+}
+
+static SlangResult _parseVisualStudioLine(const UnownedStringSlice& line, CPPCompiler::OutputMessage& outMsg)
+{
+ typedef CPPCompiler::OutputMessage OutputMessage;
+
+ UnownedStringSlice linkPrefix = UnownedStringSlice::fromLiteral("LINK :");
+ if (line.startsWith(linkPrefix))
+ {
+ outMsg.stage = OutputMessage::Stage::Link;
+ outMsg.type = OutputMessage::Type::Info;
+
+ outMsg.text = UnownedStringSlice(line.begin() + linkPrefix.size(), line.end());
+
+ return SLANG_OK;
+ }
+
+ outMsg.stage = OutputMessage::Stage::Compile;
+
+ const char*const start = line.begin();
+ const char*const end = line.end();
+
+ UnownedStringSlice postPath;
+ // Handle the path and line no
+ {
+ const char* cur = start;
+
+ // We have to assume it is a path up to the first : that isn't part of a drive specification
+
+ if ((end - cur > 2) && Path::isDriveSpecification(UnownedStringSlice(start, start + 2)))
+ {
+ // Skip drive spec
+ cur += 2;
+ }
+
+ // Find the first colon after this
+ Index colonIndex = UnownedStringSlice(cur, end).indexOf(':');
+ if (colonIndex < 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Looks like we have a line number
+ if (cur[colonIndex - 1] == ')')
+ {
+ const char* lineNoEnd = cur + colonIndex - 1;
+ const char* lineNoStart = lineNoEnd;
+ while (lineNoStart > start && *lineNoStart != '(')
+ {
+ lineNoStart--;
+ }
+ // Check this appears plausible
+ if (*lineNoStart != '(' || *lineNoEnd != ')')
+ {
+ return SLANG_FAIL;
+ }
+ Int numDigits = 0;
+ Int lineNo = 0;
+ for (const char* digitCur = lineNoStart + 1; digitCur < lineNoEnd; ++digitCur)
+ {
+ char c = *digitCur;
+ if (c >= '0' && c <= '9')
+ {
+ lineNo = lineNo * 10 + (c - '0');
+ numDigits++;
+ }
+ else
+ {
+ return SLANG_FAIL;
+ }
+ }
+ if (numDigits == 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ outMsg.filePath = UnownedStringSlice(start, lineNoStart);
+ outMsg.fileLine = lineNo;
+ }
+ else
+ {
+ outMsg.filePath = UnownedStringSlice(start, cur + colonIndex);
+ outMsg.fileLine = 0;
+ }
+
+ // Save the remaining text in 'postPath'
+ postPath = UnownedStringSlice(cur + colonIndex + 1, end);
+ }
+
+ // Split up the error section
+ UnownedStringSlice postError;
+ {
+ // tests/cpp-compiler/c-compile-link-error.exe : fatal error LNK1120: 1 unresolved externals
+
+ const Index errorColonIndex = postPath.indexOf(':');
+ if (errorColonIndex < 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ const UnownedStringSlice errorSection = UnownedStringSlice(postPath.begin(), postPath.begin() + errorColonIndex);
+ Index errorCodeIndex = errorSection.lastIndexOf(' ');
+ if (errorCodeIndex < 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Extract the code
+ outMsg.code = UnownedStringSlice(errorSection.begin() + errorCodeIndex + 1, errorSection.end());
+ if (outMsg.code.startsWith(UnownedStringSlice::fromLiteral("LNK")))
+ {
+ outMsg.stage = OutputMessage::Stage::Link;
+ }
+
+ // Extract the bit before the code
+ SLANG_RETURN_ON_FAIL(_parseErrorType(UnownedStringSlice(errorSection.begin(), errorSection.begin() + errorCodeIndex).trim(), outMsg.type));
+
+ // Link codes start with LNK prefix
+ postError = UnownedStringSlice(postPath.begin() + errorColonIndex + 1, end);
+ }
+
+ outMsg.text = postError;
+
+ return SLANG_OK;
+}
+
+/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, CPPCompiler::Output& outOutput)
+{
+ outOutput.reset();
+
+ for (auto line : LineParser(exeRes.standardOutput.getUnownedSlice()))
+ {
+#if 0
+ fwrite(line.begin(), 1, line.size(), stdout);
+ fprintf(stdout, "\n");
+#endif
+
+ OutputMessage msg;
+ if (SLANG_SUCCEEDED(_parseVisualStudioLine(line, msg)))
+ {
+ outOutput.messages.add(msg);
+ }
+ }
+
+ // if it has a compilation error.. set on output
+ if (outOutput.has(OutputMessage::Type::Error))
+ {
+ outOutput.result = SLANG_FAIL;
+ }
+
+ return SLANG_OK;
+}
+
+}